Skip to content

Commit

Permalink
Implement read/write_enumerated #11
Browse files Browse the repository at this point in the history
  • Loading branch information
kellerkindt committed Apr 27, 2020
1 parent a3f4781 commit 12bdfc4
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 28 deletions.
89 changes: 75 additions & 14 deletions asn1rs-model/src/gen/rust/walker.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::gen::rust::GeneratorSupplement;
use crate::gen::RustCodeGenerator;
use crate::model::rust::PlainEnum;
use crate::model::{Definition, Model, Range, Rust, RustType};
use codegen::{Block, Impl, Scope};
use std::fmt::Display;
Expand Down Expand Up @@ -78,7 +79,9 @@ impl AsnDefWalker {
self.write_field_constraints(scope, &name, &fields);
self.write_sequence_constraint(scope, &name, &fields);
}
Rust::Enum(_) => {}
Rust::Enum(plain) => {
self.write_enumerated_constraint(scope, &name, plain);
}
Rust::DataEnum(_) => {}
Rust::TupleStruct(_) => {}
}
Expand Down Expand Up @@ -171,9 +174,7 @@ impl AsnDefWalker {
self.write_sequence_constraint_read_fn(&mut imp, name, fields);
self.write_sequence_constraint_write_fn(&mut imp, name, fields);

scope.raw(&Self::write_sequence_constraint_insert_consts(
name, fields, imp,
));
Self::write_sequence_constraint_insert_consts(scope, name, fields, imp);
}

fn impl_readable(&self, scope: &mut Scope, name: &str) {
Expand Down Expand Up @@ -201,6 +202,50 @@ impl AsnDefWalker {
.line(format!("AsnDef{}::write_value(writer, self)", name));
}

fn write_enumerated_constraint(&self, scope: &mut Scope, name: &str, enumerated: &PlainEnum) {
let mut imp = Impl::new(name);
imp.impl_trait(format!("{}::enumerated::Constraint", CRATE_SYN_PREFIX));

imp.new_fn("to_choice_index")
.arg_ref_self()
.ret("usize")
.push_block({
let mut match_block = Block::new("match self");
for (index, variant) in enumerated.variants().enumerate() {
match_block.line(format!("Self::{} => {},", variant, index));
}
match_block
});

imp.new_fn("from_choice_index")
.arg("index", "usize")
.ret("Option<Self>")
.push_block({
let mut match_block = Block::new("match index");
for (index, variant) in enumerated.variants().enumerate() {
match_block.line(format!("{} => Some(Self::{}),", index, variant));
}
match_block.line("_ => None,");
match_block
});

Self::insert_consts(
scope,
imp,
&[
format!("const NAME: &str = \"{}\";", name),
format!("const VARIANT_COUNT: usize = {};", enumerated.len()),
format!(
"const STD_VARIANT_COUNT: usize = {};",
enumerated
.last_standard_index()
.unwrap_or_else(|| enumerated.len())
),
format!("const EXTENSIBLE: bool = {};", enumerated.is_extensible()),
],
);
}

fn write_integer_constraint_type<T: Display>(
scope: &mut Scope,
name: &str,
Expand All @@ -221,21 +266,37 @@ impl AsnDefWalker {
}

fn write_sequence_constraint_insert_consts(
scope: &mut Scope,
name: &str,
fields: &[(String, RustType)],
imp: Impl,
) -> String {
) {
Self::insert_consts(
scope,
imp,
&[
format!(
"const OPTIONAL_FIELDS: usize = {};",
fields.iter().filter(|f| f.1.is_option()).count()
),
format!("const NAME: &'static str = \"{}\";", name),
],
);
}

fn insert_consts<S: ToString, I: IntoIterator<Item = S>>(
scope: &mut Scope,
imp: Impl,
consts: I,
) {
let string = Scope::new().push_impl(imp).to_string();
let mut lines = string.lines().map(ToString::to_string).collect::<Vec<_>>();
lines.insert(
1,
format!(
" const OPTIONAL_FIELDS: usize = {};",
fields.iter().filter(|f| f.1.is_option()).count()
),
);
lines.insert(1, format!("const NAME: &'static str = \"{}\";", name));
lines.join("\n")

for cnst in consts {
lines.insert(1, cnst.to_string());
}

scope.raw(&lines.join("\n"));
}

fn write_sequence_constraint_read_fn(
Expand Down
6 changes: 6 additions & 0 deletions src/io/uper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub enum Error {
UnsupportedOperation(String),
InsufficientSpaceInDestinationBuffer,
InsufficientDataInSourceBuffer,
InvalidChoiceIndex(usize, usize),
ValueNotInRange(i64, i64, i64),
EndOfStream,
}
Expand All @@ -34,6 +35,11 @@ impl std::fmt::Display for Error {
f,
"There is insufficient data in the source buffer for this operation"
),
Error::InvalidChoiceIndex(index, variant_count) => write!(
f,
"Unexpected choice-index {} with variant count {}",
index, variant_count
),
Error::ValueNotInRange(value, min, max) => write!(
f,
"The value {} is not within the inclusive range of {} and {}",
Expand Down
7 changes: 4 additions & 3 deletions src/syn/enumerated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ impl<C: Constraint> Default for Enumerated<C> {

pub trait Constraint: Sized {
const NAME: &'static str;
const STD_VARIANTS: usize;
const VARIANT_COUNT: usize;
const STD_VARIANT_COUNT: usize;
const EXTENSIBLE: bool = false;

fn choice_index(&self) -> usize;
fn to_choice_index(&self) -> usize;

fn from_choice_index(index: usize) -> Self;
fn from_choice_index(index: usize) -> Option<Self>;
}

impl<C: Constraint> WritableType for Enumerated<C> {
Expand Down
7 changes: 4 additions & 3 deletions src/syn/io/println.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ impl Writer for PrintlnWriter {
}
w.with_increased_indentation(|w| {
w.indented_println(&format!(
"choice_index {}/{}",
enumerated.choice_index(),
C::STD_VARIANTS
"choice_index {}/{}/{}",
enumerated.to_choice_index(),
C::STD_VARIANT_COUNT,
C::VARIANT_COUNT
));
Ok(())
})
Expand Down
18 changes: 10 additions & 8 deletions src/syn/io/uper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ impl Writer for UperWriter {
) -> Result<(), Self::Error> {
if C::EXTENSIBLE {
self.buffer.write_choice_index_extensible(
enumerated.choice_index() as u64,
C::STD_VARIANTS as u64,
enumerated.to_choice_index() as u64,
C::STD_VARIANT_COUNT as u64,
)
} else {
self.buffer.write_int(
enumerated.choice_index() as i64,
(0, C::STD_VARIANTS as i64),
enumerated.to_choice_index() as i64,
(0, C::STD_VARIANT_COUNT as i64),
)
}
}
Expand Down Expand Up @@ -142,14 +142,16 @@ impl Reader for UperReader {
fn read_enumerated<C: enumerated::Constraint>(&mut self) -> Result<C, Self::Error> {
if C::EXTENSIBLE {
self.buffer
.read_choice_index_extensible(C::STD_VARIANTS as u64)
.read_choice_index_extensible(C::STD_VARIANT_COUNT as u64)
.map(|v| v as usize)
.map(C::from_choice_index)
} else {
self.read_int((0, C::STD_VARIANTS as i64))
self.read_int((0, C::STD_VARIANT_COUNT as i64))
.map(|v| v as usize)
.map(C::from_choice_index)
}
.and_then(|index| {
C::from_choice_index(index)
.ok_or_else(|| UperError::InvalidChoiceIndex(index, C::VARIANT_COUNT))
})
}

fn read_opt<T: ReadableType>(
Expand Down

0 comments on commit 12bdfc4

Please sign in to comment.