asn1rs_model/model/
mod.rs

1pub mod protobuf;
2pub mod rust;
3pub mod sql;
4
5pub use self::rust::Rust;
6pub use self::rust::RustType;
7
8pub use self::protobuf::Protobuf;
9pub use self::protobuf::ProtobufType;
10
11use crate::parser::{Location, Token};
12use std::convert::TryFrom;
13use std::fmt::Debug;
14use std::iter::Peekable;
15use std::vec::IntoIter;
16
17macro_rules! loop_ctrl_separator {
18    ($token:expr) => {
19        match $token {
20            t if t.eq_separator(',') => continue,
21            t if t.eq_separator('}') => break,
22            t => return Err(Error::unexpected_token(t)),
23        }
24    };
25}
26
27mod asn;
28mod bit_string;
29mod charset;
30mod choice;
31mod components;
32mod definition;
33mod enumerated;
34mod err;
35mod int;
36mod itc;
37pub mod lor;
38mod oid;
39mod parse;
40mod range;
41mod rs;
42mod size;
43mod tag;
44mod tag_resolver;
45
46use crate::model::itc::InnerTypeConstraints;
47use crate::model::lor::{ResolveState, Resolved, Resolver, Unresolved};
48pub use asn::Asn;
49pub use asn::Type;
50pub use bit_string::BitString;
51pub use charset::Charset;
52pub use choice::Choice;
53pub use choice::ChoiceVariant;
54pub use components::ComponentTypeList;
55pub use definition::Definition;
56pub use enumerated::Enumerated;
57pub use enumerated::EnumeratedVariant;
58pub use err::Error;
59pub use err::ErrorKind;
60pub use int::Integer;
61pub use lor::Error as ResolveError;
62pub use lor::LitOrRef;
63pub use oid::{ObjectIdentifier, ObjectIdentifierComponent};
64pub use parse::PeekableTokens;
65pub use range::Range;
66pub use rs::MultiModuleResolver;
67pub use size::Size;
68pub use tag::Tag;
69pub use tag::TagProperty;
70pub use tag_resolver::TagResolver;
71
72#[derive(Debug, Clone)]
73pub struct Model<T: Target> {
74    pub name: String,
75    pub oid: Option<ObjectIdentifier>,
76    pub imports: Vec<Import>,
77    pub definitions: Vec<Definition<T::DefinitionType>>,
78    pub value_references: Vec<ValueReference<T::ValueReferenceType>>,
79}
80
81pub trait Target {
82    type DefinitionType;
83    type ValueReferenceType;
84}
85
86impl<T: Target> Default for Model<T> {
87    fn default() -> Self {
88        Model {
89            name: Default::default(),
90            oid: None,
91            imports: Default::default(),
92            definitions: Default::default(),
93            value_references: Vec::default(),
94        }
95    }
96}
97
98impl Model<Asn<Unresolved>> {
99    pub fn try_from(value: Vec<Token>) -> Result<Self, Error> {
100        let mut model = Model::default();
101        let mut iter = value.into_iter().peekable();
102
103        model.name = Self::read_name(&mut iter)?;
104        model.oid = Self::maybe_read_oid(&mut iter)?;
105        Self::skip_until_after_text_ignore_ascii_case(&mut iter, "BEGIN")?;
106
107        while let Some(token) = iter.next() {
108            if token.eq_text_ignore_ascii_case("END") {
109                model.make_names_nice();
110                return Ok(model);
111            } else if token.eq_text_ignore_ascii_case("IMPORTS") {
112                Self::read_imports(&mut iter)?
113                    .into_iter()
114                    .for_each(|i| model.imports.push(i));
115            } else if iter.peek_is_separator_eq(':') {
116                model.definitions.push(Self::read_definition(
117                    &mut iter,
118                    token.into_text_or_else(Error::unexpected_token)?,
119                )?);
120            } else {
121                model.value_references.push(Self::read_value_reference(
122                    &mut iter,
123                    token.into_text_or_else(Error::unexpected_token)?,
124                )?);
125            }
126        }
127        Err(Error::unexpected_end_of_stream())
128    }
129
130    fn read_name(iter: &mut Peekable<IntoIter<Token>>) -> Result<String, Error> {
131        iter.next()
132            .and_then(|token| token.into_text())
133            .ok_or_else(Error::missing_module_name)
134    }
135
136    fn maybe_read_oid(
137        iter: &mut Peekable<IntoIter<Token>>,
138    ) -> Result<Option<ObjectIdentifier>, Error> {
139        if iter.next_is_separator_and_eq('{') {
140            Ok(Some(Self::read_oid(iter)?))
141        } else {
142            Ok(None)
143        }
144    }
145
146    fn read_oid(iter: &mut Peekable<IntoIter<Token>>) -> Result<ObjectIdentifier, Error> {
147        let mut vec = Vec::default();
148        while let Some(token) = iter.next() {
149            if token.eq_separator('}') {
150                break;
151            } else if let Some(identifier) = token.text() {
152                if identifier.chars().all(char::is_numeric) {
153                    vec.push(ObjectIdentifierComponent::NumberForm(
154                        identifier
155                            .parse()
156                            .map_err(|_| Error::invalid_int_value(token))?,
157                    ));
158                } else if iter.next_is_separator_and_eq('(') {
159                    let number = match iter.next_text_or_err()?.parse::<u64>() {
160                        Ok(number) => number,
161                        Err(_) => return Err(Error::invalid_int_value(token)),
162                    };
163                    iter.next_separator_eq_or_err(')')?;
164                    vec.push(ObjectIdentifierComponent::NameAndNumberForm(
165                        identifier.to_string(),
166                        number,
167                    ));
168                } else {
169                    vec.push(ObjectIdentifierComponent::NameForm(identifier.to_string()));
170                }
171            } else {
172                return Err(Error::unexpected_token(token));
173            }
174        }
175        Ok(ObjectIdentifier(vec))
176    }
177
178    fn skip_until_after_text_ignore_ascii_case(
179        iter: &mut Peekable<IntoIter<Token>>,
180        text: &str,
181    ) -> Result<(), Error> {
182        for t in iter {
183            if t.eq_text_ignore_ascii_case(text) {
184                return Ok(());
185            }
186        }
187        Err(Error::unexpected_end_of_stream())
188    }
189
190    fn read_imports(iter: &mut Peekable<IntoIter<Token>>) -> Result<Vec<Import>, Error> {
191        let mut imports = Vec::new();
192        let mut import = Import::default();
193        while let Some(token) = iter.next() {
194            if token.eq_separator(';') {
195                return Ok(imports);
196            } else {
197                let text = token.into_text_or_else(Error::unexpected_token)?;
198                import.what.push(text);
199                let token = iter.next_or_err()?;
200                if token.eq_separator(',') {
201                    // ignore separator
202                } else if token.eq_text_ignore_ascii_case("FROM") {
203                    import.from = iter.next_text_or_err()?;
204                    import.from_oid = Self::maybe_read_oid(iter)?;
205                    imports.push(import);
206                    import = Import::default();
207                }
208            }
209        }
210        Err(Error::unexpected_end_of_stream())
211    }
212    fn read_definition(
213        iter: &mut Peekable<IntoIter<Token>>,
214        name: String,
215    ) -> Result<Definition<Asn<Unresolved>>, Error> {
216        iter.next_separator_eq_or_err(':')?;
217        iter.next_separator_eq_or_err(':')?;
218        iter.next_separator_eq_or_err('=')?;
219
220        let (token, tag) = Self::next_with_opt_tag(iter)?;
221
222        if token.eq_text_ignore_ascii_case("SEQUENCE") {
223            Ok(Definition(
224                name,
225                Self::read_sequence_or_sequence_of(iter)?.opt_tagged(tag),
226            ))
227        } else if token.eq_text_ignore_ascii_case("SET") {
228            Ok(Definition(
229                name,
230                Self::read_set_or_set_of(iter)?.opt_tagged(tag),
231            ))
232        } else if token.eq_text_ignore_ascii_case("ENUMERATED") {
233            Ok(Definition(
234                name,
235                Type::Enumerated(Enumerated::try_from(iter)?).opt_tagged(tag),
236            ))
237        } else if token.eq_text_ignore_ascii_case("CHOICE") {
238            Ok(Definition(
239                name,
240                Type::Choice(Choice::try_from(iter)?).opt_tagged(tag),
241            ))
242        } else if let Some(text) = token.text() {
243            Ok(Definition(
244                name,
245                Self::read_role_given_text(iter, text.to_string())?.opt_tagged(tag),
246            ))
247        } else {
248            Err(Error::unexpected_token(token))
249        }
250    }
251
252    fn read_value_reference<T: Iterator<Item = Token>>(
253        iter: &mut Peekable<T>,
254        name: String,
255    ) -> Result<ValueReference<Asn<Unresolved>>, Error> {
256        let r#type = Self::read_role(iter)?;
257        Ok(ValueReference {
258            name,
259            value: {
260                iter.next_separator_eq_or_err(':')?;
261                iter.next_separator_eq_or_err(':')?;
262                iter.next_separator_eq_or_err('=')?;
263                Self::read_literal(iter)?
264            },
265            role: Asn {
266                tag: None,
267                r#type,
268                default: None,
269            },
270        })
271    }
272
273    fn read_literal<T: Iterator<Item = Token>>(
274        iter: &mut Peekable<T>,
275    ) -> Result<LiteralValue, ErrorKind> {
276        let location = iter.peek_or_err()?.location();
277        let string = {
278            // boolean or integer
279            #[allow(clippy::blocks_in_if_conditions)]
280            if iter.peek_is_text_eq_ignore_case("true")
281                || iter.peek_is_text_eq_ignore_case("false")
282                || iter.peek_is_text_and_satisfies(|slice| {
283                    slice.chars().all(|c| c.is_ascii_digit())
284                        || (slice.starts_with('-')
285                            && slice.len() > 1
286                            && slice.chars().skip(1).all(|c| c.is_ascii_digit()))
287                })
288            {
289                iter.next_text_or_err()?
290            } else if iter.peek_is_separator_eq('"') {
291                Self::read_string_literal(iter, '"')?
292            } else if iter.peek_is_separator_eq('\'') {
293                Self::read_hex_or_bit_string_literal(iter)?
294            } else {
295                return Err(ErrorKind::UnsupportedLiteral(iter.peek_or_err()?.clone()));
296            }
297        };
298        LiteralValue::try_from_asn_str(&string)
299            .ok_or(ErrorKind::InvalidLiteral(Token::Text(location, string)))
300    }
301
302    fn read_string_literal<T: Iterator<Item = Token>>(
303        iter: &mut Peekable<T>,
304        delimiter: char,
305    ) -> Result<String, ErrorKind> {
306        iter.next_separator_eq_or_err(delimiter)?;
307        let token = iter.next_or_err()?;
308
309        let first_text = token.text().unwrap_or_default();
310        let mut string = String::from(delimiter);
311        string.push_str(first_text);
312        let mut prev_loc = Location::at(
313            token.location().line(),
314            token.location().column() + first_text.chars().count(),
315        );
316
317        loop {
318            match iter.next_or_err()? {
319                t if t.eq_separator(delimiter) => break,
320                Token::Text(loc, str) => {
321                    for _ in prev_loc.column()..loc.column() {
322                        string.push(' ');
323                    }
324                    string.push_str(&str);
325                    prev_loc = Location::at(loc.line(), loc.column() + str.chars().count())
326                }
327                Token::Separator(loc, char) => {
328                    for _ in prev_loc.column()..loc.column() {
329                        string.push(' ');
330                    }
331                    string.push(char);
332                    prev_loc = Location::at(loc.line(), loc.column() + 1)
333                }
334            }
335        }
336
337        string.push(delimiter);
338
339        Ok(string)
340    }
341
342    fn read_hex_or_bit_string_literal<T: Iterator<Item = Token>>(
343        iter: &mut Peekable<T>,
344    ) -> Result<String, ErrorKind> {
345        let mut string = Self::read_string_literal(iter, '\'')?;
346        match iter.next_text_eq_any_ignore_case_or_err(&["H", "B"])? {
347            Token::Text(_, suffix) => string.push_str(&suffix),
348            t => return Err(ErrorKind::UnexpectedToken(t)),
349        };
350        Ok(string)
351    }
352
353    fn next_with_opt_tag<T: Iterator<Item = Token>>(
354        iter: &mut Peekable<T>,
355    ) -> Result<(Token, Option<Tag>), Error> {
356        let token = iter.next_or_err()?;
357        if token.eq_separator('[') {
358            let tag = Tag::try_from(&mut *iter)?;
359            iter.next_separator_eq_or_err(']')?;
360            let token = iter.next_or_err()?;
361            Ok((token, Some(tag)))
362        } else {
363            Ok((token, None))
364        }
365    }
366
367    fn read_role<T: Iterator<Item = Token>>(
368        iter: &mut Peekable<T>,
369    ) -> Result<Type<Unresolved>, Error> {
370        let text = iter.next_text_or_err()?;
371        Self::read_role_given_text(iter, text)
372    }
373
374    fn read_role_given_text<T: Iterator<Item = Token>>(
375        iter: &mut Peekable<T>,
376        text: String,
377    ) -> Result<Type<Unresolved>, Error> {
378        Ok(match text.to_ascii_lowercase().as_ref() {
379            "integer" => Type::Integer(Integer::try_from(iter)?),
380            "boolean" => Type::Boolean,
381            "null" => Type::Null,
382            "utf8string" => Type::String(Self::maybe_read_size(iter)?, Charset::Utf8),
383            "ia5string" => Type::String(Self::maybe_read_size(iter)?, Charset::Ia5),
384            "numericstring" => Type::String(Self::maybe_read_size(iter)?, Charset::Numeric),
385            "printablestring" => Type::String(Self::maybe_read_size(iter)?, Charset::Printable),
386            "visiblestring" => Type::String(Self::maybe_read_size(iter)?, Charset::Visible),
387            "octet" => {
388                iter.next_text_eq_ignore_case_or_err("STRING")?;
389                Type::OctetString(Self::maybe_read_size(iter)?)
390            }
391            "bit" => {
392                iter.next_text_eq_ignore_case_or_err("STRING")?;
393                Type::BitString(BitString::try_from(iter)?)
394            }
395            "enumerated" => Type::Enumerated(Enumerated::try_from(iter)?),
396            "choice" => Type::Choice(Choice::try_from(iter)?),
397            "sequence" => Self::read_sequence_or_sequence_of(iter)?,
398            "set" => Self::read_set_or_set_of(iter)?,
399            _ => {
400                // TODO use InnerTypeConstraints to flatten TypeReference to an actual type and
401                //      prevent tuple-type nesting in the generated rust and other code by copying
402                //      over the fields and adding these additional constraints
403                let _ = Self::maybe_read_with_components_constraint(iter)?;
404                Type::TypeReference(text, None)
405            }
406        })
407    }
408
409    fn maybe_read_with_components_constraint<T: Iterator<Item = Token>>(
410        iter: &mut Peekable<T>,
411    ) -> Result<Option<InnerTypeConstraints>, Error> {
412        if iter.next_is_separator_and_eq('(') {
413            let result = InnerTypeConstraints::try_from(&mut *iter)?;
414            iter.next_separator_eq_or_err(')')?;
415            Ok(Some(result))
416        } else {
417            Ok(None)
418        }
419    }
420
421    fn maybe_read_size<T: Iterator<Item = Token>>(
422        iter: &mut Peekable<T>,
423    ) -> Result<Size<<Unresolved as ResolveState>::SizeType>, Error> {
424        if iter.next_is_separator_and_eq('(') {
425            let result = Size::try_from(&mut *iter)?;
426            iter.next_separator_eq_or_err(')')?;
427            Ok(result)
428        } else if iter.peek_is_text_eq_ignore_case("SIZE") {
429            Size::try_from(iter)
430        } else {
431            Ok(Size::Any)
432        }
433    }
434
435    fn read_sequence_or_sequence_of<T: Iterator<Item = Token>>(
436        iter: &mut Peekable<T>,
437    ) -> Result<Type<Unresolved>, Error> {
438        let size = Self::maybe_read_size(iter)?;
439
440        if iter.next_is_text_and_eq_ignore_case("OF") {
441            Ok(Type::SequenceOf(Box::new(Self::read_role(iter)?), size))
442        } else {
443            Ok(Type::Sequence(ComponentTypeList::try_from(iter)?))
444        }
445    }
446
447    fn read_set_or_set_of<T: Iterator<Item = Token>>(
448        iter: &mut Peekable<T>,
449    ) -> Result<Type<Unresolved>, Error> {
450        let size = Self::maybe_read_size(iter)?;
451
452        if iter.next_is_text_and_eq_ignore_case("OF") {
453            Ok(Type::SetOf(Box::new(Self::read_role(iter)?), size))
454        } else {
455            Ok(Type::Set(ComponentTypeList::try_from(iter)?))
456        }
457    }
458
459    fn read_field<T: Iterator<Item = Token>>(
460        iter: &mut Peekable<T>,
461    ) -> Result<(Field<Asn<Unresolved>>, bool), Error> {
462        let name = iter.next_text_or_err()?;
463        let (token, tag) = Self::next_with_opt_tag(iter)?;
464        let mut field = Field {
465            name,
466            role: Self::read_role_given_text(iter, token.into_text_or_else(Error::no_text)?)?
467                .opt_tagged(tag),
468        };
469
470        let token = {
471            let token = iter.next_or_err()?;
472            if token.eq_text_ignore_ascii_case("OPTIONAL") {
473                field.role.make_optional();
474                iter.next_or_err()?
475            } else if token.eq_text_ignore_ascii_case("DEFAULT") {
476                if cfg!(feature = "debug-proc-macro") {
477                    println!("TOKEN:::: {:?}", token);
478                }
479                field.role.set_default(match Self::read_literal(iter) {
480                    Ok(value) => LitOrRef::Lit(value),
481                    Err(ErrorKind::UnsupportedLiteral(token, ..)) if token.is_text() => {
482                        LitOrRef::Ref(iter.next_text_or_err()?)
483                    }
484                    Err(e) => return Err(e.into()),
485                });
486                if cfg!(feature = "debug-proc-macro") {
487                    println!("     :::: {:?}", field);
488                }
489                iter.next_or_err()?
490            } else {
491                token
492            }
493        };
494
495        let (continues, ends) = token
496            .separator()
497            .map_or((false, false), |s| (s == ',', s == '}'));
498
499        if continues || ends {
500            Ok((field, continues))
501        } else {
502            Err(Error::unexpected_token(token))
503        }
504    }
505}
506
507impl Model<Asn<Resolved>> {
508    pub fn to_rust(&self) -> Model<rust::Rust> {
509        let scope: &[&Self] = &[];
510        Model::to_rust_with_scope(self, scope)
511    }
512
513    pub fn to_rust_keep_names(&self) -> Model<rust::Rust> {
514        let scope: &[&Self] = &[];
515        Model::to_rust_keep_names_with_scope(self, scope)
516    }
517
518    pub fn to_rust_with_scope(&self, scope: &[&Self]) -> Model<rust::Rust> {
519        Model::convert_asn_to_rust(self, scope, true)
520    }
521
522    pub fn to_rust_keep_names_with_scope(&self, scope: &[&Self]) -> Model<rust::Rust> {
523        Model::convert_asn_to_rust(self, scope, false)
524    }
525}
526
527impl<RS: ResolveState> Model<Asn<RS>> {
528    pub fn make_names_nice(&mut self) {
529        Self::make_name_nice(&mut self.name);
530        for import in &mut self.imports {
531            Self::make_name_nice(&mut import.from);
532        }
533    }
534
535    fn make_name_nice(name: &mut String) {
536        const TO_REMOVE_AT_END: &[&str] = &["_Module", "Module"];
537        for to_remove in TO_REMOVE_AT_END.iter() {
538            if name.ends_with(to_remove) {
539                let new_len = name.len() - to_remove.len();
540                name.truncate(new_len);
541            }
542        }
543    }
544
545    fn maybe_read_constants<R, F: Fn(Token) -> Result<R, Error>, T: Iterator<Item = Token>>(
546        iter: &mut Peekable<T>,
547        parser: F,
548    ) -> Result<Vec<(String, R)>, Error> {
549        let mut constants = Vec::default();
550        if iter.next_is_separator_and_eq('{') {
551            loop {
552                constants.push(Self::read_constant(iter, &parser)?);
553                loop_ctrl_separator!(iter.next_or_err()?);
554            }
555        }
556        Ok(constants)
557    }
558
559    fn read_constant<R, F: Fn(Token) -> Result<R, Error>, T: Iterator<Item = Token>>(
560        iter: &mut Peekable<T>,
561        parser: F,
562    ) -> Result<(String, R), Error> {
563        let name = iter.next_text_or_err()?;
564        iter.next_separator_eq_or_err('(')?;
565        let value = iter.next_or_err()?;
566        iter.next_separator_eq_or_err(')')?;
567        Ok((name, parser(value)?))
568    }
569
570    fn constant_i64_parser(token: Token) -> Result<i64, Error> {
571        let parsed = token.text().and_then(|s| s.parse().ok());
572        parsed.ok_or_else(|| Error::invalid_value_for_constant(token))
573    }
574
575    fn constant_u64_parser(token: Token) -> Result<u64, Error> {
576        let parsed = token.text().and_then(|s| s.parse().ok());
577        parsed.ok_or_else(|| Error::invalid_value_for_constant(token))
578    }
579}
580
581#[derive(Debug, Clone, PartialOrd, PartialEq, Eq)]
582pub struct ValueReference<T> {
583    pub name: String,
584    pub role: T,
585    pub value: LiteralValue,
586}
587
588#[derive(Debug, Clone, PartialOrd, PartialEq, Eq)]
589pub enum LiteralValue {
590    Boolean(bool),
591    String(String),
592    Integer(i64),
593    OctetString(Vec<u8>),
594    EnumeratedVariant(String, String),
595}
596
597impl LiteralValue {
598    pub fn to_integer(&self) -> Option<i64> {
599        if let LiteralValue::Integer(int) = self {
600            Some(*int)
601        } else {
602            None
603        }
604    }
605}
606
607#[derive(Debug, Default, Clone, PartialOrd, PartialEq, Eq)]
608pub struct Import {
609    pub what: Vec<String>,
610    pub from: String,
611    pub from_oid: Option<ObjectIdentifier>,
612}
613
614#[derive(Debug, Clone, PartialOrd, PartialEq, Eq)]
615pub struct Field<T> {
616    pub name: String,
617    pub role: T,
618}
619
620impl<T: TagProperty> TagProperty for Field<T> {
621    fn tag(&self) -> Option<Tag> {
622        self.role.tag()
623    }
624
625    fn set_tag(&mut self, tag: Tag) {
626        self.role.set_tag(tag)
627    }
628
629    fn reset_tag(&mut self) {
630        self.role.reset_tag()
631    }
632}
633
634impl Field<Asn<Unresolved>> {
635    pub fn try_resolve<
636        R: Resolver<<Resolved as ResolveState>::SizeType>
637            + Resolver<<Resolved as ResolveState>::RangeType>
638            + Resolver<<Resolved as ResolveState>::ConstType>
639            + Resolver<Type<Unresolved>>,
640    >(
641        &self,
642        resolver: &R,
643    ) -> Result<Field<Asn<Resolved>>, ResolveError> {
644        Ok(Field {
645            name: self.name.clone(),
646            role: self.role.try_resolve(resolver)?,
647        })
648    }
649}
650
651#[cfg(test)]
652pub(crate) mod tests {
653    use crate::parser::{Location, Tokenizer};
654
655    use super::*;
656
657    pub(crate) const SIMPLE_INTEGER_STRUCT_ASN: &str = r"
658        SimpleSchema DEFINITIONS AUTOMATIC TAGS ::=
659        BEGIN
660
661        Simple ::= SEQUENCE {
662            small INTEGER(0..255),
663            bigger INTEGER(0..65535),
664            negative INTEGER(-1..255),
665            unlimited INTEGER(0..MAX) OPTIONAL
666        }
667        END
668        ";
669
670    #[test]
671    fn test_simple_asn_sequence_represented_correctly_as_asn_model() {
672        let model = Model::try_from(Tokenizer::default().parse(SIMPLE_INTEGER_STRUCT_ASN))
673            .unwrap()
674            .try_resolve()
675            .unwrap();
676
677        assert_eq!("SimpleSchema", model.name);
678        assert_eq!(true, model.imports.is_empty());
679        assert_eq!(1, model.definitions.len());
680        assert_eq!(
681            Definition(
682                "Simple".into(),
683                Type::sequence_from_fields(vec![
684                    Field {
685                        name: "small".into(),
686                        role: Type::integer_with_range(Range::inclusive(Some(0), Some(255)))
687                            .untagged(),
688                    },
689                    Field {
690                        name: "bigger".into(),
691                        role: Type::integer_with_range(Range::inclusive(Some(0), Some(65535)))
692                            .untagged(),
693                    },
694                    Field {
695                        name: "negative".into(),
696                        role: Type::integer_with_range(Range::inclusive(Some(-1), Some(255)))
697                            .untagged(),
698                    },
699                    Field {
700                        name: "unlimited".into(),
701                        role: Type::unconstrained_integer().optional().untagged(),
702                    }
703                ])
704                .untagged(),
705            ),
706            model.definitions[0]
707        );
708    }
709
710    pub(crate) const INLINE_ASN_WITH_ENUM: &str = r"
711        SimpleSchema DEFINITIONS AUTOMATIC TAGS ::=
712        BEGIN
713
714        Woah ::= SEQUENCE {
715            decision ENUMERATED {
716                ABORT,
717                RETURN,
718                CONFIRM,
719                MAYDAY,
720                THE_CAKE_IS_A_LIE
721            } OPTIONAL
722        }
723        END
724    ";
725
726    #[test]
727    fn test_inline_asn_enumerated_represented_correctly_as_asn_model() {
728        let model = Model::try_from(Tokenizer::default().parse(INLINE_ASN_WITH_ENUM))
729            .unwrap()
730            .try_resolve()
731            .unwrap();
732
733        assert_eq!("SimpleSchema", model.name);
734        assert_eq!(true, model.imports.is_empty());
735        assert_eq!(1, model.definitions.len());
736        assert_eq!(
737            Definition(
738                "Woah".into(),
739                Type::sequence_from_fields(vec![Field {
740                    name: "decision".into(),
741                    role: Type::Enumerated(Enumerated::from_names(
742                        ["ABORT", "RETURN", "CONFIRM", "MAYDAY", "THE_CAKE_IS_A_LIE",].iter()
743                    ))
744                    .optional()
745                    .untagged(),
746                }])
747                .untagged(),
748            ),
749            model.definitions[0]
750        );
751    }
752
753    pub(crate) const INLINE_ASN_WITH_SEQUENCE_OF: &str = r"
754        SimpleSchema DEFINITIONS AUTOMATIC TAGS ::=
755        BEGIN
756
757        Ones ::= SEQUENCE OF INTEGER(0..1)
758
759        NestedOnes ::= SEQUENCE OF SEQUENCE OF INTEGER(0..1)
760
761        Woah ::= SEQUENCE {
762            also-ones SEQUENCE OF INTEGER(0..1),
763            nesteds SEQUENCE OF SEQUENCE OF INTEGER(0..1),
764            optionals SEQUENCE OF SEQUENCE OF INTEGER(0..MAX) OPTIONAL
765        }
766        END
767    ";
768
769    #[test]
770    fn test_inline_asn_sequence_of_represented_correctly_as_asn_model() {
771        let model = Model::try_from(Tokenizer::default().parse(INLINE_ASN_WITH_SEQUENCE_OF))
772            .unwrap()
773            .try_resolve()
774            .unwrap();
775
776        assert_eq!("SimpleSchema", model.name);
777        assert_eq!(true, model.imports.is_empty());
778        assert_eq!(3, model.definitions.len());
779        assert_eq!(
780            Definition(
781                "Ones".into(),
782                Type::SequenceOf(
783                    Box::new(Type::integer_with_range(Range::inclusive(Some(0), Some(1)))),
784                    Size::Any,
785                )
786                .untagged(),
787            ),
788            model.definitions[0]
789        );
790        assert_eq!(
791            Definition(
792                "NestedOnes".into(),
793                Type::SequenceOf(
794                    Box::new(Type::SequenceOf(
795                        Box::new(Type::integer_with_range(Range::inclusive(Some(0), Some(1)))),
796                        Size::Any,
797                    )),
798                    Size::Any,
799                )
800                .untagged(),
801            ),
802            model.definitions[1]
803        );
804        assert_eq!(
805            Definition(
806                "Woah".into(),
807                Type::sequence_from_fields(vec![
808                    Field {
809                        name: "also-ones".into(),
810                        role: Type::SequenceOf(
811                            Box::new(Type::integer_with_range(Range::inclusive(Some(0), Some(1)))),
812                            Size::Any,
813                        )
814                        .untagged(),
815                    },
816                    Field {
817                        name: "nesteds".into(),
818                        role: Type::SequenceOf(
819                            Box::new(Type::SequenceOf(
820                                Box::new(Type::integer_with_range(Range::inclusive(
821                                    Some(0),
822                                    Some(1),
823                                ))),
824                                Size::Any,
825                            )),
826                            Size::Any,
827                        )
828                        .untagged(),
829                    },
830                    Field {
831                        name: "optionals".into(),
832                        role: Type::SequenceOf(
833                            Box::new(Type::SequenceOf(
834                                Box::new(Type::unconstrained_integer()),
835                                Size::Any,
836                            )),
837                            Size::Any,
838                        )
839                        .optional()
840                        .untagged(),
841                    },
842                ])
843                .untagged(),
844            ),
845            model.definitions[2]
846        );
847    }
848
849    pub(crate) const INLINE_ASN_WITH_CHOICE: &str = r"
850        SimpleSchema DEFINITIONS AUTOMATIC TAGS ::=
851        BEGIN
852
853        This ::= SEQUENCE OF INTEGER(0..1)
854
855        That ::= SEQUENCE OF SEQUENCE OF INTEGER(0..1)
856
857        Neither ::= ENUMERATED {
858            ABC,
859            DEF
860        }
861
862        Woah ::= SEQUENCE {
863            decision CHOICE {
864                this This,
865                that That,
866                neither Neither
867            }
868        }
869        END
870    ";
871
872    #[test]
873    fn test_inline_asn_choice_represented_correctly_as_asn_model() {
874        let model = Model::try_from(Tokenizer::default().parse(INLINE_ASN_WITH_CHOICE))
875            .unwrap()
876            .try_resolve()
877            .unwrap();
878
879        assert_eq!("SimpleSchema", model.name);
880        assert_eq!(true, model.imports.is_empty());
881        assert_eq!(4, model.definitions.len());
882        assert_eq!(
883            Definition(
884                "This".into(),
885                Type::SequenceOf(
886                    Box::new(Type::integer_with_range(Range::inclusive(Some(0), Some(1)))),
887                    Size::Any,
888                )
889                .untagged(),
890            ),
891            model.definitions[0]
892        );
893        assert_eq!(
894            Definition(
895                "That".into(),
896                Type::SequenceOf(
897                    Box::new(Type::SequenceOf(
898                        Box::new(Type::integer_with_range(Range::inclusive(Some(0), Some(1)))),
899                        Size::Any,
900                    )),
901                    Size::Any,
902                )
903                .untagged(),
904            ),
905            model.definitions[1]
906        );
907        assert_eq!(
908            Definition(
909                "Neither".into(),
910                Type::Enumerated(Enumerated::from_names(["ABC", "DEF"].iter())).untagged(),
911            ),
912            model.definitions[2]
913        );
914        assert_eq!(
915            Definition(
916                "Woah".into(),
917                Type::sequence_from_fields(vec![Field {
918                    name: "decision".into(),
919                    role: Type::choice_from_variants(vec![
920                        ChoiceVariant::name_type("this", Type::TypeReference("This".into(), None)),
921                        ChoiceVariant::name_type("that", Type::TypeReference("That".into(), None)),
922                        ChoiceVariant::name_type(
923                            "neither",
924                            Type::TypeReference("Neither".into(), None)
925                        ),
926                    ])
927                    .untagged(),
928                }])
929                .untagged(),
930            ),
931            model.definitions[3]
932        );
933    }
934
935    pub(crate) const INLINE_ASN_WITH_SEQUENCE: &str = r"
936        SimpleSchema DEFINITIONS AUTOMATIC TAGS ::=
937        BEGIN
938
939        Woah ::= SEQUENCE {
940            complex SEQUENCE {
941                ones INTEGER(0..1),
942                list-ones SEQUENCE OF INTEGER(0..1),
943                optional-ones SEQUENCE OF INTEGER(0..1) OPTIONAL
944            } OPTIONAL
945        }
946        END
947    ";
948
949    #[test]
950    fn test_inline_asn_sequence_represented_correctly_as_asn_model() {
951        let model = Model::try_from(Tokenizer::default().parse(INLINE_ASN_WITH_SEQUENCE))
952            .unwrap()
953            .try_resolve()
954            .unwrap();
955
956        assert_eq!("SimpleSchema", model.name);
957        assert_eq!(true, model.imports.is_empty());
958        assert_eq!(1, model.definitions.len());
959        assert_eq!(
960            Definition(
961                "Woah".into(),
962                Type::sequence_from_fields(vec![Field {
963                    name: "complex".into(),
964                    role: Type::sequence_from_fields(vec![
965                        Field {
966                            name: "ones".into(),
967                            role: Type::integer_with_range(Range::inclusive(Some(0), Some(1)))
968                                .untagged(),
969                        },
970                        Field {
971                            name: "list-ones".into(),
972                            role: Type::SequenceOf(
973                                Box::new(Type::integer_with_range(Range::inclusive(
974                                    Some(0),
975                                    Some(1),
976                                ))),
977                                Size::Any,
978                            )
979                            .untagged(),
980                        },
981                        Field {
982                            name: "optional-ones".into(),
983                            role: Type::SequenceOf(
984                                Box::new(Type::integer_with_range(Range::inclusive(
985                                    Some(0),
986                                    Some(1),
987                                ))),
988                                Size::Any,
989                            )
990                            .optional()
991                            .untagged(),
992                        },
993                    ])
994                    .optional()
995                    .untagged(),
996                }])
997                .untagged(),
998            ),
999            model.definitions[0]
1000        );
1001    }
1002
1003    #[test]
1004    fn test_nice_names() {
1005        let mut model = Model::default();
1006
1007        model.name = "SimpleTest".into();
1008        model.make_names_nice();
1009        assert_eq!("simple_test", model.to_rust().name);
1010
1011        model.name = "SIMPLE_Test".into();
1012        model.make_names_nice();
1013        assert_eq!("simple_test", model.to_rust().name);
1014
1015        model.name = "DRY_Module".into();
1016        model.make_names_nice();
1017        assert_eq!("dry", model.to_rust().name);
1018
1019        model.name = "DRYModule".into();
1020        model.make_names_nice();
1021        assert_eq!("dry", model.to_rust().name);
1022    }
1023
1024    #[test]
1025    pub fn test_integer_type_with_range() {
1026        let model = Model::try_from(Tokenizer::default().parse(
1027            r"
1028            SimpleSchema DEFINITIONS AUTOMATIC TAGS ::=
1029            BEGIN
1030    
1031            SimpleTypeWithRange ::= Integer (0..65535)
1032            
1033            END
1034        ",
1035        ))
1036        .expect("Failed to parse")
1037        .try_resolve()
1038        .expect("Failed to resolve");
1039
1040        assert_eq!("SimpleSchema", &model.name);
1041        assert_eq!(
1042            &[Definition(
1043                "SimpleTypeWithRange".to_string(),
1044                Type::integer_with_range(Range::inclusive(Some(0), Some(65_535))).untagged(),
1045            )][..],
1046            &model.definitions[..]
1047        )
1048    }
1049
1050    #[test]
1051    pub fn test_string_type() {
1052        let model = Model::try_from(Tokenizer::default().parse(
1053            r"
1054            SimpleSchema DEFINITIONS AUTOMATIC TAGS ::=
1055            BEGIN
1056    
1057            SimpleStringType ::= UTF8String
1058            
1059            END
1060        ",
1061        ))
1062        .expect("Failed to parse")
1063        .try_resolve()
1064        .expect("Failed to resolve");
1065
1066        assert_eq!("SimpleSchema", &model.name);
1067        assert_eq!(
1068            &[Definition(
1069                "SimpleStringType".to_string(),
1070                Type::unconstrained_utf8string().untagged(),
1071            )][..],
1072            &model.definitions[..]
1073        )
1074    }
1075
1076    #[test]
1077    pub fn test_enumerated_advanced() {
1078        let model = Model::try_from(Tokenizer::default().parse(
1079            r"SimpleSchema DEFINITIONS AUTOMATIC TAGS ::=
1080            BEGIN
1081    
1082            Basic ::= ENUMERATED {
1083                abc,
1084                def
1085            }
1086    
1087            WithExplicitNumber ::= ENUMERATED {
1088                abc(1),
1089                def(9)
1090            }
1091            
1092            WithExplicitNumberAndDefaultMark ::= ENUMERATED {
1093                abc(4),
1094                def(7),
1095                ...
1096            }
1097            
1098            WithExplicitNumberAndDefaultMarkV2 ::= ENUMERATED {
1099                abc(8),
1100                def(1),
1101                ...,
1102                v2(11)
1103            }
1104            
1105            END
1106        ",
1107        ))
1108        .expect("Failed to parse")
1109        .try_resolve()
1110        .expect("Failed to resolve");
1111
1112        assert_eq!("SimpleSchema", &model.name);
1113        assert_eq!(
1114            &[
1115                Definition(
1116                    "Basic".to_string(),
1117                    Type::Enumerated(Enumerated::from_names(["abc", "def"].iter())).untagged(),
1118                ),
1119                Definition(
1120                    "WithExplicitNumber".to_string(),
1121                    Type::Enumerated(Enumerated::from(vec![
1122                        EnumeratedVariant::from_name_number("abc", 1),
1123                        EnumeratedVariant::from_name_number("def", 9)
1124                    ]))
1125                    .untagged(),
1126                ),
1127                Definition(
1128                    "WithExplicitNumberAndDefaultMark".to_string(),
1129                    Type::Enumerated(
1130                        Enumerated::from(vec![
1131                            EnumeratedVariant::from_name_number("abc", 4),
1132                            EnumeratedVariant::from_name_number("def", 7),
1133                        ],)
1134                        .with_extension_after(1)
1135                    )
1136                    .untagged(),
1137                ),
1138                Definition(
1139                    "WithExplicitNumberAndDefaultMarkV2".to_string(),
1140                    Type::Enumerated(
1141                        Enumerated::from(vec![
1142                            EnumeratedVariant::from_name_number("abc", 8),
1143                            EnumeratedVariant::from_name_number("def", 1),
1144                            EnumeratedVariant::from_name_number("v2", 11)
1145                        ],)
1146                        .with_extension_after(1)
1147                    )
1148                    .untagged(),
1149                )
1150            ][..],
1151            &model.definitions[..]
1152        )
1153    }
1154
1155    #[test]
1156    pub fn test_enumerated_tags() {
1157        let model = Model::try_from(Tokenizer::default().parse(
1158            r"SimpleSchema DEFINITIONS AUTOMATIC TAGS ::=
1159            BEGIN
1160    
1161            Universal ::= [UNIVERSAL 2] ENUMERATED {
1162                abc,
1163                def
1164            }
1165    
1166            Application ::= [APPLICATION 7] ENUMERATED {
1167                abc,
1168                def
1169            }
1170            
1171            Private ::= [PRIVATE 11] ENUMERATED {
1172                abc,
1173                def
1174            }
1175            
1176            ContextSpecific ::= [8] ENUMERATED {
1177                abc,
1178                def
1179            }
1180            
1181            END
1182        ",
1183        ))
1184        .expect("Failed to parse")
1185        .try_resolve()
1186        .expect("Failed to resolve");
1187
1188        assert_eq!("SimpleSchema", &model.name);
1189        assert_eq!(
1190            &[
1191                Definition(
1192                    "Universal".to_string(),
1193                    Type::Enumerated(Enumerated::from_names(["abc", "def"].iter()))
1194                        .tagged(Tag::Universal(2)),
1195                ),
1196                Definition(
1197                    "Application".to_string(),
1198                    Type::Enumerated(Enumerated::from_names(["abc", "def"].iter()))
1199                        .tagged(Tag::Application(7)),
1200                ),
1201                Definition(
1202                    "Private".to_string(),
1203                    Type::Enumerated(Enumerated::from_names(["abc", "def"].iter()))
1204                        .tagged(Tag::Private(11)),
1205                ),
1206                Definition(
1207                    "ContextSpecific".to_string(),
1208                    Type::Enumerated(Enumerated::from_names(["abc", "def"].iter()))
1209                        .tagged(Tag::ContextSpecific(8)),
1210                ),
1211            ][..],
1212            &model.definitions[..]
1213        )
1214    }
1215
1216    #[test]
1217    pub fn test_parsing_tags_in_front_of_definitions_does_not_fail() {
1218        let model = Model::try_from(Tokenizer::default().parse(
1219            r"SimpleSchema DEFINITIONS AUTOMATIC TAGS ::=
1220            BEGIN
1221    
1222            Universal ::= [UNIVERSAL 2] SEQUENCE {
1223                abc [1] INTEGER(0..MAX),
1224                def [2] INTEGER(0..255)
1225            }
1226    
1227            Application ::= [APPLICATION 7] SEQUENCE OF UTF8String
1228            
1229            Private ::= [PRIVATE 11] ENUMERATED {
1230                abc,
1231                def
1232            }
1233            
1234            ContextSpecific ::= [8] INTEGER(0..MAX)
1235            
1236            END
1237        ",
1238        ))
1239        .expect("Failed to parse")
1240        .try_resolve()
1241        .expect("Failed to resolve");
1242
1243        assert_eq!("SimpleSchema", &model.name);
1244        assert_eq!(
1245            &[
1246                Definition(
1247                    "Universal".to_string(),
1248                    Type::sequence_from_fields(vec![
1249                        Field {
1250                            name: "abc".to_string(),
1251                            role: Type::unconstrained_integer().tagged(Tag::ContextSpecific(1)),
1252                        },
1253                        Field {
1254                            name: "def".to_string(),
1255                            role: Type::integer_with_range(Range::inclusive(Some(0), Some(255)))
1256                                .tagged(Tag::ContextSpecific(2)),
1257                        }
1258                    ])
1259                    .tagged(Tag::Universal(2)),
1260                ),
1261                Definition(
1262                    "Application".to_string(),
1263                    Type::SequenceOf(Box::new(Type::unconstrained_utf8string()), Size::Any)
1264                        .tagged(Tag::Application(7)),
1265                ),
1266                Definition(
1267                    "Private".to_string(),
1268                    Type::Enumerated(Enumerated::from_names(["abc", "def"].iter()))
1269                        .tagged(Tag::Private(11)),
1270                ),
1271                Definition(
1272                    "ContextSpecific".to_string(),
1273                    Type::unconstrained_integer().tagged(Tag::ContextSpecific(8)),
1274                ),
1275            ][..],
1276            &model.definitions[..]
1277        )
1278    }
1279
1280    #[test]
1281    pub fn test_parsing_of_extensible_choices() {
1282        let model = Model::try_from(Tokenizer::default().parse(
1283            r"SimpleSchema DEFINITIONS AUTOMATIC TAGS ::=
1284            BEGIN
1285    
1286            WithoutMarker ::= CHOICE {
1287                abc UTF8String,
1288                def UTF8String
1289            }
1290            
1291            WithoutExtensionPresent ::= CHOICE {
1292                abc UTF8String,
1293                def UTF8String,
1294                ...
1295            }
1296    
1297            WithExtensionPresent ::= CHOICE {
1298                abc UTF8String,
1299                def UTF8String,
1300                ...,
1301                ghi UTF8String
1302            }
1303            
1304            END
1305        ",
1306        ))
1307        .expect("Failed to parse")
1308        .try_resolve()
1309        .expect("Failed to resolve");
1310
1311        assert_eq!("SimpleSchema", model.name.as_str());
1312        assert_eq!(
1313            &[
1314                Definition::new(
1315                    "WithoutMarker",
1316                    Type::Choice(Choice::from(vec![
1317                        ChoiceVariant::name_type("abc", Type::unconstrained_utf8string()),
1318                        ChoiceVariant::name_type("def", Type::unconstrained_utf8string()),
1319                    ]))
1320                    .untagged(),
1321                ),
1322                Definition::new(
1323                    "WithoutExtensionPresent",
1324                    Type::Choice(
1325                        Choice::from(vec![
1326                            ChoiceVariant::name_type("abc", Type::unconstrained_utf8string()),
1327                            ChoiceVariant::name_type("def", Type::unconstrained_utf8string()),
1328                        ])
1329                        .with_extension_after(1),
1330                    )
1331                    .untagged(),
1332                ),
1333                Definition::new(
1334                    "WithExtensionPresent",
1335                    Type::Choice(
1336                        Choice::from(vec![
1337                            ChoiceVariant::name_type("abc", Type::unconstrained_utf8string()),
1338                            ChoiceVariant::name_type("def", Type::unconstrained_utf8string()),
1339                            ChoiceVariant::name_type("ghi", Type::unconstrained_utf8string()),
1340                        ])
1341                        .with_extension_after(1),
1342                    )
1343                    .untagged(),
1344                )
1345            ][..],
1346            &model.definitions[..]
1347        )
1348    }
1349
1350    #[test]
1351    pub fn test_parsing_of_extensible_with_markers_at_invalid_locations() {
1352        assert_eq!(
1353            Error::invalid_position_for_extension_marker(Token::Separator(
1354                Location::at(4, 21),
1355                '.',
1356            )),
1357            Model::try_from(Tokenizer::default().parse(
1358                r"SimpleSchema DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1359
1360                Invalid ::= CHOICE {
1361                    ...
1362                }
1363                
1364                END",
1365            ))
1366            .expect_err("Parsed invalid definition")
1367        );
1368
1369        assert_eq!(
1370            Error::invalid_position_for_extension_marker(Token::Separator(
1371                Location::at(4, 21),
1372                '.',
1373            )),
1374            Model::try_from(Tokenizer::default().parse(
1375                r"SimpleSchema DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1376    
1377                Invalid ::= CHOICE {
1378                    ...,
1379                    abc UTF8String
1380                }
1381                
1382                END",
1383            ))
1384            .expect_err("Parsed invalid definition")
1385        );
1386
1387        assert_eq!(
1388            Error::invalid_position_for_extension_marker(Token::Separator(
1389                Location::at(4, 21),
1390                '.',
1391            )),
1392            Model::try_from(Tokenizer::default().parse(
1393                r"SimpleSchema DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1394    
1395                Invalid ::= ENUMERATED {
1396                    ...
1397                }
1398                
1399                END",
1400            ))
1401            .expect_err("Parsed invalid definition")
1402        );
1403
1404        assert_eq!(
1405            Error::invalid_position_for_extension_marker(Token::Separator(
1406                Location::at(4, 21),
1407                '.',
1408            )),
1409            Model::try_from(Tokenizer::default().parse(
1410                r"SimpleSchema DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1411
1412                Invalid ::= ENUMERATED {
1413                    ...,
1414                    abc(77)
1415                }
1416                
1417                END",
1418            ))
1419            .expect_err("Parsed invalid definition")
1420        );
1421    }
1422
1423    #[test]
1424    pub fn test_parsing_module_definition_oid() {
1425        let model = Model::try_from(Tokenizer::default().parse(
1426            "SomeName { very(1) clever oid(4) 1337 } DEFINITIONS AUTOMATIC TAGS ::= BEGIN END",
1427        ))
1428        .expect("Failed to load model");
1429        assert_eq!(
1430            ObjectIdentifier(vec![
1431                ObjectIdentifierComponent::NameAndNumberForm("very".to_string(), 1),
1432                ObjectIdentifierComponent::NameForm("clever".to_string()),
1433                ObjectIdentifierComponent::NameAndNumberForm("oid".to_string(), 4),
1434                ObjectIdentifierComponent::NumberForm(1337),
1435            ]),
1436            model.oid.expect("ObjectIdentifier is missing")
1437        )
1438    }
1439
1440    #[test]
1441    pub fn test_parsing_module_definition_oid_in_import_from() {
1442        let model = Model::try_from(Tokenizer::default().parse(
1443            r"SomeName DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1444                IMPORTS
1445                    SomeData, OtherDef, Wowz
1446                FROM TheOtherModule { very(1) official(2) oid 42 };
1447                END",
1448        ))
1449        .expect("Failed to load model");
1450        assert_eq!(
1451            &ObjectIdentifier(vec![
1452                ObjectIdentifierComponent::NameAndNumberForm("very".to_string(), 1),
1453                ObjectIdentifierComponent::NameAndNumberForm("official".to_string(), 2),
1454                ObjectIdentifierComponent::NameForm("oid".to_string()),
1455                ObjectIdentifierComponent::NumberForm(42),
1456            ]),
1457            model.imports[0]
1458                .from_oid
1459                .as_ref()
1460                .expect("ObjectIdentifier is missing")
1461        )
1462    }
1463
1464    #[test]
1465    pub fn test_parsing_module_definition_with_integer_constant() {
1466        let model = Model::try_from(Tokenizer::default().parse(
1467            r"SomeName DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1468                TheGreatStruct ::= SEQUENCE {
1469                    inline     INTEGER { ab(1), cd(2), ef(3) },
1470                    eff-u8     INTEGER { gh(1), ij(4), kl(9) } (0..255),
1471                    tagged [7] INTEGER { mn(5), op(4), qr(9) } (0..255) 
1472                }
1473                
1474                SeAlias ::= INTEGER { wow(1), much(2), great(3) }
1475                
1476                OhAlias ::= [APPLICATION 9] INTEGER { oh(1), lul(2) } (0..255)
1477                END",
1478        ))
1479        .expect("Failed to load model")
1480        .try_resolve()
1481        .expect("Failed to resolve");
1482        assert_eq!(
1483            vec![
1484                Definition(
1485                    "TheGreatStruct".to_string(),
1486                    Type::sequence_from_fields(vec![
1487                        Field {
1488                            name: "inline".to_string(),
1489                            role: Type::Integer(Integer {
1490                                range: Range::none(),
1491                                constants: vec![
1492                                    ("ab".to_string(), 1),
1493                                    ("cd".to_string(), 2),
1494                                    ("ef".to_string(), 3)
1495                                ],
1496                            })
1497                            .untagged(),
1498                        },
1499                        Field {
1500                            name: "eff-u8".to_string(),
1501                            role: Type::Integer(Integer {
1502                                range: Range::inclusive(Some(0), Some(255)),
1503                                constants: vec![
1504                                    ("gh".to_string(), 1),
1505                                    ("ij".to_string(), 4),
1506                                    ("kl".to_string(), 9)
1507                                ],
1508                            })
1509                            .untagged(),
1510                        },
1511                        Field {
1512                            name: "tagged".to_string(),
1513                            role: Type::Integer(Integer {
1514                                range: Range::inclusive(Some(0), Some(255)),
1515                                constants: vec![
1516                                    ("mn".to_string(), 5),
1517                                    ("op".to_string(), 4),
1518                                    ("qr".to_string(), 9)
1519                                ],
1520                            })
1521                            .tagged(Tag::ContextSpecific(7)),
1522                        },
1523                    ])
1524                    .untagged(),
1525                ),
1526                Definition(
1527                    "SeAlias".to_string(),
1528                    Type::Integer(Integer {
1529                        range: Range::none(),
1530                        constants: vec![
1531                            ("wow".to_string(), 1),
1532                            ("much".to_string(), 2),
1533                            ("great".to_string(), 3),
1534                        ],
1535                    })
1536                    .untagged(),
1537                ),
1538                Definition(
1539                    "OhAlias".to_string(),
1540                    Type::Integer(Integer {
1541                        range: Range::inclusive(Some(0), Some(255)),
1542                        constants: vec![("oh".to_string(), 1), ("lul".to_string(), 2),],
1543                    })
1544                    .tagged(Tag::Application(9)),
1545                )
1546            ],
1547            model.definitions
1548        )
1549    }
1550
1551    #[test]
1552    pub fn test_parsing_module_definition_with_extensible_integer() {
1553        let model = Model::try_from(Tokenizer::default().parse(
1554            r"SomeName DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1555                RangedOptional ::= SEQUENCE {
1556                    value     INTEGER { gh(1), ij(4), kl(9) } (0..255,...) OPTIONAL
1557                }
1558                
1559                END",
1560        ))
1561        .expect("Failed to load model")
1562        .try_resolve()
1563        .expect("Failed to resolve");
1564        assert_eq!(
1565            vec![Definition(
1566                "RangedOptional".to_string(),
1567                Type::sequence_from_fields(vec![Field {
1568                    name: "value".to_string(),
1569                    role: Type::Integer(Integer {
1570                        range: Range::inclusive(Some(0), Some(255)).with_extensible(true),
1571                        constants: vec![
1572                            ("gh".to_string(), 1),
1573                            ("ij".to_string(), 4),
1574                            ("kl".to_string(), 9)
1575                        ],
1576                    })
1577                    .optional()
1578                    .untagged(),
1579                }])
1580                .untagged(),
1581            )],
1582            model.definitions
1583        )
1584    }
1585
1586    #[test]
1587    pub fn test_resolve_tag() {
1588        let external = Model::try_from(Tokenizer::default().parse(
1589            r"ExternalModule DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1590            External ::= [APPLICATION 1] INTEGER
1591            END
1592            ",
1593        ))
1594        .expect("Failed to parse module")
1595        .try_resolve()
1596        .expect("Failed to resolve");
1597        let model = Model::try_from(Tokenizer::default().parse(
1598            r"InternalModul DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1599                IMPORTS
1600                    External
1601                FROM ExternalModule;
1602                
1603                Implicit ::= SEQUENCE {
1604                    implicit     INTEGER OPTIONAL,
1605                    explicit [4] INTEGER 
1606                }
1607                
1608                Explicit ::= [APPLICATION 8] ENUMERATED {
1609                    abc,
1610                    def
1611                }
1612                
1613                Composed ::= CHOICE {
1614                    first-but-greater-tag-value [APPLICATION 99] INTEGER,
1615                    second-but-indirect-lower-tag Explicit
1616                }
1617                
1618                ExternallyComposed ::= CHOICE {
1619                    internal Explicit,
1620                    extenral External
1621                }
1622                
1623                END",
1624        ))
1625        .expect("Failed to load model")
1626        .try_resolve()
1627        .expect("Failed to resolve");
1628        let rust = model.to_rust_with_scope(&[&external]);
1629
1630        if let Rust::Struct {
1631            ordering: _,
1632            fields,
1633            tag,
1634            extension_after: _,
1635        } = rust.definitions[0].value()
1636        {
1637            assert_eq!("Implicit", rust.definitions[0].0.as_str());
1638            assert_eq!(None, *tag); // None because default
1639            assert_eq!(None, fields[0].tag()); // None because default
1640            assert_eq!(Some(Tag::ContextSpecific(4)), fields[1].tag()); // explicitly set
1641        } else {
1642            panic!("Expected Rust::Struct for ASN.1 SEQUENCE");
1643        }
1644
1645        if let Rust::Enum(plain) = rust.definitions[1].value() {
1646            assert_eq!("Explicit", rust.definitions[1].0.as_str());
1647            assert_eq!(2, plain.len());
1648            assert_eq!(Some(Tag::Application(8)), plain.tag()); // explicitly set
1649        } else {
1650            panic!("Expected Rust::Enum for ASN.1 ENUMERATED")
1651        }
1652
1653        if let Rust::DataEnum(data) = rust.definitions[2].value() {
1654            assert_eq!("Composed", rust.definitions[2].0.as_str());
1655            assert_eq!(2, data.len());
1656            assert_eq!(None, data.tag()); // None because no tag explicitly set
1657        } else {
1658            panic!("Expected Rust::DataEnum for ASN.1 CHOICE")
1659        }
1660
1661        if let Rust::DataEnum(data) = rust.definitions[3].value() {
1662            assert_eq!("ExternallyComposed", rust.definitions[3].0.as_str());
1663            assert_eq!(2, data.len());
1664            assert_eq!(None, data.tag()); // None because no tag explicitly set
1665        } else {
1666            panic!("Expected Rust::DataEnum for ASN.1 CHOICE")
1667        }
1668
1669        assert_eq!(4, rust.definitions.len());
1670    }
1671
1672    #[test]
1673    pub fn test_value_reference_boolean() {
1674        let model = Model::try_from(Tokenizer::default().parse(
1675            r"SomeName DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1676                
1677                somethingYes BOOLEAN ::= TRUE
1678                somethingNo BOOLEAN ::= FALSE
1679                
1680                END",
1681        ))
1682        .expect("Failed to load model");
1683        assert_eq!(
1684            &[
1685                ValueReference {
1686                    name: "somethingYes".to_string(),
1687                    role: Type::Boolean.untagged(),
1688                    value: LiteralValue::Boolean(true)
1689                },
1690                ValueReference {
1691                    name: "somethingNo".to_string(),
1692                    role: Type::Boolean.untagged(),
1693                    value: LiteralValue::Boolean(false)
1694                },
1695            ],
1696            &model.value_references[..]
1697        )
1698    }
1699
1700    #[test]
1701    pub fn test_value_reference_integer() {
1702        let model = Model::try_from(Tokenizer::default().parse(
1703            r"SomeName DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1704                
1705                maxSomethingSomething INTEGER ::= 1337
1706                
1707                END",
1708        ))
1709        .expect("Failed to load model");
1710        assert_eq!(
1711            ValueReference {
1712                name: "maxSomethingSomething".to_string(),
1713                role: Type::Integer(Integer {
1714                    range: Default::default(),
1715                    constants: Vec::default()
1716                })
1717                .untagged(),
1718                value: LiteralValue::Integer(1337)
1719            },
1720            model.value_references[0]
1721        )
1722    }
1723
1724    #[test]
1725    pub fn test_value_reference_bit_string() {
1726        let model = Model::try_from(Tokenizer::default().parse(
1727            r"SomeName DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1728                
1729                magicFlags BIT STRING ::= 'a711'H
1730                
1731                magicFlags2 BIT STRING ::= '1001'B
1732                
1733                END",
1734        ))
1735        .expect("Failed to load model");
1736        assert_eq!(
1737            ValueReference {
1738                name: "magicFlags".to_string(),
1739                role: Type::BitString(BitString {
1740                    size: Size::Any,
1741                    constants: Vec::default()
1742                })
1743                .untagged(),
1744                value: LiteralValue::OctetString(vec![0xa7, 0x11])
1745            },
1746            model.value_references[0]
1747        );
1748        assert_eq!(
1749            ValueReference {
1750                name: "magicFlags2".to_string(),
1751                role: Type::BitString(BitString {
1752                    size: Size::Any,
1753                    constants: Vec::default()
1754                })
1755                .untagged(),
1756                value: LiteralValue::OctetString(vec![0x09])
1757            },
1758            model.value_references[1]
1759        );
1760    }
1761
1762    #[test]
1763    pub fn test_value_reference_octet_string() {
1764        let model = Model::try_from(Tokenizer::default().parse(
1765            r"SomeName DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1766
1767                answers OCTET STRING ::= '42'h
1768
1769                END",
1770        ))
1771        .expect("Failed to load model");
1772        assert_eq!(
1773            ValueReference {
1774                name: "answers".to_string(),
1775                role: Type::OctetString(Size::Any).untagged(),
1776                value: LiteralValue::OctetString(vec![0x42])
1777            },
1778            model.value_references[0]
1779        )
1780    }
1781
1782    #[test]
1783    pub fn test_value_reference_string() {
1784        let model = Model::try_from(Tokenizer::default().parse(
1785            r#"SomeName DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1786
1787                utf8 UTF8String ::= "häw äre yöu .. .. doing"
1788                ia5 IA5String ::= "how are you"
1789
1790                END"#,
1791        ))
1792        .expect("Failed to load model");
1793        assert_eq!(
1794            &[
1795                ValueReference {
1796                    name: "utf8".to_string(),
1797                    role: Type::String(Size::Any, Charset::Utf8).untagged(),
1798                    value: LiteralValue::String("häw äre yöu .. .. doing".to_string())
1799                },
1800                ValueReference {
1801                    name: "ia5".to_string(),
1802                    role: Type::String(Size::Any, Charset::Ia5).untagged(),
1803                    value: LiteralValue::String("how are you".to_string())
1804                }
1805            ],
1806            &model.value_references[..]
1807        );
1808    }
1809
1810    #[test]
1811    pub fn test_value_reference_in_size() {
1812        let model = Model::try_from(Tokenizer::default().parse(
1813            r#"SomeName DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1814
1815                se_min INTEGER ::= 42
1816                se_max INTEGER ::= 1337
1817                
1818                seq-fix         ::= SEQUENCE (SIZE(se_min)) OF INTEGER
1819                seq-min-max     ::= SEQUENCE (SIZE(se_min..se_max)) OF INTEGER
1820                seq-min-max-ext ::= SEQUENCE (SIZE(se_min..se_max,...)) OF INTEGER
1821                
1822                mixed-min-max     ::= SEQUENCE (SIZE(se_min..4711)) OF INTEGER
1823                mixed-min-max-ext ::= SEQUENCE (SIZE(420..se_max,...)) OF INTEGER
1824
1825                END"#,
1826        ))
1827        .expect("Failed to load model")
1828        .try_resolve()
1829        .expect("Failed to resolve");
1830        assert_eq!(
1831            &[
1832                Definition(
1833                    "seq-fix".to_string(),
1834                    Type::<Resolved>::SequenceOf(
1835                        Box::new(Type::Integer(Integer::default())),
1836                        Size::Fix(42_usize, false)
1837                    )
1838                    .untagged()
1839                ),
1840                Definition(
1841                    "seq-min-max".to_string(),
1842                    Type::<Resolved>::SequenceOf(
1843                        Box::new(Type::Integer(Integer::default())),
1844                        Size::Range(42_usize, 1337, false)
1845                    )
1846                    .untagged()
1847                ),
1848                Definition(
1849                    "seq-min-max-ext".to_string(),
1850                    Type::<Resolved>::SequenceOf(
1851                        Box::new(Type::Integer(Integer::default())),
1852                        Size::Range(42_usize, 1337, true)
1853                    )
1854                    .untagged()
1855                ),
1856                Definition(
1857                    "mixed-min-max".to_string(),
1858                    Type::<Resolved>::SequenceOf(
1859                        Box::new(Type::Integer(Integer::default())),
1860                        Size::Range(42_usize, 4711, false)
1861                    )
1862                    .untagged()
1863                ),
1864                Definition(
1865                    "mixed-min-max-ext".to_string(),
1866                    Type::<Resolved>::SequenceOf(
1867                        Box::new(Type::Integer(Integer::default())),
1868                        Size::Range(420_usize, 1337, true)
1869                    )
1870                    .untagged()
1871                )
1872            ],
1873            &model.definitions[..]
1874        );
1875    }
1876
1877    #[test]
1878    pub fn test_value_reference_in_range() {
1879        let model = Model::try_from(Tokenizer::default().parse(
1880            r#"SomeName DEFINITIONS AUTOMATIC TAGS ::= BEGIN
1881
1882                se_min INTEGER ::= 42
1883                se_max INTEGER ::= 1337
1884                
1885                seq-min-max     ::= INTEGER(se_min..se_max)
1886                seq-min-max-ext ::= INTEGER(se_min..se_max,...)
1887                
1888                mixed-min-max     ::= INTEGER(se_min..4711)
1889                mixed-min-max-ext ::= INTEGER(-42069..se_max,...)
1890
1891                END"#,
1892        ))
1893        .expect("Failed to load model")
1894        .try_resolve()
1895        .expect("Failed to resolve");
1896        assert_eq!(
1897            &[
1898                Definition(
1899                    "seq-min-max".to_string(),
1900                    Type::<Resolved>::Integer(Integer::with_range(Range::inclusive(
1901                        Some(42),
1902                        Some(1337)
1903                    )))
1904                    .untagged()
1905                ),
1906                Definition(
1907                    "seq-min-max-ext".to_string(),
1908                    Type::<Resolved>::Integer(Integer::with_range(
1909                        Range::inclusive(Some(42), Some(1337)).with_extensible(true)
1910                    ))
1911                    .untagged()
1912                ),
1913                Definition(
1914                    "mixed-min-max".to_string(),
1915                    Type::<Resolved>::Integer(Integer::with_range(Range::inclusive(
1916                        Some(42),
1917                        Some(4711)
1918                    )))
1919                    .untagged()
1920                ),
1921                Definition(
1922                    "mixed-min-max-ext".to_string(),
1923                    Type::<Resolved>::Integer(Integer::with_range(
1924                        Range::inclusive(Some(-42069), Some(1337)).with_extensible(true)
1925                    ))
1926                    .untagged()
1927                )
1928            ],
1929            &model.definitions[..]
1930        );
1931    }
1932}