asn1rs_model/model/rust/
mod.rs

1use crate::model::lor::{ResolveState, Resolved};
2use crate::model::rust::Field as RustField;
3use crate::model::{Asn, ChoiceVariant, Integer, LiteralValue, Target};
4use crate::model::{Charset, Range};
5use crate::model::{ComponentTypeList, ValueReference};
6use crate::model::{Definition, Type};
7use crate::model::{Import, Tag, TagProperty};
8use crate::model::{Model, Size};
9use crate::model::{TagResolver, Type as AsnType};
10use std::borrow::Cow;
11
12const I8_MAX: i64 = i8::MAX as i64;
13const I16_MAX: i64 = i16::MAX as i64;
14const I32_MAX: i64 = i32::MAX as i64;
15//const I64_MAX: i64 = i64::MAX as i64;
16
17const U8_MAX: u64 = u8::MAX as u64;
18const U16_MAX: u64 = u16::MAX as u64;
19const U32_MAX: u64 = u32::MAX as u64;
20//const U64_MAX: u64 = u64::MAX as u64;
21
22pub type PlainVariant = String;
23pub type PlainEnum = Enumeration<PlainVariant>;
24pub type DataEnum = Enumeration<DataVariant>;
25
26/// Integers are ordered where Ixx < Uxx so
27/// that when comparing two instances `RustType`
28/// and a > b, then the integer type of a can
29/// use ::from(..) to cast from b
30#[allow(clippy::module_name_repetitions)]
31#[derive(Debug, Clone, PartialOrd, PartialEq)]
32pub enum RustType {
33    Bool,
34    I8(Range<i8>),
35    U8(Range<u8>),
36    I16(Range<i16>),
37    U16(Range<u16>),
38    I32(Range<i32>),
39    U32(Range<u32>),
40    I64(Range<i64>),
41    U64(Range<Option<u64>>),
42    String(Size, Charset),
43    VecU8(Size),
44    BitVec(Size),
45    Vec(Box<RustType>, Size, EncodingOrdering),
46    Null,
47
48    Option(Box<RustType>),
49    Default(Box<RustType>, LiteralValue),
50
51    /// Indicates a complex, custom type that is
52    /// not one of rusts known types. This can be
53    /// thought of as a "ReferenceType"; declaring usage,
54    /// but not being declared here
55    Complex(String, Option<Tag>),
56}
57
58impl RustType {
59    pub fn as_inner_type(&self) -> &RustType {
60        if let RustType::Vec(inner, ..) | RustType::Option(inner) | RustType::Default(inner, ..) =
61            self
62        {
63            inner.as_inner_type()
64        } else {
65            self
66        }
67    }
68
69    pub fn into_inner_type(self) -> RustType {
70        if let RustType::Vec(inner, ..) | RustType::Option(inner) | RustType::Default(inner, ..) =
71            self
72        {
73            inner.into_inner_type()
74        } else {
75            self
76        }
77    }
78
79    pub fn to_inner_type_string(&self) -> String {
80        self.as_inner_type().to_string()
81    }
82
83    pub fn no_option(self) -> Self {
84        match self {
85            RustType::Option(inner) => *inner,
86            RustType::Default(inner, ..) => inner.no_option(),
87            rust => rust,
88        }
89    }
90
91    pub fn as_no_option(&self) -> &Self {
92        if let RustType::Option(inner) = self {
93            inner.as_no_option()
94        } else {
95            self
96        }
97    }
98
99    pub fn is_vec(&self) -> bool {
100        matches!(self.as_no_option(), RustType::Vec(..))
101    }
102
103    /// Checks whether self is `RustType::Option(..)`
104    pub fn is_option(&self) -> bool {
105        matches!(self, RustType::Option(..))
106    }
107
108    /// Values which might not be serialized according to ASN
109    pub fn is_optional(&self) -> bool {
110        matches!(self, RustType::Option(..) | RustType::Default(..))
111    }
112
113    pub fn is_primitive(&self) -> bool {
114        matches!(
115            self,
116            RustType::Bool
117                | RustType::U8(_)
118                | RustType::I8(_)
119                | RustType::U16(_)
120                | RustType::I16(_)
121                | RustType::U32(_)
122                | RustType::I32(_)
123                | RustType::U64(_)
124                | RustType::I64(_),
125        ) || matches!(self, RustType::Default(inner, ..) if inner.is_primitive())
126    }
127
128    pub fn integer_range_str(&self) -> Option<Range<String>> {
129        #[allow(clippy::match_same_arms)] // to have the same order as the original enum
130        match self {
131            RustType::Bool => None,
132            RustType::U8(Range(min, max, extensible)) => {
133                Some(Range(min.to_string(), max.to_string(), *extensible))
134            }
135            RustType::I8(Range(min, max, extensible)) => {
136                Some(Range(min.to_string(), max.to_string(), *extensible))
137            }
138            RustType::U16(Range(min, max, extensible)) => {
139                Some(Range(min.to_string(), max.to_string(), *extensible))
140            }
141            RustType::I16(Range(min, max, extensible)) => {
142                Some(Range(min.to_string(), max.to_string(), *extensible))
143            }
144            RustType::U32(Range(min, max, extensible)) => {
145                Some(Range(min.to_string(), max.to_string(), *extensible))
146            }
147            RustType::I32(Range(min, max, extensible)) => {
148                Some(Range(min.to_string(), max.to_string(), *extensible))
149            }
150            RustType::U64(Range(min, max, extensible)) => Some(Range(
151                min.unwrap_or_default().to_string(),
152                max.unwrap_or_else(|| i64::MAX as u64).to_string(),
153                *extensible,
154            )),
155            RustType::I64(Range(min, max, extensible)) => {
156                Some(Range(min.to_string(), max.to_string(), *extensible))
157            }
158            RustType::String(..) => None,
159            RustType::VecU8(_) => None,
160            RustType::BitVec(_) => None,
161            RustType::Vec(inner, _size, _ordering) => inner.integer_range_str(),
162            RustType::Null => None,
163            RustType::Option(inner) => inner.integer_range_str(),
164            RustType::Default(inner, ..) => inner.integer_range_str(),
165            RustType::Complex(_, _) => None,
166        }
167    }
168
169    pub fn into_asn(self) -> AsnType {
170        match self {
171            RustType::Bool => AsnType::Boolean,
172            RustType::I8(Range(min, max, extensible)) => AsnType::integer_with_range(Range(
173                Some(i64::from(min)),
174                Some(i64::from(max)),
175                extensible,
176            )),
177            RustType::U8(Range(min, max, extensible)) => AsnType::integer_with_range(Range(
178                Some(i64::from(min)),
179                Some(i64::from(max)),
180                extensible,
181            )),
182            RustType::I16(Range(min, max, extensible)) => AsnType::integer_with_range(Range(
183                Some(i64::from(min)),
184                Some(i64::from(max)),
185                extensible,
186            )),
187            RustType::U16(Range(min, max, extensible)) => AsnType::integer_with_range(Range(
188                Some(i64::from(min)),
189                Some(i64::from(max)),
190                extensible,
191            )),
192            RustType::I32(Range(min, max, extensible)) => AsnType::integer_with_range(Range(
193                Some(i64::from(min)),
194                Some(i64::from(max)),
195                extensible,
196            )),
197            RustType::U32(Range(min, max, extensible)) => AsnType::integer_with_range(Range(
198                Some(i64::from(min)),
199                Some(i64::from(max)),
200                extensible,
201            )),
202            RustType::I64(Range(min, max, extensible)) => {
203                AsnType::integer_with_range(Range(Some(min), Some(max), extensible))
204            }
205            RustType::U64(range) => AsnType::integer_with_range(Range(
206                range.min().map(|v| v as i64),
207                range.max().map(|v| v as i64),
208                range.extensible(),
209            )),
210            RustType::String(size, charset) => AsnType::String(size, charset),
211            RustType::VecU8(size) => AsnType::OctetString(size),
212            RustType::BitVec(size) => AsnType::bit_vec_with_size(size),
213            RustType::Vec(inner, size, EncodingOrdering::Keep) => {
214                AsnType::SequenceOf(Box::new(inner.into_asn()), size)
215            }
216            RustType::Vec(inner, size, EncodingOrdering::Sort) => {
217                AsnType::SetOf(Box::new(inner.into_asn()), size)
218            }
219            RustType::Null => AsnType::Null,
220            RustType::Option(value) => AsnType::Optional(Box::new(value.into_asn())),
221            RustType::Default(value, default) => {
222                AsnType::Default(Box::new(value.into_asn()), default)
223            }
224            RustType::Complex(name, tag) => AsnType::TypeReference(name, tag),
225        }
226    }
227
228    pub fn similar(&self, other: &Self) -> bool {
229        match self {
230            RustType::Bool => RustType::Bool == *other,
231            RustType::U8(_) => matches!(other, RustType::U8(_)),
232            RustType::I8(_) => matches!(other, RustType::I8(_)),
233            RustType::U16(_) => matches!(other, RustType::U16(_)),
234            RustType::I16(_) => matches!(other, RustType::I16(_)),
235            RustType::U32(_) => matches!(other, RustType::U32(_)),
236            RustType::I32(_) => matches!(other, RustType::I32(_)),
237            RustType::U64(_) => matches!(other, RustType::U64(_)),
238            RustType::I64(_) => matches!(other, RustType::I64(_)),
239            RustType::String(..) => matches!(other, RustType::String(..)),
240            RustType::VecU8(_) => matches!(other, RustType::VecU8(_)),
241            RustType::BitVec(_) => matches!(other, RustType::BitVec(_)),
242            RustType::Vec(inner_a, _size, _ordering) => {
243                if let RustType::Vec(inner_b, _other_size, _ordering) = other {
244                    inner_a.similar(inner_b)
245                } else {
246                    false
247                }
248            }
249            RustType::Null => RustType::Null == *other,
250            RustType::Option(inner) => {
251                matches!(other, RustType::Option(o) if o.similar(inner))
252                    || matches!(other, RustType::Default(o, ..) if o.similar(inner))
253            }
254            RustType::Default(inner, ..) => {
255                other.similar(inner)
256                    || matches!(other, RustType::Default(o, ..) if o.similar(inner))
257                    || matches!(other, RustType::Option(o, ..) if o.similar(inner))
258            }
259            RustType::Complex(inner_a, _tag) => {
260                if let RustType::Complex(inner_b, _tag) = other {
261                    inner_a.eq(inner_b)
262                } else {
263                    false
264                }
265            }
266        }
267    }
268
269    /// ITU-T X.680 | ISO/IEC 8824-1, 8.6
270    pub fn tag(&self) -> Option<Tag> {
271        Some(match self {
272            RustType::Bool => Tag::DEFAULT_BOOLEAN,
273            RustType::I8(_)
274            | RustType::U8(_)
275            | RustType::I16(_)
276            | RustType::U16(_)
277            | RustType::I32(_)
278            | RustType::U32(_)
279            | RustType::I64(_)
280            | RustType::U64(_) => Tag::DEFAULT_INTEGER,
281            RustType::BitVec(_) => Tag::DEFAULT_BIT_STRING,
282            RustType::VecU8(_) => Tag::DEFAULT_OCTET_STRING,
283            RustType::String(_, charset) => charset.default_tag(),
284            RustType::Vec(_, _, EncodingOrdering::Keep) => Tag::DEFAULT_SEQUENCE_OF,
285            RustType::Vec(_, _, EncodingOrdering::Sort) => Tag::DEFAULT_SET_OF,
286            RustType::Null => Tag::DEFAULT_NULL,
287            RustType::Option(inner) => return inner.tag(),
288            RustType::Default(inner, ..) => return inner.tag(),
289            // TODO this is wrong. This should resolve the tag from the referenced type instead, but atm the infrastructure is missing to do such a thing, see github#13
290            RustType::Complex(_, tag) => return *tag,
291        })
292    }
293}
294
295/// Describes whether the original declaration cares about (re-)ordering the elements or whether
296/// their encoding is to be applied in the order of definition (struct fields) or appearance (vec)
297#[derive(Debug, Clone, Copy, PartialOrd, PartialEq, Eq)]
298pub enum EncodingOrdering {
299    Sort,
300    Keep,
301}
302
303#[derive(Debug, Clone, PartialOrd, PartialEq)]
304pub enum Rust {
305    Struct {
306        ordering: EncodingOrdering,
307        fields: Vec<Field>,
308        tag: Option<Tag>,
309        extension_after: Option<usize>,
310    },
311    Enum(PlainEnum),
312    DataEnum(DataEnum),
313
314    /// Used to represent a single, unnamed inner type
315    // TODO inline the referred type!?
316    TupleStruct {
317        r#type: RustType,
318        tag: Option<Tag>,
319        constants: Vec<(String, String)>,
320    },
321}
322
323impl Rust {
324    #[cfg(test)]
325    pub fn struct_from_fields(fields: Vec<Field>) -> Self {
326        Self::Struct {
327            ordering: EncodingOrdering::Keep,
328            fields,
329            tag: None,
330            extension_after: None,
331        }
332    }
333
334    pub fn tuple_struct_from_type(r#type: RustType) -> Self {
335        Self::TupleStruct {
336            r#type,
337            tag: None,
338            constants: Vec::default(),
339        }
340    }
341}
342
343impl Target for Rust {
344    type DefinitionType = Rust;
345    type ValueReferenceType = RustType;
346}
347
348impl TagProperty for Rust {
349    fn tag(&self) -> Option<Tag> {
350        match self {
351            Rust::Struct { tag, .. } => *tag,
352            Rust::Enum(e) => e.tag(),
353            Rust::DataEnum(c) => c.tag(),
354            Rust::TupleStruct { tag, .. } => *tag,
355        }
356    }
357
358    fn set_tag(&mut self, new_tag: Tag) {
359        match self {
360            Rust::Struct { tag, .. } => *tag = Some(new_tag),
361            Rust::Enum(e) => e.set_tag(new_tag),
362            Rust::DataEnum(c) => c.set_tag(new_tag),
363            Rust::TupleStruct { tag, .. } => *tag = Some(new_tag),
364        }
365    }
366
367    fn reset_tag(&mut self) {
368        match self {
369            Rust::Struct { tag, .. } => *tag = None,
370            Rust::Enum(e) => e.reset_tag(),
371            Rust::DataEnum(c) => c.reset_tag(),
372            Rust::TupleStruct { tag, .. } => *tag = None,
373        }
374    }
375}
376
377impl RustType {
378    /// Returns the representation of this type in rust code in a const context.
379    /// Primitive (heapless) types remain unchanged, while types such as `String`, `Vec<u8>`, ...
380    /// are replaced by their `'static` representatives (`&'static str`, `&'static [u8]`, ...)
381    pub fn to_const_lit_string(&self) -> Cow<'static, str> {
382        Cow::Borrowed(match self {
383            RustType::Bool => "bool",
384            RustType::U8(_) => "u8",
385            RustType::I8(_) => "i8",
386            RustType::U16(_) => "u16",
387            RustType::I16(_) => "i16",
388            RustType::U32(_) => "u32",
389            RustType::I32(_) => "i32",
390            RustType::U64(_) => "u64",
391            RustType::I64(_) => "i64",
392            RustType::String(..) => "&'static str",
393            RustType::VecU8(_) => "&'static [u8]",
394            RustType::BitVec(_) => "u64",
395            RustType::Vec(inner, _size, _ordering) => {
396                return Cow::Owned(format!("&'static [{}]", inner.to_const_lit_string()))
397            }
398            RustType::Null => "Null",
399            RustType::Option(inner) => {
400                return Cow::Owned(format!("Option<{}>", inner.to_const_lit_string()))
401            }
402            RustType::Default(inner, ..) => return inner.to_const_lit_string(),
403            RustType::Complex(name, _) => return Cow::Owned(name.clone()),
404        })
405    }
406}
407
408impl ToString for RustType {
409    fn to_string(&self) -> String {
410        match self {
411            RustType::Bool => "bool",
412            RustType::U8(_) => "u8",
413            RustType::I8(_) => "i8",
414            RustType::U16(_) => "u16",
415            RustType::I16(_) => "i16",
416            RustType::U32(_) => "u32",
417            RustType::I32(_) => "i32",
418            RustType::U64(_) => "u64",
419            RustType::I64(_) => "i64",
420            RustType::String(..) => "String",
421            RustType::VecU8(_) => "Vec<u8>",
422            RustType::BitVec(_) => "BitVec",
423            RustType::Vec(inner, _size, _ordering) => return format!("Vec<{}>", inner.to_string()),
424            RustType::Null => "Null",
425            RustType::Option(inner) => return format!("Option<{}>", inner.to_string()),
426            RustType::Default(inner, ..) => return inner.to_string(),
427            RustType::Complex(name, _) => return name.clone(),
428        }
429        .into()
430    }
431}
432
433#[derive(Debug, Clone, PartialOrd, PartialEq)]
434pub struct Field {
435    pub(crate) name_type: (String, RustType),
436    pub(crate) tag: Option<Tag>,
437    pub(crate) constants: Vec<(String, String)>,
438}
439
440impl Field {
441    pub fn from_name_type<T: ToString>(name: T, r#type: RustType) -> Self {
442        Self {
443            name_type: (name.to_string(), r#type),
444            tag: None,
445            constants: Vec::default(),
446        }
447    }
448
449    pub fn fallback_representation(&self) -> &(String, RustType) {
450        &self.name_type
451    }
452
453    pub fn name(&self) -> &str {
454        &self.name_type.0
455    }
456
457    pub fn r#type(&self) -> &RustType {
458        &self.name_type.1
459    }
460
461    pub fn constants(&self) -> &[(String, String)] {
462        &self.constants[..]
463    }
464
465    pub fn with_constants(mut self, constants: Vec<(String, String)>) -> Self {
466        self.constants = constants;
467        self
468    }
469}
470
471impl TagProperty for Field {
472    fn tag(&self) -> Option<Tag> {
473        self.tag
474    }
475
476    fn set_tag(&mut self, tag: Tag) {
477        self.tag = Some(tag);
478    }
479
480    fn reset_tag(&mut self) {
481        self.tag = None;
482    }
483}
484
485#[derive(Debug, Clone, PartialOrd, PartialEq, Eq)]
486pub struct Enumeration<T> {
487    variants: Vec<T>,
488    tag: Option<Tag>,
489    extended_after_index: Option<usize>,
490}
491
492impl<T> From<Vec<T>> for Enumeration<T> {
493    fn from(variants: Vec<T>) -> Self {
494        Enumeration {
495            variants,
496            tag: None,
497            extended_after_index: None,
498        }
499    }
500}
501
502impl<T> Enumeration<T> {
503    pub fn with_extension_after(mut self, extension_after: Option<usize>) -> Self {
504        self.extended_after_index = extension_after;
505        self
506    }
507
508    pub fn len(&self) -> usize {
509        self.variants.len()
510    }
511
512    pub fn is_empty(&self) -> bool {
513        self.variants.is_empty()
514    }
515
516    pub fn variants(&self) -> impl Iterator<Item = &T> {
517        self.variants.iter()
518    }
519
520    pub fn extension_after_index(&self) -> Option<usize> {
521        self.extended_after_index
522    }
523
524    pub fn extension_after_variant(&self) -> Option<&T> {
525        self.extended_after_index
526            .and_then(|index| self.variants.get(index))
527    }
528
529    pub fn is_extensible(&self) -> bool {
530        self.extended_after_index.is_some()
531    }
532}
533
534impl<T> TagProperty for Enumeration<T> {
535    fn tag(&self) -> Option<Tag> {
536        self.tag
537    }
538
539    fn set_tag(&mut self, tag: Tag) {
540        self.tag = Some(tag);
541    }
542
543    fn reset_tag(&mut self) {
544        self.tag = None;
545    }
546}
547
548impl PlainEnum {
549    pub fn from_names(names: impl Iterator<Item = impl ToString>) -> Self {
550        Self::from(names.map(|n| n.to_string()).collect::<Vec<_>>())
551    }
552}
553
554#[derive(Debug, Clone, PartialOrd, PartialEq)]
555pub struct DataVariant {
556    name_type: (String, RustType),
557    tag: Option<Tag>,
558}
559
560impl DataVariant {
561    pub fn from_name_type<T: ToString>(name: T, r#type: RustType) -> Self {
562        Self {
563            name_type: (name.to_string(), r#type),
564            tag: None,
565        }
566    }
567
568    pub fn fallback_representation(&self) -> &(String, RustType) {
569        &self.name_type
570    }
571
572    pub fn name(&self) -> &str {
573        &self.name_type.0
574    }
575
576    pub fn r#type(&self) -> &RustType {
577        &self.name_type.1
578    }
579}
580
581impl TagProperty for DataVariant {
582    fn tag(&self) -> Option<Tag> {
583        self.tag
584    }
585
586    fn set_tag(&mut self, tag: Tag) {
587        self.tag = Some(tag);
588    }
589
590    fn reset_tag(&mut self) {
591        self.tag = None;
592    }
593}
594
595impl Model<Rust> {
596    pub fn convert_asn_to_rust(
597        asn_model: &Model<Asn>,
598        scope: &[&Model<Asn>],
599        make_names_nice: bool,
600    ) -> Model<Rust> {
601        let mut definitions = Vec::with_capacity(asn_model.definitions.len());
602        let mut ctxt = Context {
603            resolver: TagResolver::new(asn_model, scope),
604            target: &mut definitions,
605            make_names_nice,
606        };
607        let mut model = Model {
608            name: ctxt.module_name(&asn_model.name),
609            oid: asn_model.oid.clone(),
610            imports: asn_model
611                .imports
612                .iter()
613                .map(|i| Import {
614                    what: i.what.iter().map(|w| ctxt.struct_or_enum_name(w)).collect(),
615                    from: ctxt.module_name(&i.from),
616                    from_oid: i.from_oid.clone(),
617                })
618                .collect(),
619            definitions: Vec::default(),
620            value_references: Vec::with_capacity(asn_model.value_references.len()),
621        };
622        for Definition(name, asn) in &asn_model.definitions {
623            let rust_name = ctxt.struct_or_enum_name(name);
624            Self::definition_to_rust(&rust_name, &asn.r#type, asn.tag, &mut ctxt);
625        }
626        for vref in &asn_model.value_references {
627            if let Some(rust_type) = Self::map_asn_type_to_rust_type_flat(&vref.role.r#type) {
628                model.value_references.push(ValueReference {
629                    name: ctxt.constant_name(&vref.name),
630                    role: rust_type,
631                    value: vref.value.clone(),
632                });
633            } else {
634                // TODO some kind of debug-log?
635                println!("Ignoring ValueReference {}", vref.name);
636            }
637        }
638        model.definitions = definitions;
639        model
640    }
641
642    fn map_asn_type_to_rust_type_flat(r#type: &Type) -> Option<RustType> {
643        Some(match &r#type {
644            Type::Boolean => RustType::Bool,
645            Type::Integer(int) if int.range.extensible() => {
646                Self::asn_extensible_integer_to_rust(int)
647            }
648            Type::Integer(int) => Self::asn_fixed_integer_to_rust_type(int),
649            Type::String(size, charset) => RustType::String(size.clone(), *charset),
650            Type::OctetString(size) => RustType::VecU8(size.clone()),
651            Type::BitString(bs) => RustType::BitVec(bs.size.clone()),
652            Type::Null => RustType::Null,
653            Type::Optional(opt) => {
654                RustType::Option(Box::new(Self::map_asn_type_to_rust_type_flat(opt)?))
655            }
656            Type::Default(inner, default) => RustType::Default(
657                Box::new(Self::map_asn_type_to_rust_type_flat(inner)?),
658                default.clone(),
659            ),
660            Type::TypeReference(name, tag) => RustType::Complex(name.clone(), *tag),
661            Type::Sequence(_)
662            | Type::SequenceOf(_, _)
663            | Type::Set(_)
664            | Type::SetOf(_, _)
665            | Type::Enumerated(_)
666            | Type::Choice(_) => return None,
667        })
668    }
669
670    /// Converts the given `Asn` value to `Rust`, adding new `Definition`s as
671    /// necessary (inlined types cannot be represented in rust and thus need to
672    /// be extracted to their own types).
673    /// The returned value is what shall be used to reference to the definition
674    /// and can therefore be used to be inserted in the parent element.
675    ///
676    /// The name is expected in a valid and rusty way
677    fn definition_to_rust(name: &str, asn: &AsnType, tag: Option<Tag>, ctxt: &mut Context<'_>) {
678        match asn {
679            AsnType::Boolean
680            | AsnType::Null
681            | AsnType::String(..)
682            | AsnType::OctetString(_)
683            | AsnType::BitString(_) => {
684                let rust_type = Self::definition_type_to_rust_type(name, asn, tag, ctxt);
685                ctxt.add_definition(Definition(
686                    name.to_string(),
687                    Rust::tuple_struct_from_type(rust_type).with_tag_opt(tag),
688                ));
689            }
690            AsnType::TypeReference(_, tag) => {
691                let rust_type = Self::definition_type_to_rust_type(name, asn, *tag, ctxt);
692                ctxt.add_definition(Definition(
693                    name.to_string(),
694                    Rust::tuple_struct_from_type(rust_type).with_tag_opt(*tag),
695                ));
696            }
697
698            me @ AsnType::Integer(_) => {
699                let rust_type = Self::definition_type_to_rust_type(name, asn, tag, ctxt);
700                let constants = ctxt.to_rust_constants(me);
701                ctxt.add_definition(Definition(
702                    name.into(),
703                    Rust::TupleStruct {
704                        r#type: rust_type,
705                        tag,
706                        constants,
707                    },
708                ));
709            }
710
711            AsnType::Optional(inner) => {
712                let inner = RustType::Option(Box::new(Self::definition_type_to_rust_type(
713                    name, inner, tag, ctxt,
714                )));
715                ctxt.add_definition(Definition(
716                    name.into(),
717                    Rust::tuple_struct_from_type(inner).with_tag_opt(tag),
718                ))
719            }
720
721            AsnType::Default(inner, default) => {
722                let inner = RustType::Default(
723                    Box::new(Self::definition_type_to_rust_type(name, inner, tag, ctxt)),
724                    default.clone(),
725                );
726                ctxt.add_definition(Definition(
727                    name.into(),
728                    Rust::tuple_struct_from_type(inner).with_tag_opt(tag),
729                ))
730            }
731
732            AsnType::Sequence(ComponentTypeList {
733                fields,
734                extension_after,
735            }) => {
736                let fields = Self::asn_fields_to_rust_fields(name, fields, *extension_after, ctxt);
737                ctxt.add_definition(Definition(
738                    name.into(),
739                    Rust::Struct {
740                        ordering: EncodingOrdering::Keep,
741                        fields,
742                        tag,
743                        extension_after: *extension_after,
744                    },
745                ));
746            }
747
748            AsnType::Set(ComponentTypeList {
749                fields,
750                extension_after,
751            }) => {
752                let fields = Self::asn_fields_to_rust_fields(name, fields, *extension_after, ctxt);
753                ctxt.add_definition(Definition(
754                    name.into(),
755                    Rust::Struct {
756                        ordering: EncodingOrdering::Sort,
757                        fields,
758                        tag,
759                        extension_after: *extension_after,
760                    },
761                ));
762            }
763
764            AsnType::SequenceOf(asn, size) => {
765                let inner = RustType::Vec(
766                    Box::new(Self::definition_type_to_rust_type(name, asn, tag, ctxt)),
767                    size.clone(),
768                    EncodingOrdering::Keep,
769                );
770                ctxt.add_definition(Definition(name.into(), Rust::tuple_struct_from_type(inner)));
771            }
772
773            AsnType::SetOf(asn, size) => {
774                let inner = RustType::Vec(
775                    Box::new(Self::definition_type_to_rust_type(name, asn, tag, ctxt)),
776                    size.clone(),
777                    EncodingOrdering::Sort,
778                );
779                ctxt.add_definition(Definition(
780                    name.into(),
781                    Rust::tuple_struct_from_type(inner).with_tag_opt(tag),
782                ));
783            }
784
785            AsnType::Choice(choice) => {
786                let mut enumeration = Enumeration {
787                    variants: Vec::with_capacity(choice.len()),
788                    tag,
789                    extended_after_index: choice.extension_after_index(),
790                };
791
792                for ChoiceVariant {
793                    name: variant_name,
794                    r#type,
795                    tag,
796                } in choice.variants()
797                {
798                    let rust_name = format!("{}{}", name, ctxt.struct_or_enum_name(variant_name));
799                    let rust_role =
800                        Self::definition_type_to_rust_type(&rust_name, r#type, *tag, ctxt);
801                    let rust_field_name = ctxt.variant_name(variant_name);
802                    enumeration.variants.push(
803                        DataVariant::from_name_type(rust_field_name, rust_role).with_tag_opt(*tag),
804                    );
805                }
806
807                ctxt.add_definition(Definition(name.into(), Rust::DataEnum(enumeration)));
808            }
809
810            AsnType::Enumerated(enumerated) => {
811                let mut rust_enum = Enumeration {
812                    variants: Vec::with_capacity(enumerated.len()),
813                    tag,
814                    extended_after_index: enumerated.extension_after_index(),
815                };
816
817                for variant in enumerated.variants() {
818                    rust_enum.variants.push(ctxt.variant_name(variant.name()));
819                }
820
821                ctxt.add_definition(Definition(name.into(), Rust::Enum(rust_enum)));
822            }
823        }
824    }
825
826    fn asn_fields_to_rust_fields(
827        name: &str,
828        fields: &[crate::model::Field<Asn>],
829        extension_after: Option<usize>,
830        ctxt: &mut Context<'_>,
831    ) -> Vec<Field> {
832        let mut rust_fields = Vec::with_capacity(fields.len());
833
834        for (index, field) in fields.iter().enumerate() {
835            let rust_name = format!("{}{}", name, ctxt.struct_or_enum_name(&field.name));
836            let tag = field.role.tag;
837            let rust_role =
838                Self::definition_type_to_rust_type(&rust_name, &field.role.r#type, tag, ctxt);
839            let rust_role = if let Some(def) = &field.role.default {
840                RustType::Default(Box::new(rust_role.no_option()), def.clone())
841            } else if extension_after.map(|e| index > e).unwrap_or(false)
842                && !rust_role.is_optional()
843            {
844                RustType::Option(Box::new(rust_role))
845            } else {
846                rust_role
847            };
848            let rust_field_name = ctxt.field_name(&field.name);
849            let constants = ctxt.to_rust_constants(&field.role.r#type);
850            rust_fields.push(
851                RustField::from_name_type(rust_field_name, rust_role)
852                    .with_constants(constants)
853                    .with_tag_opt(tag),
854            );
855        }
856
857        rust_fields
858    }
859
860    fn definition_type_to_rust_type(
861        name: &str,
862        asn: &AsnType,
863        tag: Option<Tag>,
864        ctxt: &mut Context<'_>,
865    ) -> RustType {
866        match asn {
867            AsnType::Boolean => RustType::Bool,
868            AsnType::Null => RustType::Null,
869            AsnType::Integer(int) if int.range.extensible() => {
870                Self::asn_extensible_integer_to_rust(int)
871            }
872            AsnType::Integer(int) => Self::asn_fixed_integer_to_rust_type(int),
873
874            AsnType::String(size, charset) => RustType::String(size.clone(), *charset),
875            AsnType::OctetString(size) => RustType::VecU8(size.clone()),
876            AsnType::BitString(bitstring) => RustType::BitVec(bitstring.size.clone()),
877            Type::Optional(inner) => {
878                RustType::Option(Box::new(Self::definition_type_to_rust_type(
879                    name,
880                    inner,
881                    tag.or_else(|| ctxt.resolver().resolve_no_default(inner)),
882                    ctxt,
883                )))
884            }
885            Type::Default(inner, default) => RustType::Default(
886                Box::new(Self::definition_type_to_rust_type(
887                    name,
888                    inner,
889                    tag.or_else(|| ctxt.resolver().resolve_no_default(inner)),
890                    ctxt,
891                )),
892                default.clone(),
893            ),
894            AsnType::SequenceOf(asn, size) => RustType::Vec(
895                Box::new(Self::definition_type_to_rust_type(
896                    name,
897                    asn,
898                    tag.or_else(|| ctxt.resolver().resolve_no_default(asn)),
899                    ctxt,
900                )),
901                size.clone(),
902                EncodingOrdering::Keep,
903            ),
904            AsnType::SetOf(asn, size) => RustType::Vec(
905                Box::new(Self::definition_type_to_rust_type(
906                    name,
907                    asn,
908                    tag.or_else(|| ctxt.resolver().resolve_no_default(asn)),
909                    ctxt,
910                )),
911                size.clone(),
912                EncodingOrdering::Sort,
913            ),
914            ty @ AsnType::Sequence(_)
915            | ty @ AsnType::Set(_)
916            | ty @ AsnType::Enumerated(_)
917            | ty @ AsnType::Choice(_) => {
918                let name = ctxt.struct_or_enum_name(name);
919                Self::definition_to_rust(&name, asn, tag, ctxt);
920                RustType::Complex(name, tag.or_else(|| ctxt.resolver().resolve_type_tag(ty)))
921            }
922            AsnType::TypeReference(name, tag) => RustType::Complex(
923                ctxt.struct_or_enum_name(name),
924                (*tag).or_else(|| ctxt.resolver().resolve_tag(name)),
925            ),
926        }
927    }
928
929    fn asn_extensible_integer_to_rust(
930        int: &Integer<<Resolved as ResolveState>::RangeType>,
931    ) -> RustType {
932        match (int.range.min(), int.range.max()) {
933            (None, None) | (Some(0), None) | (Some(0), Some(i64::MAX)) | (None, Some(i64::MAX)) => {
934                RustType::U64(Range(None, None, true))
935            }
936            (min, max) if min.unwrap_or_default() >= 0 && max.unwrap_or_default() >= 0 => {
937                RustType::U64(Range(min.map(|v| v as u64), max.map(|v| v as u64), true))
938            }
939            (min, max) => RustType::I64(Range(
940                min.unwrap_or(i64::MIN),
941                max.unwrap_or(i64::MAX),
942                true,
943            )),
944        }
945    }
946
947    fn asn_fixed_integer_to_rust_type(
948        int: &Integer<<Resolved as ResolveState>::RangeType>,
949    ) -> RustType {
950        match (int.range.min(), int.range.max()) {
951            (None, None) | (Some(0), None) | (Some(0), Some(i64::MAX)) | (None, Some(i64::MAX)) => {
952                RustType::U64(Range(None, None, false))
953            }
954            (min, max) => {
955                let min = min.unwrap_or_default();
956                let max = max.unwrap_or(i64::MAX);
957                if min >= 0 {
958                    match max as u64 {
959                        m if m <= U8_MAX => RustType::U8(Range::inclusive(min as u8, max as u8)),
960                        m if m <= U16_MAX => RustType::U16(Range::inclusive(min as u16, max as u16)),
961                        m if m <= U32_MAX => RustType::U32(Range::inclusive(min as u32, max as u32)),
962                        _/*m if m <= U64_MAX*/ => RustType::U64(Range::inclusive(Some(min as u64), Some(max as u64))),
963                        //_ => panic!("This should never happen, since max (as u64 frm i64) cannot be greater than U64_MAX")
964                    }
965                } else {
966                    // i32 => -2147483648    to    2147483647  --\
967                    //        -2147483648 + 1   = -2147483647    | same
968                    //    abs(-2147483648 + 1)  =  2147483647  --/
969                    let max_amplitude = (min + 1).abs().max(max);
970                    match max_amplitude {
971                        _ if max_amplitude <= I8_MAX => RustType::I8(Range::inclusive(min as i8, max as i8)),
972                        _ if max_amplitude <= I16_MAX => RustType::I16(Range::inclusive(min as i16, max as i16)),
973                        _ if max_amplitude <= I32_MAX => RustType::I32(Range::inclusive(min as i32, max as i32)),
974                        _/*if max_amplitude <= I64_MAX*/ => RustType::I64(Range::inclusive(min, max)),
975                        //_ => panic!("This should never happen, since max (being i64) cannot be greater than I64_MAX")
976                    }
977                }
978            }
979        }
980    }
981}
982
983struct Context<'a> {
984    resolver: TagResolver<'a>,
985    target: &'a mut Vec<Definition<Rust>>,
986    make_names_nice: bool,
987}
988
989impl Context<'_> {
990    fn to_rust_constants(&self, asn: &AsnType) -> Vec<(String, String)> {
991        match asn {
992            AsnType::Integer(integer) => integer
993                .constants
994                .iter()
995                .map(|(name, value)| (self.constant_name(name), format!("{}", value)))
996                .collect(),
997            AsnType::BitString(bitstring) => bitstring
998                .constants
999                .iter()
1000                .map(|(name, value)| (self.constant_name(name), format!("{}", value)))
1001                .collect(),
1002
1003            Type::Boolean
1004            | Type::Null
1005            | Type::String(..)
1006            | Type::OctetString(_)
1007            | Type::Optional(_)
1008            | Type::Default(..)
1009            | Type::Sequence(_)
1010            | Type::SequenceOf(..)
1011            | Type::Set(_)
1012            | Type::SetOf(..)
1013            | Type::Enumerated(_)
1014            | Type::Choice(_)
1015            | Type::TypeReference(_, _) => Vec::default(),
1016        }
1017    }
1018
1019    pub fn struct_or_enum_name(&self, name: &str) -> String {
1020        if self.make_names_nice {
1021            rust_struct_or_enum_name(name)
1022        } else {
1023            name.to_string()
1024        }
1025    }
1026
1027    pub fn constant_name(&self, name: &str) -> String {
1028        if self.make_names_nice {
1029            rust_constant_name(name)
1030        } else {
1031            name.to_string()
1032        }
1033    }
1034
1035    pub fn variant_name(&self, name: &str) -> String {
1036        if self.make_names_nice {
1037            rust_variant_name(name)
1038        } else {
1039            name.to_string()
1040        }
1041    }
1042
1043    pub fn field_name(&self, name: &str) -> String {
1044        if self.make_names_nice {
1045            rust_field_name(name)
1046        } else {
1047            name.to_string()
1048        }
1049    }
1050
1051    pub fn module_name(&self, name: &str) -> String {
1052        if self.make_names_nice {
1053            rust_module_name(name, false)
1054        } else {
1055            name.to_string()
1056        }
1057    }
1058
1059    pub fn add_definition(&mut self, def: Definition<Rust>) {
1060        self.target.push(def)
1061    }
1062
1063    pub fn resolver(&self) -> &TagResolver<'_> {
1064        &self.resolver
1065    }
1066}
1067
1068#[allow(clippy::module_name_repetitions)]
1069pub fn rust_field_name(name: &str) -> String {
1070    rust_module_name(name, false)
1071}
1072
1073#[allow(clippy::module_name_repetitions)]
1074pub fn rust_variant_name(name: &str) -> String {
1075    let mut out = String::new();
1076    let mut next_upper = true;
1077    let mut prev_upper = false;
1078    let mut chars = name.chars().peekable();
1079    while let Some(c) = chars.next() {
1080        if c == '-' || c == '_' {
1081            next_upper = true;
1082            prev_upper = false;
1083        } else if next_upper && !prev_upper {
1084            out.push(c.to_ascii_uppercase());
1085            next_upper = false;
1086            prev_upper = true;
1087        } else {
1088            if prev_upper && !chars.peek().map(|c| c.is_lowercase()).unwrap_or(false) {
1089                out.push(c.to_ascii_lowercase());
1090            } else {
1091                out.push(c);
1092            }
1093            prev_upper = c.is_ascii_uppercase();
1094        }
1095    }
1096    out
1097}
1098
1099#[allow(clippy::module_name_repetitions)]
1100pub fn rust_struct_or_enum_name(name: &str) -> String {
1101    rust_variant_name(name)
1102}
1103
1104#[allow(clippy::module_name_repetitions)]
1105pub fn rust_module_name(name: &str, pad_non_alphabetic: bool) -> String {
1106    let mut out = String::new();
1107    let mut prev_lowered = false;
1108    let mut prev_alphabetic = false;
1109    let mut chars = name.chars().peekable();
1110    while let Some(c) = chars.next() {
1111        let mut lowered = false;
1112        let alphabetic = c.is_alphabetic();
1113        if pad_non_alphabetic
1114            && prev_alphabetic != alphabetic
1115            && c != '-'
1116            && c != '_'
1117            && !out.is_empty()
1118            && !out.ends_with('_')
1119        {
1120            out.push('_');
1121        }
1122        if c.is_uppercase() {
1123            if !out.is_empty() && prev_alphabetic {
1124                if !prev_lowered {
1125                    out.push('_');
1126                } else if let Some(next) = chars.peek() {
1127                    if next.is_lowercase() {
1128                        out.push('_');
1129                    }
1130                }
1131            }
1132            lowered = true;
1133            out.push_str(&c.to_lowercase().to_string());
1134        } else if c == '-' || c == '_' {
1135            out.push('_');
1136        } else {
1137            out.push(c);
1138        }
1139        prev_lowered = lowered;
1140        prev_alphabetic = alphabetic;
1141    }
1142    out
1143}
1144
1145#[allow(clippy::module_name_repetitions)]
1146pub fn rust_constant_name(name: &str) -> String {
1147    rust_module_name(name, true).to_uppercase()
1148}
1149
1150impl LiteralValue {
1151    pub fn as_rust_const_literal_expect<F: FnOnce(&Self) -> bool>(
1152        &self,
1153        make_names_nice: bool,
1154        probe: F,
1155    ) -> impl std::fmt::Display + '_ {
1156        if probe(self) {
1157            self.as_rust_const_literal(make_names_nice)
1158        } else {
1159            panic!("Invalid string literal {:?}", self)
1160        }
1161    }
1162
1163    pub fn as_rust_const_literal(&self, make_names_nice: bool) -> impl std::fmt::Display + '_ {
1164        struct Ref<'a>(&'a LiteralValue, bool);
1165        impl std::fmt::Display for Ref<'_> {
1166            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1167                match self.0 {
1168                    LiteralValue::Boolean(v) => write!(f, "{}", v),
1169                    LiteralValue::String(v) => write!(f, "\"{}\"", v),
1170                    LiteralValue::Integer(v) => write!(f, "{}", v),
1171                    LiteralValue::OctetString(v) => {
1172                        write!(f, "[")?;
1173                        for b in v {
1174                            write!(f, "0x{:02x}, ", *b)?;
1175                        }
1176                        write!(f, "]")
1177                    }
1178                    LiteralValue::EnumeratedVariant(r#type, variant) => {
1179                        write!(
1180                            f,
1181                            "{}::{}",
1182                            if self.1 {
1183                                Cow::Owned(rust_struct_or_enum_name(r#type))
1184                            } else {
1185                                Cow::Borrowed(r#type)
1186                            },
1187                            if self.1 {
1188                                Cow::Owned(rust_variant_name(variant))
1189                            } else {
1190                                Cow::Borrowed(variant)
1191                            }
1192                        )
1193                    }
1194                }
1195            }
1196        }
1197        Ref(self, make_names_nice)
1198    }
1199}
1200
1201#[cfg(test)]
1202mod tests {
1203    use super::*;
1204    use crate::gen::rust::walker::tests::assert_starts_with_lines;
1205    use crate::gen::RustCodeGenerator;
1206    use crate::model::tag::tests::test_property;
1207    use crate::model::tests::*;
1208    use crate::model::{Choice, Enumerated, EnumeratedVariant, Field, Tag, Type};
1209    use crate::parser::Tokenizer;
1210
1211    #[test]
1212    fn test_rust_struct_or_enum_name() {
1213        fn stable_rust_struct_or_enum_name(name: &str) -> String {
1214            let v1 = rust_struct_or_enum_name(name);
1215            assert_eq!(v1, rust_struct_or_enum_name(&v1));
1216            v1
1217        }
1218
1219        assert_eq!("TestAbc", stable_rust_struct_or_enum_name("test-abc"));
1220        assert_eq!(
1221            "BerndDasBrot",
1222            stable_rust_struct_or_enum_name("berndDasBrot")
1223        );
1224        assert_eq!(
1225            "WhoKnowsWhat",
1226            stable_rust_struct_or_enum_name("who-knowsWhat")
1227        );
1228        assert_eq!("EWaffle", stable_rust_struct_or_enum_name("e-waffle"));
1229        assert_eq!("EeWaffle", stable_rust_struct_or_enum_name("ee-waffle"));
1230        assert_eq!("EeWaffle", stable_rust_struct_or_enum_name("EEWaffle"));
1231    }
1232
1233    #[test]
1234    fn test_rust_variant_name() {
1235        fn stable_rust_variant_name(name: &str) -> String {
1236            let v1 = rust_variant_name(name);
1237            assert_eq!(v1, rust_variant_name(&v1));
1238            v1
1239        }
1240
1241        assert_eq!("TestAbc", stable_rust_variant_name("test-abc"));
1242        assert_eq!("BerndDasBrot", stable_rust_variant_name("berndDasBrot"));
1243        assert_eq!("WhoKnowsWhat", stable_rust_variant_name("who-knowsWhat"));
1244        assert_eq!("EWaffle", stable_rust_variant_name("e-waffle"));
1245        assert_eq!("EeWaffle", stable_rust_variant_name("ee-waffle"));
1246        assert_eq!("EeWaffle", stable_rust_variant_name("EEWaffle"));
1247    }
1248
1249    #[test]
1250    fn test_rust_constant_name() {
1251        fn stable_constant_name(name: &str) -> String {
1252            let v1 = rust_constant_name(name);
1253            assert_eq!(v1, rust_constant_name(&v1));
1254            v1
1255        }
1256
1257        assert_eq!(
1258            "SOME_IMPORTANT_VALUE_60_DEGREE_OFFSET_30_OTHER_10_MORE_42",
1259            stable_constant_name("some-importantValue60degreeOffset-30-other10-more_42")
1260        );
1261    }
1262
1263    #[test]
1264    fn test_rust_name_multiple_upper_case() {
1265        assert_eq!(
1266            "SomeThingyThingWithId",
1267            rust_struct_or_enum_name("some-thingy-ThingWithID")
1268        );
1269    }
1270
1271    #[test]
1272    fn test_simple_asn_sequence_represented_correctly_as_rust_model() {
1273        let model_rust = Model::try_from(Tokenizer::default().parse(SIMPLE_INTEGER_STRUCT_ASN))
1274            .unwrap()
1275            .try_resolve()
1276            .unwrap()
1277            .to_rust();
1278
1279        assert_eq!("simple_schema", model_rust.name);
1280        assert_eq!(true, model_rust.imports.is_empty());
1281        assert_eq!(1, model_rust.definitions.len());
1282        assert_eq!(
1283            Definition(
1284                "Simple".into(),
1285                Rust::struct_from_fields(vec![
1286                    RustField::from_name_type("small", RustType::U8(Range::inclusive(0, 255))),
1287                    RustField::from_name_type("bigger", RustType::U16(Range::inclusive(0, 65535))),
1288                    RustField::from_name_type("negative", RustType::I16(Range::inclusive(-1, 255))),
1289                    RustField::from_name_type(
1290                        "unlimited",
1291                        RustType::Option(Box::new(RustType::U64(Range::none()))),
1292                    ),
1293                ]),
1294            ),
1295            model_rust.definitions[0]
1296        );
1297    }
1298
1299    #[test]
1300    fn test_inline_asn_enumerated_represented_correctly_as_rust_model() {
1301        let model_rust = Model::try_from(Tokenizer::default().parse(INLINE_ASN_WITH_ENUM))
1302            .unwrap()
1303            .try_resolve()
1304            .unwrap()
1305            .to_rust();
1306
1307        assert_eq!("simple_schema", model_rust.name);
1308        assert_eq!(true, model_rust.imports.is_empty());
1309        assert_eq!(2, model_rust.definitions.len());
1310        assert_eq!(
1311            Definition(
1312                "WoahDecision".into(),
1313                Rust::Enum(
1314                    vec![
1315                        "Abort".into(),
1316                        "Return".into(),
1317                        "Confirm".into(),
1318                        "Mayday".into(),
1319                        "TheCakeIsALie".into()
1320                    ]
1321                    .into()
1322                ),
1323            ),
1324            model_rust.definitions[0]
1325        );
1326        assert_eq!(
1327            Definition(
1328                "Woah".into(),
1329                Rust::struct_from_fields(vec![RustField::from_name_type(
1330                    "decision",
1331                    RustType::Option(Box::new(RustType::Complex(
1332                        "WoahDecision".into(),
1333                        Some(Tag::DEFAULT_ENUMERATED)
1334                    ))),
1335                )])
1336            ),
1337            model_rust.definitions[1]
1338        );
1339    }
1340
1341    #[test]
1342    fn test_inline_asn_sequence_of_represented_correctly_as_rust_model() {
1343        let model_rust = Model::try_from(Tokenizer::default().parse(INLINE_ASN_WITH_SEQUENCE_OF))
1344            .unwrap()
1345            .try_resolve()
1346            .unwrap()
1347            .to_rust();
1348
1349        assert_eq!("simple_schema", model_rust.name);
1350        assert_eq!(true, model_rust.imports.is_empty());
1351        assert_eq!(3, model_rust.definitions.len());
1352        assert_eq!(
1353            Definition(
1354                "Ones".into(),
1355                Rust::tuple_struct_from_type(RustType::Vec(
1356                    Box::new(RustType::U8(Range::inclusive(0, 1))),
1357                    Size::Any,
1358                    EncodingOrdering::Keep
1359                )),
1360            ),
1361            model_rust.definitions[0]
1362        );
1363        assert_eq!(
1364            Definition(
1365                "NestedOnes".into(),
1366                Rust::tuple_struct_from_type(RustType::Vec(
1367                    Box::new(RustType::Vec(
1368                        Box::new(RustType::U8(Range::inclusive(0, 1))),
1369                        Size::Any,
1370                        EncodingOrdering::Keep
1371                    )),
1372                    Size::Any,
1373                    EncodingOrdering::Keep
1374                )),
1375            ),
1376            model_rust.definitions[1]
1377        );
1378        assert_eq!(
1379            Definition(
1380                "Woah".into(),
1381                Rust::struct_from_fields(vec![
1382                    RustField::from_name_type(
1383                        "also_ones",
1384                        RustType::Vec(
1385                            Box::new(RustType::U8(Range::inclusive(0, 1))),
1386                            Size::Any,
1387                            EncodingOrdering::Keep
1388                        ),
1389                    ),
1390                    RustField::from_name_type(
1391                        "nesteds",
1392                        RustType::Vec(
1393                            Box::new(RustType::Vec(
1394                                Box::new(RustType::U8(Range::inclusive(0, 1))),
1395                                Size::Any,
1396                                EncodingOrdering::Keep
1397                            )),
1398                            Size::Any,
1399                            EncodingOrdering::Keep
1400                        ),
1401                    ),
1402                    RustField::from_name_type(
1403                        "optionals",
1404                        RustType::Option(Box::new(RustType::Vec(
1405                            Box::new(RustType::Vec(
1406                                Box::new(RustType::U64(Range::none())),
1407                                Size::Any,
1408                                EncodingOrdering::Keep
1409                            )),
1410                            Size::Any,
1411                            EncodingOrdering::Keep
1412                        ))),
1413                    )
1414                ]),
1415            ),
1416            model_rust.definitions[2]
1417        );
1418    }
1419
1420    #[test]
1421    fn test_inline_asn_choice_represented_correctly_as_rust_model() {
1422        let model_rust = Model::try_from(Tokenizer::default().parse(INLINE_ASN_WITH_CHOICE))
1423            .unwrap()
1424            .try_resolve()
1425            .unwrap()
1426            .to_rust();
1427
1428        assert_eq!("simple_schema", model_rust.name);
1429        assert_eq!(true, model_rust.imports.is_empty());
1430        assert_eq!(5, model_rust.definitions.len());
1431        assert_eq!(
1432            Definition(
1433                "This".into(),
1434                Rust::tuple_struct_from_type(RustType::Vec(
1435                    Box::new(RustType::U8(Range::inclusive(0, 1))),
1436                    Size::Any,
1437                    EncodingOrdering::Keep
1438                )),
1439            ),
1440            model_rust.definitions[0]
1441        );
1442        assert_eq!(
1443            Definition(
1444                "That".into(),
1445                Rust::tuple_struct_from_type(RustType::Vec(
1446                    Box::new(RustType::Vec(
1447                        Box::new(RustType::U8(Range::inclusive(0, 1))),
1448                        Size::Any,
1449                        EncodingOrdering::Keep
1450                    )),
1451                    Size::Any,
1452                    EncodingOrdering::Keep
1453                )),
1454            ),
1455            model_rust.definitions[1]
1456        );
1457        assert_eq!(
1458            Definition(
1459                "Neither".into(),
1460                Rust::Enum(vec!["Abc".into(), "Def".into(),].into()),
1461            ),
1462            model_rust.definitions[2]
1463        );
1464        assert_eq!(
1465            Definition(
1466                "WoahDecision".into(),
1467                Rust::DataEnum(
1468                    vec![
1469                        DataVariant::from_name_type(
1470                            "This",
1471                            RustType::Complex("This".into(), Some(Tag::DEFAULT_SEQUENCE_OF))
1472                        ),
1473                        DataVariant::from_name_type(
1474                            "That",
1475                            RustType::Complex("That".into(), Some(Tag::DEFAULT_SEQUENCE_OF))
1476                        ),
1477                        DataVariant::from_name_type(
1478                            "Neither",
1479                            RustType::Complex("Neither".into(), Some(Tag::DEFAULT_ENUMERATED))
1480                        ),
1481                    ]
1482                    .into()
1483                )
1484            ),
1485            model_rust.definitions[3]
1486        );
1487        assert_eq!(
1488            Definition(
1489                "Woah".into(),
1490                Rust::struct_from_fields(vec![RustField::from_name_type(
1491                    "decision",
1492                    RustType::Complex("WoahDecision".into(), Some(Tag::DEFAULT_ENUMERATED)),
1493                )])
1494            ),
1495            model_rust.definitions[4]
1496        );
1497    }
1498
1499    #[test]
1500    fn test_inline_asn_sequence_represented_correctly_as_rust_model() {
1501        let model_rust = Model::try_from(Tokenizer::default().parse(INLINE_ASN_WITH_SEQUENCE))
1502            .unwrap()
1503            .try_resolve()
1504            .unwrap()
1505            .to_rust();
1506
1507        assert_eq!("simple_schema", model_rust.name);
1508        assert_eq!(true, model_rust.imports.is_empty());
1509        assert_eq!(2, model_rust.definitions.len());
1510        assert_eq!(
1511            Definition(
1512                "WoahComplex".into(),
1513                Rust::struct_from_fields(vec![
1514                    RustField::from_name_type("ones", RustType::U8(Range::inclusive(0, 1))),
1515                    RustField::from_name_type(
1516                        "list_ones",
1517                        RustType::Vec(
1518                            Box::new(RustType::U8(Range::inclusive(0, 1))),
1519                            Size::Any,
1520                            EncodingOrdering::Keep
1521                        ),
1522                    ),
1523                    RustField::from_name_type(
1524                        "optional_ones",
1525                        RustType::Option(Box::new(RustType::Vec(
1526                            Box::new(RustType::U8(Range::inclusive(0, 1,))),
1527                            Size::Any,
1528                            EncodingOrdering::Keep
1529                        ))),
1530                    ),
1531                ]),
1532            ),
1533            model_rust.definitions[0]
1534        );
1535        assert_eq!(
1536            Definition(
1537                "Woah".into(),
1538                Rust::struct_from_fields(vec![RustField::from_name_type(
1539                    "complex",
1540                    RustType::Option(Box::new(RustType::Complex(
1541                        "WoahComplex".into(),
1542                        Some(Tag::DEFAULT_SEQUENCE)
1543                    ))),
1544                )]),
1545            ),
1546            model_rust.definitions[1]
1547        );
1548    }
1549
1550    #[test]
1551    fn test_simple_enum() {
1552        let mut model_asn = Model::default();
1553        model_asn.definitions.push(Definition(
1554            "SimpleEnumTest".into(),
1555            AsnType::Enumerated(Enumerated::from_names(
1556                ["Bernd", "Das-Verdammte", "Brooot"].iter(),
1557            ))
1558            .untagged(),
1559        ));
1560
1561        let model_rust = model_asn.to_rust();
1562
1563        assert_eq!(1, model_rust.definitions.len());
1564        assert_eq!(
1565            Definition(
1566                "SimpleEnumTest".into(),
1567                Rust::Enum(vec!["Bernd".into(), "DasVerdammte".into(), "Brooot".into(),].into()),
1568            ),
1569            model_rust.definitions[0]
1570        );
1571    }
1572
1573    #[test]
1574    fn test_choice_simple() {
1575        let mut model_asn = Model::default();
1576        model_asn.definitions.push(Definition(
1577            "SimpleChoiceTest".into(),
1578            AsnType::choice_from_variants(vec![
1579                ChoiceVariant::name_type("bernd-das-brot", AsnType::unconstrained_utf8string()),
1580                ChoiceVariant::name_type("nochSoEinBrot", AsnType::unconstrained_octetstring()),
1581            ])
1582            .untagged(),
1583        ));
1584
1585        let model_rust = model_asn.to_rust();
1586
1587        assert_eq!(1, model_rust.definitions.len());
1588        assert_eq!(
1589            Definition(
1590                "SimpleChoiceTest".into(),
1591                Rust::DataEnum(
1592                    vec![
1593                        DataVariant::from_name_type(
1594                            "BerndDasBrot",
1595                            RustType::String(Size::Any, Charset::Utf8),
1596                        ),
1597                        DataVariant::from_name_type("NochSoEinBrot", RustType::VecU8(Size::Any)),
1598                    ]
1599                    .into()
1600                ),
1601            ),
1602            model_rust.definitions[0]
1603        )
1604    }
1605
1606    #[test]
1607    fn test_choice_list_and_nested_list() {
1608        let mut model_asn = Model::default();
1609        model_asn.definitions.push(Definition(
1610            "ListChoiceTestWithNestedList".into(),
1611            AsnType::choice_from_variants(vec![
1612                ChoiceVariant::name_type(
1613                    "normal-List",
1614                    AsnType::SequenceOf(Box::new(AsnType::unconstrained_utf8string()), Size::Any),
1615                ),
1616                ChoiceVariant::name_type(
1617                    "NESTED-List",
1618                    AsnType::SequenceOf(
1619                        Box::new(AsnType::SequenceOf(
1620                            Box::new(AsnType::unconstrained_octetstring()),
1621                            Size::Any,
1622                        )),
1623                        Size::Any,
1624                    ),
1625                ),
1626            ])
1627            .untagged(),
1628        ));
1629
1630        let model_rust = model_asn.to_rust();
1631
1632        assert_eq!(1, model_rust.definitions.len());
1633        assert_eq!(
1634            Definition(
1635                "ListChoiceTestWithNestedList".into(),
1636                Rust::DataEnum(
1637                    vec![
1638                        DataVariant::from_name_type(
1639                            "NormalList",
1640                            RustType::Vec(
1641                                Box::new(RustType::String(Size::Any, Charset::Utf8)),
1642                                Size::Any,
1643                                EncodingOrdering::Keep
1644                            ),
1645                        ),
1646                        DataVariant::from_name_type(
1647                            "NestedList",
1648                            RustType::Vec(
1649                                Box::new(RustType::Vec(
1650                                    Box::new(RustType::VecU8(Size::Any)),
1651                                    Size::Any,
1652                                    EncodingOrdering::Keep
1653                                )),
1654                                Size::Any,
1655                                EncodingOrdering::Keep
1656                            ),
1657                        ),
1658                    ]
1659                    .into()
1660                ),
1661            ),
1662            model_rust.definitions[0]
1663        )
1664    }
1665
1666    #[test]
1667    fn test_tuple_list() {
1668        let mut model_asn = Model::default();
1669        model_asn.name = "TupleTestModel".into();
1670        model_asn.definitions.push(Definition(
1671            "TupleTest".into(),
1672            AsnType::SequenceOf(Box::new(AsnType::unconstrained_utf8string()), Size::Any)
1673                .untagged(),
1674        ));
1675        let model_rust = model_asn.to_rust();
1676        assert_eq!("tuple_test_model", model_rust.name);
1677        assert_eq!(model_asn.imports, model_rust.imports);
1678        assert_eq!(1, model_rust.definitions.len());
1679        assert_eq!(
1680            Definition(
1681                "TupleTest".into(),
1682                Rust::tuple_struct_from_type(RustType::Vec(
1683                    Box::new(RustType::String(Size::Any, Charset::Utf8)),
1684                    Size::Any,
1685                    EncodingOrdering::Keep
1686                )),
1687            ),
1688            model_rust.definitions[0]
1689        );
1690    }
1691
1692    #[test]
1693    fn test_nested_tuple_list() {
1694        let mut model_asn = Model::default();
1695        model_asn.name = "TupleTestModel".into();
1696        model_asn.definitions.push(Definition(
1697            "NestedTupleTest".into(),
1698            AsnType::SequenceOf(
1699                Box::new(AsnType::SequenceOf(
1700                    Box::new(AsnType::unconstrained_utf8string()),
1701                    Size::Any,
1702                )),
1703                Size::Any,
1704            )
1705            .untagged(),
1706        ));
1707        let model_rust = model_asn.to_rust();
1708        assert_eq!("tuple_test_model", model_rust.name);
1709        assert_eq!(model_asn.imports, model_rust.imports);
1710        assert_eq!(1, model_rust.definitions.len());
1711        assert_eq!(
1712            Definition(
1713                "NestedTupleTest".into(),
1714                Rust::tuple_struct_from_type(RustType::Vec(
1715                    Box::new(RustType::Vec(
1716                        Box::new(RustType::String(Size::Any, Charset::Utf8)),
1717                        Size::Any,
1718                        EncodingOrdering::Keep
1719                    )),
1720                    Size::Any,
1721                    EncodingOrdering::Keep
1722                )),
1723            ),
1724            model_rust.definitions[0]
1725        );
1726    }
1727
1728    #[test]
1729    fn test_optional_list_in_struct() {
1730        let mut model_asn = Model::default();
1731        model_asn.name = "OptionalStructListTestModel".into();
1732        model_asn.definitions.push(Definition(
1733            "OptionalStructListTest".into(),
1734            AsnType::sequence_from_fields(vec![Field {
1735                name: "strings".into(),
1736                role: AsnType::SequenceOf(Box::new(AsnType::unconstrained_utf8string()), Size::Any)
1737                    .optional()
1738                    .untagged(),
1739            }])
1740            .untagged(),
1741        ));
1742        let model_rust = model_asn.to_rust();
1743        assert_eq!("optional_struct_list_test_model", model_rust.name);
1744        assert_eq!(model_asn.imports, model_rust.imports);
1745        assert_eq!(1, model_rust.definitions.len());
1746        assert_eq!(
1747            Definition(
1748                "OptionalStructListTest".into(),
1749                Rust::struct_from_fields(vec![RustField::from_name_type(
1750                    "strings",
1751                    RustType::Option(Box::new(RustType::Vec(
1752                        Box::new(RustType::String(Size::Any, Charset::Utf8)),
1753                        Size::Any,
1754                        EncodingOrdering::Keep
1755                    ))),
1756                )]),
1757            ),
1758            model_rust.definitions[0]
1759        );
1760    }
1761
1762    #[test]
1763    fn test_list_in_struct() {
1764        let mut model_asn = Model::default();
1765        model_asn.name = "StructListTestModel".into();
1766        model_asn.definitions.push(Definition(
1767            "StructListTest".into(),
1768            AsnType::sequence_from_fields(vec![Field {
1769                name: "strings".into(),
1770                role: AsnType::SequenceOf(Box::new(AsnType::unconstrained_utf8string()), Size::Any)
1771                    .untagged(),
1772            }])
1773            .untagged(),
1774        ));
1775        let model_rust = model_asn.to_rust();
1776        assert_eq!("struct_list_test_model", model_rust.name);
1777        assert_eq!(model_asn.imports, model_rust.imports);
1778        assert_eq!(1, model_rust.definitions.len());
1779        assert_eq!(
1780            Definition(
1781                "StructListTest".into(),
1782                Rust::struct_from_fields(vec![RustField::from_name_type(
1783                    "strings",
1784                    RustType::Vec(
1785                        Box::new(RustType::String(Size::Any, Charset::Utf8)),
1786                        Size::Any,
1787                        EncodingOrdering::Keep
1788                    ),
1789                )]),
1790            ),
1791            model_rust.definitions[0]
1792        );
1793    }
1794
1795    #[test]
1796    fn test_nested_list_in_struct() {
1797        let mut model_asn = Model::default();
1798        model_asn.name = "NestedStructListTestModel".into();
1799        model_asn.definitions.push(Definition(
1800            "NestedStructListTest".into(),
1801            AsnType::sequence_from_fields(vec![Field {
1802                name: "strings".into(),
1803                role: AsnType::SequenceOf(
1804                    Box::new(AsnType::SequenceOf(
1805                        Box::new(AsnType::unconstrained_utf8string()),
1806                        Size::Any,
1807                    )),
1808                    Size::Any,
1809                )
1810                .untagged(),
1811            }])
1812            .untagged(),
1813        ));
1814        let model_rust = model_asn.to_rust();
1815        assert_eq!("nested_struct_list_test_model", model_rust.name);
1816        assert_eq!(model_asn.imports, model_rust.imports);
1817        assert_eq!(1, model_rust.definitions.len());
1818        assert_eq!(
1819            Definition(
1820                "NestedStructListTest".into(),
1821                Rust::struct_from_fields(vec![RustField::from_name_type(
1822                    "strings",
1823                    RustType::Vec(
1824                        Box::new(RustType::Vec(
1825                            Box::new(RustType::String(Size::Any, Charset::Utf8)),
1826                            Size::Any,
1827                            EncodingOrdering::Keep
1828                        )),
1829                        Size::Any,
1830                        EncodingOrdering::Keep
1831                    ),
1832                )]),
1833            ),
1834            model_rust.definitions[0]
1835        );
1836    }
1837
1838    #[test]
1839    pub fn test_extensible_enum() {
1840        let mut model_asn = Model::default();
1841        model_asn.name = "ExtensibleEnum".to_string();
1842        model_asn.definitions.push(Definition(
1843            "Extensible".to_string(),
1844            AsnType::Enumerated(
1845                Enumerated::from(vec![
1846                    "abc".into(),
1847                    "def".into(),
1848                    EnumeratedVariant::from_name_number("ghi", 42),
1849                ])
1850                .with_extension_after(2),
1851            )
1852            .untagged(),
1853        ));
1854        let model_rust = model_asn.to_rust();
1855        assert_eq!("extensible_enum", model_rust.name);
1856        assert_eq!(model_asn.imports, model_rust.imports);
1857        assert_eq!(
1858            &[Definition(
1859                "Extensible".into(),
1860                Rust::Enum(
1861                    PlainEnum::from_names(["Abc", "Def", "Ghi"].iter())
1862                        .with_extension_after(Some(2))
1863                ),
1864            )],
1865            &model_rust.definitions[..]
1866        );
1867    }
1868
1869    #[test]
1870    pub fn test_extensible_choice() {
1871        let mut model_asn = Model::default();
1872        model_asn.name = "ExtensibleChoice".to_string();
1873        model_asn.definitions.push(Definition(
1874            "Extensible".to_string(),
1875            AsnType::Choice(
1876                Choice::from(vec![
1877                    ChoiceVariant::name_type("abc", Type::unconstrained_octetstring()),
1878                    ChoiceVariant::name_type("def", Type::unconstrained_integer()),
1879                    ChoiceVariant {
1880                        name: "ghi".to_string(),
1881                        tag: Some(Tag::Universal(4)),
1882                        r#type: Type::Boolean,
1883                    },
1884                ])
1885                .with_extension_after(2),
1886            )
1887            .untagged(),
1888        ));
1889
1890        let model_rust = model_asn.to_rust();
1891        assert_eq!("extensible_choice", model_rust.name);
1892        assert_eq!(model_asn.imports, model_rust.imports);
1893        assert_eq!(
1894            &[Definition(
1895                "Extensible".into(),
1896                Rust::DataEnum(
1897                    DataEnum::from(vec![
1898                        DataVariant::from_name_type("Abc".to_string(), RustType::VecU8(Size::Any)),
1899                        DataVariant::from_name_type(
1900                            "Def".to_string(),
1901                            RustType::U64(Range::none()),
1902                        ),
1903                        DataVariant::from_name_type("Ghi".to_string(), RustType::Bool)
1904                            .with_tag(Tag::Universal(4)),
1905                    ])
1906                    .with_extension_after(Some(2))
1907                ),
1908            )],
1909            &model_rust.definitions[..]
1910        );
1911    }
1912
1913    #[test]
1914    pub fn test_tag_property_rust_struct() {
1915        test_property(Rust::Struct {
1916            ordering: EncodingOrdering::Keep,
1917            fields: Vec::default(),
1918            tag: None,
1919            extension_after: None,
1920        });
1921    }
1922
1923    #[test]
1924    pub fn test_tag_property_rust_enum() {
1925        test_property(Rust::Enum(PlainEnum::from_names(
1926            Some("Variant").into_iter(),
1927        )));
1928    }
1929
1930    #[test]
1931    pub fn test_tag_property_rust_data_enum() {
1932        test_property(Rust::DataEnum(DataEnum::from(vec![
1933            DataVariant::from_name_type(
1934                "SomeName".to_string(),
1935                RustType::String(Size::Any, Charset::Visible),
1936            ),
1937        ])));
1938    }
1939
1940    #[test]
1941    pub fn test_tag_property_rust_tuple_struct() {
1942        test_property(Rust::TupleStruct {
1943            r#type: RustType::VecU8(Size::Any),
1944            tag: None,
1945            constants: Vec::default(),
1946        });
1947    }
1948
1949    #[test]
1950    pub fn test_tag_property_field() {
1951        test_property(RustField::from_name_type(
1952            "FieldName".to_string(),
1953            RustType::Bool,
1954        ));
1955    }
1956
1957    #[test]
1958    pub fn test_tag_property_enumeration() {
1959        test_property(Enumeration::from(vec!["VariantA", "VariantB"]));
1960    }
1961
1962    #[test]
1963    pub fn test_tag_property_data_variant() {
1964        test_property(DataVariant::from_name_type(
1965            "VariantName".to_string(),
1966            RustType::Bool,
1967        ));
1968    }
1969
1970    #[test]
1971    pub fn test_value_reference_to_rust() {
1972        let asn = Model::<Asn<Resolved>> {
1973            name: "SomeGreatName".to_string(),
1974            oid: None,
1975            imports: Vec::default(),
1976            definitions: Vec::default(),
1977            value_references: vec![
1978                ValueReference {
1979                    name: "local-http".to_string(),
1980                    role: AsnType::Integer(Integer::with_range(Range::inclusive(
1981                        None,
1982                        Some(65535),
1983                    )))
1984                    .untagged(),
1985                    value: LiteralValue::Integer(8080),
1986                },
1987                ValueReference {
1988                    name: "use-firewall".to_string(),
1989                    role: AsnType::Boolean.untagged(),
1990                    value: LiteralValue::Boolean(true),
1991                },
1992            ],
1993        };
1994
1995        assert_starts_with_lines(
1996            r#"
1997            use asn1rs::prelude::*;
1998
1999            pub const LOCAL_HTTP: u16 = 8080;
2000            pub const USE_FIREWALL: bool = true;
2001
2002        "#,
2003            &RustCodeGenerator::from(asn.to_rust())
2004                .to_string_without_generators()
2005                .into_iter()
2006                .map(|(_f, c)| c)
2007                .next()
2008                .unwrap(),
2009        );
2010    }
2011
2012    #[test]
2013    fn test_to_rust_coherent_complex_reference_renaming() {
2014        let asn = Model::<Asn<Resolved>> {
2015            name: "CoherentComplexRenaming".to_string(),
2016            oid: None,
2017            imports: vec![],
2018            definitions: vec![
2019                Definition("Some-Name-WithID".to_string(), Type::Boolean.untagged()),
2020                Definition(
2021                    "Complex-Container".to_string(),
2022                    Type::Sequence(ComponentTypeList {
2023                        fields: vec![
2024                            Field {
2025                                name: "some-internal".to_string(),
2026                                role: Type::Boolean.untagged(),
2027                            },
2028                            Field {
2029                                name: "id".to_string(),
2030                                role: Type::TypeReference("Some-Name-WithID".to_string(), None)
2031                                    .untagged(),
2032                            },
2033                        ],
2034                        extension_after: None,
2035                    })
2036                    .untagged(),
2037                ),
2038            ],
2039            value_references: vec![],
2040        };
2041        assert_eq!(
2042            vec![
2043                Definition(
2044                    "SomeNameWithId".to_string(),
2045                    Rust::TupleStruct {
2046                        r#type: RustType::Bool,
2047                        tag: None,
2048                        constants: vec![]
2049                    }
2050                ),
2051                Definition(
2052                    "ComplexContainer".to_string(),
2053                    Rust::Struct {
2054                        ordering: EncodingOrdering::Keep,
2055                        fields: vec![
2056                            crate::model::rust::Field::from_name_type(
2057                                "some_internal".to_string(),
2058                                RustType::Bool
2059                            ),
2060                            crate::model::rust::Field::from_name_type(
2061                                "id".to_string(),
2062                                RustType::Complex(
2063                                    "SomeNameWithId".to_string(),
2064                                    Some(Tag::Universal(1)) // where does this come from!?
2065                                )
2066                            ),
2067                        ],
2068                        tag: None,
2069                        extension_after: None
2070                    }
2071                ),
2072            ],
2073            asn.to_rust().definitions
2074        );
2075    }
2076}