Skip to content

Commit

Permalink
Generate structs with the new asn-attributes #11
Browse files Browse the repository at this point in the history
  • Loading branch information
kellerkindt committed May 4, 2020
1 parent 7de0269 commit 5d3507c
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 21 deletions.
100 changes: 81 additions & 19 deletions asn1rs-model/src/gen/rust/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ use self::uper::UperSerializer;
use crate::gen::Generator;
use crate::model::rust::DataEnum;
use crate::model::rust::PlainEnum;
use crate::model::Definition;
use crate::model::Model;
use crate::model::Range;
use crate::model::Rust;
use crate::model::RustType;
use crate::model::{Asn, Definition, Tag, Type as AsnType, Type};
use codegen::Block;
use codegen::Enum;
use codegen::Function;
Expand Down Expand Up @@ -148,6 +148,7 @@ impl RustCodeGenerator {
let mut scope = Scope::new();
generators.iter().for_each(|g| g.add_imports(&mut scope));

scope.import("asn1rs::prelude", "*");
for import in &model.imports {
let from = format!("super::{}", &Self::rust_module_name(&import.from));
for what in &import.what {
Expand All @@ -170,7 +171,7 @@ impl RustCodeGenerator {
fn add_definition(&self, scope: &mut Scope, Definition(name, rust): &Definition<Rust>) {
match rust {
Rust::Struct(fields) => Self::add_struct(
self.new_struct(scope, name),
self.new_struct(scope, name, false),
name,
fields,
self.direct_field_access,
Expand All @@ -182,7 +183,7 @@ impl RustCodeGenerator {
Self::add_data_enum(self.new_enum(scope, name, false), name, enumeration)
}
Rust::TupleStruct(inner) => Self::add_tuple_struct(
self.new_struct(scope, name),
self.new_struct(scope, name, true),
name,
inner,
self.direct_field_access,
Expand All @@ -197,13 +198,15 @@ impl RustCodeGenerator {
pub_access: bool,
) {
for (field_name, field_type) in fields.iter() {
let name = Self::rust_field_name(field_name, true);
let name = if pub_access {
format!("pub {}", name)
} else {
name
};
str_ct.field(&name, field_type.to_string());
str_ct.field(
&format!(
"{} {}{}",
Self::asn_attribute(&field_type.clone().into_asn().untagged()),
if pub_access { "pub " } else { "" },
Self::rust_field_name(field_name, true),
),
field_type.to_string(),
);
}
}

Expand All @@ -216,21 +219,63 @@ impl RustCodeGenerator {
fn add_data_enum(en_m: &mut Enum, _name: &str, enumeration: &DataEnum) {
for (variant, rust_type) in enumeration.variants() {
en_m.new_variant(&format!(
"{}({})",
"{} {}({})",
// TODO assuming untagged
Self::asn_attribute(&rust_type.clone().into_asn().untagged()),
Self::rust_variant_name(variant),
rust_type.to_string(),
));
}
}

fn add_tuple_struct(str_ct: &mut Struct, _name: &str, inner: &RustType, pub_access: bool) {
let field_type = inner.to_string();
let field_type = if pub_access {
format!("pub {}", field_type)
} else {
field_type
};
str_ct.tuple_field(&field_type);
// TODO assuming untagged
str_ct.tuple_field(format!(
"{} {}{}",
Self::asn_attribute(&inner.clone().into_asn().untagged()),
if pub_access { "pub " } else { "" },
inner.to_string(),
));
}

fn asn_attribute(asn: &Asn) -> String {
format!(
"#[asn({}){}{}]",
Self::asn_attribute_type(&asn.r#type),
if asn.tag.is_some() { ", " } else { "" },
if let Some(tag) = &asn.tag {
Self::asn_attribute_tag(tag)
} else {
String::default()
}
)
}

fn asn_attribute_type(r#type: &AsnType) -> String {
match r#type {
Type::Boolean => String::from("boolean"),
Type::Integer(Some(Range(min, max))) => format!("integer({}..{})", min, max),
Type::Integer(None) => format!("integer(min..max)"),
Type::UTF8String => String::from("utf8string"),
Type::OctetString => String::from("octet_string"),
Type::Optional(inner) => format!("option({})", Self::asn_attribute_type(&*inner)),
Type::SequenceOf(inner) => {
format!("sequence_of({})", Self::asn_attribute_type(&*inner))
}
Type::Sequence(_) => String::from("sequence"),
Type::Enumerated(_) => String::from("enumerated"),
Type::Choice(_) => String::from("choice"),
Type::TypeReference(inner) => format!("complex({})", inner),
}
}

fn asn_attribute_tag(tag: &Tag) -> String {
match tag {
Tag::Universal(t) => format!("tag(UNIVERSAL({}))", t),
Tag::Application(t) => format!("tag(APPLICATION({}))", t),
Tag::Private(t) => format!("tag(PRIVATE({}))", t),
Tag::ContextSpecific(t) => format!("tag({})", t),
}
}

fn impl_definition(
Expand Down Expand Up @@ -605,7 +650,20 @@ impl RustCodeGenerator {
out
}

fn new_struct<'a>(&self, scope: &'a mut Scope, name: &str) -> &'a mut Struct {
fn new_struct<'a>(
&self,
scope: &'a mut Scope,
name: &str,
asn_transparent: bool,
) -> &'a mut Struct {
scope.raw(&format!(
"#[asn({})]",
if asn_transparent {
"transparent"
} else {
"sequence"
}
));
let str_ct = scope
.new_struct(name)
.vis("pub")
Expand All @@ -621,6 +679,10 @@ impl RustCodeGenerator {
}

fn new_enum<'a>(&self, scope: &'a mut Scope, name: &str, c_enum: bool) -> &'a mut Enum {
scope.raw(&format!(
"#[asn({})]",
if c_enum { "enumerated" } else { "choice" }
));
let en_m = scope
.new_enum(name)
.vis("pub")
Expand Down
12 changes: 10 additions & 2 deletions asn1rs-model/src/gen/rust/walker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,16 @@ impl AsnDefExpander {
RustType::U64(_) => {}
RustType::String => {}
RustType::VecU8 => {}
RustType::Vec(_) => {}
RustType::Option(_) => {}
RustType::Vec(inner) => self.write_field_constraints(
scope,
name,
&[(field.to_string(), *inner.clone())],
),
RustType::Option(inner) => self.write_field_constraints(
scope,
name,
&[(field.to_string(), *inner.clone())],
),
RustType::Complex(_) => {}
}
}
Expand Down
36 changes: 36 additions & 0 deletions asn1rs-model/src/model/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,42 @@ impl RustType {
}
}

pub fn into_asn(self) -> AsnType {
match self {
RustType::Bool => AsnType::Boolean,
RustType::I8(Range(min, max)) => {
AsnType::Integer(Some(Range(i64::from(min), i64::from(max))))
}
RustType::U8(Range(min, max)) => {
AsnType::Integer(Some(Range(i64::from(min), i64::from(max))))
}
RustType::I16(Range(min, max)) => {
AsnType::Integer(Some(Range(i64::from(min), i64::from(max))))
}
RustType::U16(Range(min, max)) => {
AsnType::Integer(Some(Range(i64::from(min), i64::from(max))))
}
RustType::I32(Range(min, max)) => {
AsnType::Integer(Some(Range(i64::from(min), i64::from(max))))
}
RustType::U32(Range(min, max)) => {
AsnType::Integer(Some(Range(i64::from(min), i64::from(max))))
}
RustType::I64(Range(min, max)) => {
AsnType::Integer(Some(Range(i64::from(min), i64::from(max))))
}
RustType::U64(Some(Range(min, max))) => {
AsnType::Integer(Some(Range(min as i64, max as i64)))
}
RustType::U64(None) => AsnType::Integer(None),
RustType::String => AsnType::UTF8String,
RustType::VecU8 => AsnType::OctetString,
RustType::Vec(inner) => AsnType::SequenceOf(Box::new(inner.into_asn())),
RustType::Option(value) => AsnType::Optional(Box::new(value.into_asn())),
RustType::Complex(name) => AsnType::TypeReference(name),
}
}

pub fn similar(&self, other: &Self) -> bool {
match self {
RustType::Bool => return *other == RustType::Bool,
Expand Down

0 comments on commit 5d3507c

Please sign in to comment.