rasn_compiler/intermediate/
mod.rs

1//! The `intermediate` module provides an intermediate representation for ASN.1 notation.
2//! It includes constants for the various ASN.1 keywords and types to represent the
3//! single ASN.1 data elements in an intermediate representation from which the
4//! generator module produces bindings.
5//! The intermediate representation aims to preserve as much information as possible
6//! from the original specification, even though some of that information might not actually
7//! be relevant for decoding and encoding in any of the common encoding rules
8//! (inner type constraints are such an example).
9pub mod constraints;
10pub mod encoding_rules;
11pub mod error;
12pub mod information_object;
13pub mod macros;
14pub mod parameterization;
15pub mod types;
16pub mod utils;
17
18use std::{borrow::Cow, cell::RefCell, collections::BTreeMap, ops::Add, rc::Rc};
19
20use crate::common::INTERNAL_IO_FIELD_REF_TYPE_NAME_PREFIX;
21use constraints::Constraint;
22use error::{GrammarError, GrammarErrorType};
23use information_object::{
24    ObjectClassAssignment, ObjectClassFieldType, ToplevelInformationDefinition,
25};
26#[cfg(test)]
27use internal_macros::EnumDebug;
28use macros::ToplevelMacroDefinition;
29use parameterization::Parameterization;
30use quote::{quote, ToTokens, TokenStreamExt};
31use types::*;
32
33#[cfg(doc)]
34use crate::Backend;
35
36// Comment tokens
37pub const BLOCK_COMMENT_START: &str = "/*";
38pub const BLOCK_COMMENT_END: &str = "*/";
39pub const LINE_COMMENT: &str = "--";
40
41// Bracket tokens
42pub const LEFT_PARENTHESIS: char = '(';
43pub const RIGHT_PARENTHESIS: char = ')';
44pub const LEFT_BRACKET: char = '[';
45pub const RIGHT_BRACKET: char = ']';
46pub const LEFT_BRACE: char = '{';
47pub const RIGHT_BRACE: char = '}';
48pub const LEFT_CHEVRON: char = '<';
49pub const RIGHT_CHEVRON: char = '>';
50
51// Type tokens
52pub const NULL: &str = "NULL";
53pub const BOOLEAN: &str = "BOOLEAN";
54pub const INTEGER: &str = "INTEGER";
55pub const REAL: &str = "REAL";
56pub const BIT_STRING: &str = "BIT STRING";
57pub const OCTET_STRING: &str = "OCTET STRING";
58pub const IA5_STRING: &str = "IA5String";
59pub const UTF8_STRING: &str = "UTF8String";
60pub const NUMERIC_STRING: &str = "NumericString";
61pub const VISIBLE_STRING: &str = "VisibleString";
62pub const TELETEX_STRING: &str = "TeletexString";
63pub const T61_STRING: &str = "T61String";
64pub const VIDEOTEX_STRING: &str = "VideotexString";
65pub const GRAPHIC_STRING: &str = "GraphicString";
66pub const GENERAL_STRING: &str = "GeneralString";
67pub const UNIVERSAL_STRING: &str = "UniversalString";
68pub const BMP_STRING: &str = "BMPString";
69pub const PRINTABLE_STRING: &str = "PrintableString";
70pub const GENERALIZED_TIME: &str = "GeneralizedTime";
71pub const UTC_TIME: &str = "UTCTime";
72pub const ENUMERATED: &str = "ENUMERATED";
73pub const CHOICE: &str = "CHOICE";
74pub const SEQUENCE: &str = "SEQUENCE";
75pub const SEQUENCE_OF: &str = "SEQUENCE OF";
76pub const SET_OF: &str = "SET OF";
77pub const OF: &str = "OF";
78pub const ALL: &str = "ALL";
79pub const SET: &str = "SET";
80pub const OBJECT_IDENTIFIER: &str = "OBJECT IDENTIFIER";
81pub const COMPONENTS_OF: &str = "COMPONENTS OF";
82pub const ANY: &str = "ANY";
83pub const DEFINED: &str = "DEFINED";
84pub const BY: &str = "BY";
85
86// Tagging tokens
87pub const UNIVERSAL: &str = "UNIVERSAL";
88pub const PRIVATE: &str = "PRIVATE";
89pub const APPLICATION: &str = "APPLICATION";
90
91// Value tokens
92pub const TRUE: &str = "TRUE";
93pub const FALSE: &str = "FALSE";
94
95// Header tokens
96pub const BEGIN: &str = "BEGIN";
97pub const END: &str = "END";
98pub const DEFINITIONS: &str = "DEFINITIONS";
99pub const AUTOMATIC: &str = "AUTOMATIC";
100pub const EXPLICIT: &str = "EXPLICIT";
101pub const IMPLICIT: &str = "IMPLICIT";
102pub const IMPORTS: &str = "IMPORTS";
103pub const EXPORTS: &str = "EXPORTS";
104pub const FROM: &str = "FROM";
105pub const INSTRUCTIONS: &str = "INSTRUCTIONS";
106pub const TAGS: &str = "TAGS";
107pub const EXTENSIBILITY_IMPLIED: &str = "EXTENSIBILITY IMPLIED";
108pub const WITH_SUCCESSORS: &str = "WITH SUCCESSORS";
109pub const WITH_DESCENDANTS: &str = "WITH DESCENDANTS";
110pub const SEMICOLON: char = ';';
111
112// Information Object Class tokens
113pub const AMPERSAND: char = '&';
114pub const CLASS: &str = "CLASS";
115pub const UNIQUE: &str = "UNIQUE";
116pub const WITH_SYNTAX: &str = "WITH SYNTAX";
117pub const AT: char = '@';
118pub const DOT: char = '.';
119
120// Subtyping tokens
121pub const SIZE: &str = "SIZE";
122pub const CONSTRAINED_BY: &str = "CONSTRAINED BY";
123pub const PATTERN: &str = "PATTERN";
124pub const DEFAULT: &str = "DEFAULT";
125pub const CONTAINING: &str = "CONTAINING";
126pub const ENCODED_BY: &str = "ENCODED BY";
127pub const OPTIONAL: &str = "OPTIONAL";
128pub const WITH_COMPONENTS: &str = "WITH COMPONENTS";
129pub const WITH_COMPONENT: &str = "WITH COMPONENT";
130pub const UNION: &str = "UNION";
131pub const EXCEPT: &str = "EXCEPT";
132pub const INTERSECTION: &str = "INTERSECTION";
133pub const ABSENT: &str = "ABSENT";
134pub const PRESENT: &str = "PRESENT";
135pub const INCLUDES: &str = "INCLUDES";
136pub const MIN: &str = "MIN";
137pub const MAX: &str = "MAX";
138pub const LESS_THAN: char = '<';
139pub const GREATER_THAN: char = '>';
140pub const PIPE: &str = "|";
141pub const CARET: &str = "^";
142
143// Macro tokens
144pub const MACRO: &str = "MACRO";
145
146pub const ASSIGN: &str = "::=";
147pub const RANGE: &str = "..";
148pub const ELLIPSIS: &str = "...";
149pub const COMMA: char = ',';
150pub const COLON: char = ':';
151pub const SINGLE_QUOTE: char = '\'';
152
153// invalid syntax word tokens
154pub const ABSTRACT_SYNTAX: &str = "ABSTRACT-SYNTAX";
155pub const BIT: &str = "BIT";
156pub const CHARACTER: &str = "CHARACTER";
157pub const DATE: &str = "DATE";
158pub const DATE_TIME: &str = "DATE-TIME";
159pub const DURATION: &str = "DURATION";
160pub const EMBEDDED_PDV: &str = "EMBEDDED PDV";
161pub const EXTERNAL: &str = "EXTERNAL";
162pub const INSTANCE_OF: &str = "INSTANCE OF";
163pub const MINUS_INFINITY: &str = "MINUS-INFINITY";
164pub const NOT_A_NUMBER: &str = "NOT-A-NUMBER";
165pub const OBJECT: &str = "OBJECT";
166pub const OCTET: &str = "OCTET";
167pub const OID_IRI: &str = "OID-IRI";
168pub const PLUS_INFINITY: &str = "PLUS-INFINITY";
169pub const RELATIVE_OID: &str = "RELATIVE-OID";
170pub const RELATIVE_OID_IRI: &str = "RELATIVE-OID-IRI";
171pub const TIME: &str = "TIME";
172pub const TIME_OF_DAY: &str = "TIME-OF-DAY";
173pub const TYPE_IDENTIFIER: &str = "TYPE-IDENTIFIER";
174pub const ENCODING_CONTROL: &str = "ENCODING-CONTROL";
175
176pub const ASN1_KEYWORDS: [&str; 67] = [
177    ABSTRACT_SYNTAX,
178    BIT,
179    CHARACTER,
180    CONTAINING,
181    DATE,
182    DATE_TIME,
183    DURATION,
184    EMBEDDED_PDV,
185    EXTERNAL,
186    INSTANCE_OF,
187    MINUS_INFINITY,
188    NOT_A_NUMBER,
189    OBJECT,
190    OCTET,
191    OID_IRI,
192    PLUS_INFINITY,
193    RELATIVE_OID,
194    RELATIVE_OID_IRI,
195    TIME,
196    TIME_OF_DAY,
197    TYPE_IDENTIFIER,
198    SIZE,
199    DEFAULT,
200    OPTIONAL,
201    WITH_COMPONENTS,
202    WITH_COMPONENT,
203    UNION,
204    EXCEPT,
205    INTERSECTION,
206    ABSENT,
207    PRESENT,
208    INCLUDES,
209    MIN,
210    MAX,
211    CLASS,
212    UNIQUE,
213    WITH_SYNTAX,
214    NULL,
215    BOOLEAN,
216    INTEGER,
217    REAL,
218    ENUMERATED,
219    CHOICE,
220    SEQUENCE,
221    OF,
222    ALL,
223    SET,
224    OBJECT_IDENTIFIER,
225    UNIVERSAL,
226    PRIVATE,
227    APPLICATION,
228    TRUE,
229    FALSE,
230    BEGIN,
231    END,
232    DEFINITIONS,
233    AUTOMATIC,
234    EXPLICIT,
235    IMPLICIT,
236    IMPORTS,
237    FROM,
238    INSTRUCTIONS,
239    TAGS,
240    MACRO,
241    ANY,
242    BY,
243    DEFINED,
244];
245
246macro_rules! grammar_error {
247    ($kind:ident, $($arg:tt)*) => {
248        GrammarError::new(&format!($($arg)*),GrammarErrorType::$kind)
249    };
250}
251
252#[derive(Debug, Clone, PartialEq)]
253pub struct EncodingReferenceDefault(pub String);
254
255impl From<&str> for EncodingReferenceDefault {
256    fn from(value: &str) -> Self {
257        Self(value.into())
258    }
259}
260
261#[cfg_attr(test, derive(EnumDebug))]
262#[cfg_attr(not(test), derive(Debug))]
263#[derive(Clone, Copy, PartialEq, Default)]
264pub enum TaggingEnvironment {
265    Automatic,
266    #[default]
267    Implicit,
268    Explicit,
269}
270
271impl Add<&TaggingEnvironment> for &TaggingEnvironment {
272    type Output = TaggingEnvironment;
273
274    fn add(self, rhs: &TaggingEnvironment) -> Self::Output {
275        match (self, rhs) {
276            (t, TaggingEnvironment::Automatic) => *t,
277            (_, t) => *t,
278        }
279    }
280}
281
282/// Represents the extensibility environment as specified in
283/// Rec. ITU-T X.680 (02/2021) § 13.4
284#[cfg_attr(test, derive(EnumDebug))]
285#[cfg_attr(not(test), derive(Debug))]
286#[derive(Clone, Copy, PartialEq, Default)]
287pub enum ExtensibilityEnvironment {
288    Implied,
289    #[default]
290    Explicit,
291}
292
293/// Represents compatibility selectors as specified in
294/// Rec. ITU-T X.680 (02/2021) § 13.16 (f)
295#[cfg_attr(test, derive(EnumDebug))]
296#[cfg_attr(not(test), derive(Debug))]
297#[derive(Clone, PartialEq)]
298pub enum With {
299    Successors,
300    Descendants,
301}
302
303/// Represents a global module reference as specified in
304/// Rec. ITU-T X.680 (02/2021)
305#[derive(Debug, Clone, PartialEq)]
306pub struct ExternalValueReference {
307    pub module_reference: String,
308    pub value_reference: String,
309}
310
311/// Represents a global module reference as specified in
312/// Rec. ITU-T X.680 (02/2021)
313#[derive(Debug, Clone, PartialEq)]
314pub struct GlobalModuleReference {
315    pub module_reference: String,
316    pub assigned_identifier: AssignedIdentifier,
317}
318
319impl From<(&str, AssignedIdentifier)> for GlobalModuleReference {
320    fn from(value: (&str, AssignedIdentifier)) -> Self {
321        Self {
322            module_reference: value.0.to_owned(),
323            assigned_identifier: value.1,
324        }
325    }
326}
327
328/// Represents an assigned identifier as specified in
329/// Rec. ITU-T X.680 (02/2021)
330#[cfg_attr(test, derive(EnumDebug))]
331#[cfg_attr(not(test), derive(Debug))]
332#[derive(Clone, PartialEq)]
333pub enum AssignedIdentifier {
334    ObjectIdentifierValue(ObjectIdentifierValue),
335    ExternalValueReference(ExternalValueReference),
336    ValueReference(String),
337    ParameterizedValue {
338        value_reference: String,
339        actual_parameter_list: String,
340    },
341    Empty,
342}
343
344/// Represents a module import as specified in
345/// Rec. ITU-T X.680 (02/2021) § 13.16
346#[derive(Debug, Clone, PartialEq)]
347pub struct Import {
348    pub types: Vec<String>,
349    pub global_module_reference: GlobalModuleReference,
350    pub with: Option<With>,
351}
352
353impl From<(Vec<&str>, (GlobalModuleReference, Option<&str>))> for Import {
354    fn from(value: (Vec<&str>, (GlobalModuleReference, Option<&str>))) -> Self {
355        Self {
356            types: value.0.into_iter().map(String::from).collect(),
357            global_module_reference: value.1 .0,
358            with: value.1 .1.map(|with| {
359                if with == WITH_SUCCESSORS {
360                    With::Successors
361                } else {
362                    With::Descendants
363                }
364            }),
365        }
366    }
367}
368
369/// Represents a module export as specified in
370/// Rec. ITU-T X.680 (02/2021) § 13.13
371#[cfg_attr(test, derive(EnumDebug))]
372#[cfg_attr(not(test), derive(Debug))]
373#[derive(Clone, PartialEq)]
374pub enum Exports {
375    Identifier(Vec<String>),
376    All,
377}
378
379impl From<Vec<&str>> for Exports {
380    fn from(value: Vec<&str>) -> Self {
381        Self::Identifier(value.iter().map(ToString::to_string).collect())
382    }
383}
384
385/// Represents a module header's definitive identifier as specified in
386/// Rec. ITU-T X.680 (02/2021) § 13.8
387#[cfg_attr(test, derive(EnumDebug))]
388#[cfg_attr(not(test), derive(Debug))]
389#[derive(Clone, PartialEq)]
390pub enum DefinitiveIdentifier {
391    DefinitiveOID(ObjectIdentifierValue),
392    DefinitiveOIDandIRI {
393        oid: ObjectIdentifierValue,
394        iri: String,
395    },
396}
397
398impl From<(ObjectIdentifierValue, Option<&str>)> for DefinitiveIdentifier {
399    fn from(value: (ObjectIdentifierValue, Option<&str>)) -> Self {
400        if let Some(iri_value) = value.1 {
401            Self::DefinitiveOIDandIRI {
402                oid: value.0,
403                iri: iri_value.to_owned(),
404            }
405        } else {
406            Self::DefinitiveOID(value.0)
407        }
408    }
409}
410
411/// Represents a module header as specified in
412/// Rec. ITU-T X.680 (02/2021) § 13
413#[derive(Debug, Clone, PartialEq)]
414pub struct ModuleHeader {
415    pub name: String,
416    pub module_identifier: Option<DefinitiveIdentifier>,
417    pub encoding_reference_default: Option<EncodingReferenceDefault>,
418    pub tagging_environment: TaggingEnvironment,
419    pub extensibility_environment: ExtensibilityEnvironment,
420    pub imports: Vec<Import>,
421    pub exports: Option<Exports>,
422}
423
424impl ModuleHeader {
425    /// Returns an import that matches a given identifier, if present.
426    pub fn find_import(&self, identifier: &str) -> Option<&String> {
427        self.imports
428            .iter()
429            .find_map(|i| i.types.iter().find(|id| *id == identifier))
430    }
431}
432
433impl
434    From<(
435        &str,
436        Option<DefinitiveIdentifier>,
437        Option<(
438            Option<EncodingReferenceDefault>,
439            TaggingEnvironment,
440            ExtensibilityEnvironment,
441        )>,
442        Option<Exports>,
443        Option<Vec<Import>>,
444    )> for ModuleHeader
445{
446    fn from(
447        value: (
448            &str,
449            Option<DefinitiveIdentifier>,
450            Option<(
451                Option<EncodingReferenceDefault>,
452                TaggingEnvironment,
453                ExtensibilityEnvironment,
454            )>,
455            Option<Exports>,
456            Option<Vec<Import>>,
457        ),
458    ) -> Self {
459        let (encoding_reference_default, tagging_environment, extensibility_environment) =
460            value.2.unwrap_or((
461                None,
462                TaggingEnvironment::Explicit,
463                ExtensibilityEnvironment::Explicit,
464            ));
465        Self {
466            name: value.0.into(),
467            module_identifier: value.1,
468            encoding_reference_default,
469            tagging_environment,
470            extensibility_environment,
471            exports: value.3,
472            imports: value.4.unwrap_or_default(),
473        }
474    }
475}
476
477/// Represents an object identifier value as specified in
478/// Rec. ITU-T X.680 (02/2021) §32
479#[derive(Debug, Clone, PartialEq)]
480pub struct ObjectIdentifierValue(pub Vec<ObjectIdentifierArc>);
481
482impl From<Vec<ObjectIdentifierArc>> for ObjectIdentifierValue {
483    fn from(value: Vec<ObjectIdentifierArc>) -> Self {
484        Self(value)
485    }
486}
487
488/// Represents a single arc of an object identifier value
489/// as specified in Rec. ITU-T X.680 (02/2021) §32
490#[derive(Debug, Clone, PartialEq)]
491pub struct ObjectIdentifierArc {
492    pub name: Option<String>,
493    pub number: Option<u128>,
494}
495
496impl ObjectIdentifierArc {
497    const ITU_T: u128 = 0;
498    const ISO: u128 = 1;
499    const JOINT_ISO_ITU_T: u128 = 2;
500    const JOINT_ISO_CCITT: u128 = 2;
501    const RECOMMENDATION: u128 = 0;
502    const QUESTION: u128 = 1;
503    const ADMINISTRATION: u128 = 2;
504    const NETWORK_OPERATOR: u128 = 3;
505    const ITU_T_IDENTIFIED_ORGANIZATION: u128 = 4;
506    const R_RECOMMENDATION: u128 = 5;
507    const STANDARD: u128 = 0;
508    const REGISTRATION_AUTHORITY: u128 = 1;
509    const MEMBER_BODY: u128 = 2;
510    const ISO_IDENTIFIED_ORGANIZATION: u128 = 3;
511
512    pub(crate) fn well_known(name: Option<&String>, root: Option<u8>) -> Option<u128> {
513        match (root, name.map(|s| s.as_str())) {
514            (_, Some("itu-t")) => Some(Self::ITU_T),
515            (_, Some("iso")) => Some(Self::ISO),
516            (_, Some("joint-iso-itu-t")) => Some(Self::JOINT_ISO_ITU_T),
517            (_, Some("joint-iso-ccitt")) => Some(Self::JOINT_ISO_CCITT),
518            (Some(0), Some("recommendation")) => Some(Self::RECOMMENDATION),
519            (Some(0), Some("question")) => Some(Self::QUESTION),
520            (Some(0), Some("administration")) => Some(Self::ADMINISTRATION),
521            (Some(0), Some("network-operator")) => Some(Self::NETWORK_OPERATOR),
522            (Some(0), Some("identified-organization")) => Some(Self::ITU_T_IDENTIFIED_ORGANIZATION),
523            (Some(0), Some("r-recommendation")) => Some(Self::R_RECOMMENDATION),
524            (Some(1), Some("standard")) => Some(Self::STANDARD),
525            (Some(1), Some("registration-authority")) => Some(Self::REGISTRATION_AUTHORITY),
526            (Some(1), Some("member-body")) => Some(Self::MEMBER_BODY),
527            (Some(1), Some("identified-organization")) => Some(Self::ISO_IDENTIFIED_ORGANIZATION),
528            _ => None,
529        }
530    }
531}
532
533impl From<u128> for ObjectIdentifierArc {
534    fn from(value: u128) -> Self {
535        Self {
536            name: None,
537            number: Some(value),
538        }
539    }
540}
541
542impl From<&str> for ObjectIdentifierArc {
543    fn from(value: &str) -> Self {
544        Self {
545            name: Some(value.into()),
546            number: None,
547        }
548    }
549}
550
551impl From<(&str, u128)> for ObjectIdentifierArc {
552    fn from(value: (&str, u128)) -> Self {
553        Self {
554            name: Some(value.0.into()),
555            number: Some(value.1),
556        }
557    }
558}
559
560/// Represents a top-level ASN.1 definition.
561/// The compiler distinguished three different variants of top-level definitions.
562///
563/// The linker and any [Backend] for this compiler consumes top-level definitions in
564/// order to generate bindings.
565#[cfg_attr(test, derive(EnumDebug))]
566#[cfg_attr(not(test), derive(Debug))]
567#[derive(Clone, PartialEq)]
568pub enum ToplevelDefinition {
569    /// Definition for a custom type based on ASN.1's built-in type.
570    Type(ToplevelTypeDefinition),
571    /// Definition for a value using custom or built-in type.
572    Value(ToplevelValueDefinition),
573    /// Definition for a object class as introduced in ITU-T X.681 9.
574    Class(ObjectClassAssignment),
575    /// Definition for an object or object set, as introduced in ITU-T X.681 11.
576    Object(ToplevelInformationDefinition),
577    /// Definition for a macro.
578    Macro(ToplevelMacroDefinition),
579}
580
581impl ToplevelDefinition {
582    pub(crate) fn has_enum_value(&self, type_name: Option<&String>, identifier: &String) -> bool {
583        if let ToplevelDefinition::Type(ToplevelTypeDefinition {
584            name,
585            ty: ASN1Type::Enumerated(e),
586            ..
587        }) = self
588        {
589            if type_name.is_some() && Some(name) != type_name {
590                return false;
591            }
592            e.members.iter().any(|m| &m.name == identifier)
593        } else {
594            false
595        }
596    }
597
598    pub(crate) fn set_module_header(&mut self, module_header: Rc<RefCell<ModuleHeader>>) {
599        match self {
600            ToplevelDefinition::Type(ref mut t) => {
601                t.module_header = Some(module_header);
602            }
603            ToplevelDefinition::Value(ref mut v) => {
604                v.module_header = Some(module_header);
605            }
606            ToplevelDefinition::Class(ref mut c) => {
607                c.module_header = Some(module_header);
608            }
609            ToplevelDefinition::Object(ref mut o) => {
610                o.module_header = Some(module_header);
611            }
612            ToplevelDefinition::Macro(ref mut m) => {
613                m.module_header = Some(module_header);
614            }
615        }
616    }
617
618    pub(crate) fn get_module_header(&self) -> Option<Rc<RefCell<ModuleHeader>>> {
619        match self {
620            ToplevelDefinition::Type(ref t) => t.module_header.as_ref().cloned(),
621            ToplevelDefinition::Value(ref v) => v.module_header.as_ref().cloned(),
622            ToplevelDefinition::Class(ref c) => c.module_header.as_ref().cloned(),
623            ToplevelDefinition::Object(ref o) => o.module_header.as_ref().cloned(),
624            ToplevelDefinition::Macro(ref m) => m.module_header.as_ref().cloned(),
625        }
626    }
627
628    pub(crate) fn apply_tagging_environment(&mut self, environment: &TaggingEnvironment) {
629        if let (env, ToplevelDefinition::Type(ty)) = (environment, self) {
630            ty.tag = ty.tag.as_ref().map(|t| AsnTag {
631                environment: env + &t.environment,
632                tag_class: t.tag_class,
633                id: t.id,
634            });
635            match &mut ty.ty {
636                ASN1Type::Sequence(s) | ASN1Type::Set(s) => s.members.iter_mut().for_each(|m| {
637                    m.tag = m.tag.as_ref().map(|t| AsnTag {
638                        environment: env + &t.environment,
639                        tag_class: t.tag_class,
640                        id: t.id,
641                    });
642                }),
643                ASN1Type::Choice(c) => c.options.iter_mut().for_each(|o| {
644                    o.tag = o.tag.as_ref().map(|t| AsnTag {
645                        environment: env + &t.environment,
646                        tag_class: t.tag_class,
647                        id: t.id,
648                    });
649                }),
650                _ => (),
651            }
652        }
653    }
654
655    /// Returns the name of a top-level definition.
656    /// ### Example
657    /// ```
658    /// # use rasn_compiler::prelude::ir::*;
659    /// assert_eq!(
660    ///     ToplevelDefinition::Value(
661    ///         ToplevelValueDefinition {
662    ///             comments: String::from("Comments from the ASN.1 spec"),
663    ///             parameterization: None,
664    ///             name: String::from("the-answer"),
665    ///             associated_type: ASN1Type::Integer(Integer {
666    ///                 constraints: vec![],
667    ///                 distinguished_values: None,
668    ///             }),
669    ///             value: ASN1Value::Integer(42),
670    ///             module_header: None,
671    ///         }
672    ///     ).name(),
673    ///     &String::from("the-answer")
674    /// );
675    /// ```
676    pub fn name(&self) -> &String {
677        match self {
678            ToplevelDefinition::Class(c) => &c.name,
679            ToplevelDefinition::Object(o) => &o.name,
680            ToplevelDefinition::Type(t) => &t.name,
681            ToplevelDefinition::Value(v) => &v.name,
682            ToplevelDefinition::Macro(v) => &v.name,
683        }
684    }
685}
686
687/// Represents a top-level definition of a value
688/// using a custom or built-in ASN.1 type.
689#[derive(Debug, Clone, PartialEq)]
690pub struct ToplevelValueDefinition {
691    pub comments: String,
692    pub name: String,
693    pub associated_type: ASN1Type,
694    pub parameterization: Option<Parameterization>,
695    pub value: ASN1Value,
696    pub module_header: Option<Rc<RefCell<ModuleHeader>>>,
697}
698
699impl From<(&str, ASN1Value, ASN1Type)> for ToplevelValueDefinition {
700    fn from(value: (&str, ASN1Value, ASN1Type)) -> Self {
701        Self {
702            comments: String::new(),
703            name: value.0.to_owned(),
704            associated_type: value.2.to_owned(),
705            parameterization: None,
706            value: value.1,
707            module_header: None,
708        }
709    }
710}
711
712impl
713    From<(
714        Vec<&str>,
715        &str,
716        Option<Parameterization>,
717        ASN1Type,
718        ASN1Value,
719    )> for ToplevelValueDefinition
720{
721    fn from(
722        value: (
723            Vec<&str>,
724            &str,
725            Option<Parameterization>,
726            ASN1Type,
727            ASN1Value,
728        ),
729    ) -> Self {
730        Self {
731            comments: value.0.join("\n"),
732            name: value.1.into(),
733            parameterization: value.2,
734            associated_type: value.3,
735            value: value.4,
736            module_header: None,
737        }
738    }
739}
740
741#[derive(Debug, Clone, PartialEq)]
742pub struct ToplevelTypeDefinition {
743    pub comments: String,
744    pub tag: Option<AsnTag>,
745    pub name: String,
746    pub ty: ASN1Type,
747    pub parameterization: Option<Parameterization>,
748    pub module_header: Option<Rc<RefCell<ModuleHeader>>>,
749}
750
751impl ToplevelTypeDefinition {
752    pub fn pdu(&self) -> &ASN1Type {
753        &self.ty
754    }
755}
756
757impl From<(&str, ASN1Type)> for ToplevelTypeDefinition {
758    fn from(value: (&str, ASN1Type)) -> Self {
759        Self {
760            comments: String::new(),
761            tag: None,
762            name: value.0.to_owned(),
763            ty: value.1,
764            parameterization: None,
765            module_header: None,
766        }
767    }
768}
769
770impl
771    From<(
772        Vec<&str>,
773        &str,
774        Option<Parameterization>,
775        (Option<AsnTag>, ASN1Type),
776    )> for ToplevelTypeDefinition
777{
778    fn from(
779        value: (
780            Vec<&str>,
781            &str,
782            Option<Parameterization>,
783            (Option<AsnTag>, ASN1Type),
784        ),
785    ) -> Self {
786        Self {
787            comments: value.0.join("\n"),
788            name: value.1.into(),
789            parameterization: value.2,
790            ty: value.3 .1,
791            tag: value.3 .0,
792            module_header: None,
793        }
794    }
795}
796
797/// The possible types of an ASN1 data element.
798/// In addition, the `ElsewhereDeclaredType` enumeral denotes an type
799/// specified in the same or an imported ASN1 specification.
800#[cfg_attr(test, derive(EnumDebug))]
801#[cfg_attr(not(test), derive(Debug))]
802#[derive(Clone, PartialEq)]
803pub enum ASN1Type {
804    Null,
805    Boolean(Boolean),
806    Integer(Integer),
807    Real(Real),
808    BitString(BitString),
809    OctetString(OctetString),
810    CharacterString(CharacterString),
811    Enumerated(Enumerated),
812    Choice(Choice),
813    Sequence(SequenceOrSet),
814    SequenceOf(SequenceOrSetOf),
815    Set(SequenceOrSet),
816    SetOf(SequenceOrSetOf),
817    Time(Time),
818    GeneralizedTime(GeneralizedTime),
819    UTCTime(UTCTime),
820    Any,
821    ElsewhereDeclaredType(DeclarationElsewhere),
822    ChoiceSelectionType(ChoiceSelectionType),
823    ObjectIdentifier(ObjectIdentifier),
824    ObjectClassField(ObjectClassFieldType),
825    EmbeddedPdv,
826    External,
827}
828
829impl ASN1Type {
830    pub fn as_str(&self) -> Cow<'_, str> {
831        match self {
832            ASN1Type::Null => Cow::Borrowed(NULL),
833            ASN1Type::Boolean(_) => Cow::Borrowed(BOOLEAN),
834            ASN1Type::Integer(_) => Cow::Borrowed(INTEGER),
835            ASN1Type::Real(_) => Cow::Borrowed(REAL),
836            ASN1Type::BitString(_) => Cow::Borrowed(BIT_STRING),
837            ASN1Type::OctetString(_) => Cow::Borrowed(OCTET_STRING),
838            ASN1Type::CharacterString(CharacterString {
839                ty: CharacterStringType::BMPString,
840                ..
841            }) => Cow::Borrowed(BMP_STRING),
842            ASN1Type::CharacterString(CharacterString {
843                ty: CharacterStringType::UTF8String,
844                ..
845            }) => Cow::Borrowed(UTF8_STRING),
846            ASN1Type::CharacterString(CharacterString {
847                ty: CharacterStringType::PrintableString,
848                ..
849            }) => Cow::Borrowed(PRINTABLE_STRING),
850            ASN1Type::CharacterString(CharacterString {
851                ty: CharacterStringType::TeletexString,
852                ..
853            }) => Cow::Borrowed(TELETEX_STRING),
854            ASN1Type::CharacterString(CharacterString {
855                ty: CharacterStringType::IA5String,
856                ..
857            }) => Cow::Borrowed(IA5_STRING),
858            ASN1Type::CharacterString(CharacterString {
859                ty: CharacterStringType::UniversalString,
860                ..
861            }) => Cow::Borrowed(UNIVERSAL_STRING),
862            ASN1Type::CharacterString(CharacterString {
863                ty: CharacterStringType::VisibleString,
864                ..
865            }) => Cow::Borrowed(VISIBLE_STRING),
866            ASN1Type::CharacterString(CharacterString {
867                ty: CharacterStringType::GeneralString,
868                ..
869            }) => Cow::Borrowed(GENERAL_STRING),
870            ASN1Type::CharacterString(CharacterString {
871                ty: CharacterStringType::VideotexString,
872                ..
873            }) => Cow::Borrowed(VIDEOTEX_STRING),
874            ASN1Type::CharacterString(CharacterString {
875                ty: CharacterStringType::GraphicString,
876                ..
877            }) => Cow::Borrowed(GRAPHIC_STRING),
878            ASN1Type::CharacterString(CharacterString {
879                ty: CharacterStringType::NumericString,
880                ..
881            }) => Cow::Borrowed(NUMERIC_STRING),
882            ASN1Type::Enumerated(_) => Cow::Borrowed(ENUMERATED),
883            ASN1Type::Choice(_) => Cow::Borrowed(CHOICE),
884            ASN1Type::Sequence(_) => Cow::Borrowed(SEQUENCE),
885            ASN1Type::SequenceOf(_) => Cow::Borrowed(SEQUENCE_OF),
886            ASN1Type::Set(_) => Cow::Borrowed(SET),
887            ASN1Type::SetOf(_) => Cow::Borrowed(SET_OF),
888            ASN1Type::Time(_) => Cow::Borrowed(TIME),
889            ASN1Type::GeneralizedTime(_) => Cow::Borrowed(GENERALIZED_TIME),
890            ASN1Type::UTCTime(_) => Cow::Borrowed(UTC_TIME),
891            ASN1Type::Any => Cow::Borrowed(ANY),
892            ASN1Type::ElsewhereDeclaredType(DeclarationElsewhere { identifier, .. }) => {
893                Cow::Borrowed(identifier)
894            }
895            ASN1Type::ChoiceSelectionType(_) => todo!(),
896            ASN1Type::ObjectIdentifier(_) => Cow::Borrowed(OBJECT_IDENTIFIER),
897            ASN1Type::ObjectClassField(ifr) => Cow::Owned(format!(
898                "{INTERNAL_IO_FIELD_REF_TYPE_NAME_PREFIX}{}${}",
899                ifr.class,
900                ifr.field_path_as_str()
901            )),
902            ASN1Type::EmbeddedPdv => Cow::Borrowed(EMBEDDED_PDV),
903            ASN1Type::External => Cow::Borrowed(EXTERNAL),
904        }
905    }
906
907    pub fn is_builtin_type(&self) -> bool {
908        !matches!(
909            self,
910            ASN1Type::ElsewhereDeclaredType(_)
911                | ASN1Type::ChoiceSelectionType(_)
912                | ASN1Type::ObjectClassField(_)
913        )
914    }
915
916    pub fn constraints(&self) -> Option<&Vec<Constraint>> {
917        match self {
918            ASN1Type::Boolean(b) => Some(b.constraints()),
919            ASN1Type::Real(r) => Some(r.constraints()),
920            ASN1Type::Integer(i) => Some(i.constraints()),
921            ASN1Type::BitString(b) => Some(b.constraints()),
922            ASN1Type::OctetString(o) => Some(o.constraints()),
923            ASN1Type::CharacterString(c) => Some(c.constraints()),
924            ASN1Type::Enumerated(e) => Some(e.constraints()),
925            ASN1Type::Time(t) => Some(t.constraints()),
926            ASN1Type::Choice(c) => Some(c.constraints()),
927            ASN1Type::Set(s) | ASN1Type::Sequence(s) => Some(s.constraints()),
928            ASN1Type::SetOf(s) | ASN1Type::SequenceOf(s) => Some(s.constraints()),
929            ASN1Type::ElsewhereDeclaredType(e) => Some(e.constraints()),
930            ASN1Type::ObjectClassField(f) => Some(f.constraints()),
931            _ => None,
932        }
933    }
934
935    pub fn constraints_mut(&mut self) -> Option<&mut Vec<Constraint>> {
936        match self {
937            ASN1Type::Boolean(b) => Some(b.constraints_mut()),
938            ASN1Type::Real(r) => Some(r.constraints_mut()),
939            ASN1Type::Integer(i) => Some(i.constraints_mut()),
940            ASN1Type::BitString(b) => Some(b.constraints_mut()),
941            ASN1Type::OctetString(o) => Some(o.constraints_mut()),
942            ASN1Type::CharacterString(c) => Some(c.constraints_mut()),
943            ASN1Type::Enumerated(e) => Some(e.constraints_mut()),
944            ASN1Type::Time(t) => Some(t.constraints_mut()),
945            ASN1Type::Choice(c) => Some(c.constraints_mut()),
946            ASN1Type::Set(s) | ASN1Type::Sequence(s) => Some(s.constraints_mut()),
947            ASN1Type::SetOf(s) | ASN1Type::SequenceOf(s) => Some(s.constraints_mut()),
948            ASN1Type::ElsewhereDeclaredType(e) => Some(e.constraints_mut()),
949            ASN1Type::ObjectClassField(f) => Some(f.constraints_mut()),
950            _ => None,
951        }
952    }
953}
954
955pub const NUMERIC_STRING_CHARSET: [char; 11] =
956    [' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
957pub const PRINTABLE_STRING_CHARSET: [char; 74] = [
958    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
959    'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
960    'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
961    '5', '6', '7', '8', '9', ' ', '\'', '(', ')', '+', ',', '-', '.', '/', ':', '=', '?',
962];
963
964/// The types of an ASN1 character strings.
965#[cfg_attr(test, derive(EnumDebug))]
966#[cfg_attr(not(test), derive(Debug))]
967#[derive(Clone, PartialEq, Copy)]
968pub enum CharacterStringType {
969    NumericString,
970    VisibleString,
971    IA5String,
972    TeletexString,
973    VideotexString,
974    GraphicString,
975    GeneralString,
976    UniversalString,
977    UTF8String,
978    BMPString,
979    PrintableString,
980}
981
982impl CharacterStringType {
983    pub fn character_set(&self) -> BTreeMap<usize, char> {
984        match self {
985            CharacterStringType::NumericString => {
986                NUMERIC_STRING_CHARSET.into_iter().enumerate().collect()
987            }
988            CharacterStringType::VisibleString | CharacterStringType::PrintableString => {
989                PRINTABLE_STRING_CHARSET.into_iter().enumerate().collect()
990            }
991            CharacterStringType::IA5String => (0..128u32)
992                .map(|i| char::from_u32(i).unwrap())
993                .enumerate()
994                .collect(),
995            _ => (0..u16::MAX as u32)
996                .filter_map(char::from_u32)
997                .enumerate()
998                .collect(),
999        }
1000    }
1001}
1002
1003/// Representation of common integer types
1004#[derive(Debug, Clone, Copy, PartialEq)]
1005pub enum IntegerType {
1006    Int8,
1007    Uint8,
1008    Int16,
1009    Uint16,
1010    Int32,
1011    Uint32,
1012    Int64,
1013    Uint64,
1014    Unbounded,
1015}
1016
1017impl ToTokens for IntegerType {
1018    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
1019        match self {
1020            IntegerType::Int8 => tokens.append_all(quote!(i8)),
1021            IntegerType::Uint8 => tokens.append_all(quote!(u8)),
1022            IntegerType::Int16 => tokens.append_all(quote!(i16)),
1023            IntegerType::Uint16 => tokens.append_all(quote!(u16)),
1024            IntegerType::Int32 => tokens.append_all(quote!(i32)),
1025            IntegerType::Uint32 => tokens.append_all(quote!(u32)),
1026            IntegerType::Int64 => tokens.append_all(quote!(i64)),
1027            IntegerType::Uint64 => tokens.append_all(quote!(u64)),
1028            IntegerType::Unbounded => tokens.append_all(quote!(Integer)),
1029        }
1030    }
1031}
1032
1033impl IntegerType {
1034    pub fn is_unbounded(&self) -> bool {
1035        self == &IntegerType::Unbounded
1036    }
1037    /// Returns the Integer type with more restrictions
1038    /// - an IntegerType with a smaller set of values is considered more restrictive
1039    /// - an unsigned IntegerType is considered more restrictive if the size of the set of values is equal
1040    ///   if equal, `self` is returned
1041    pub fn max_restrictive(self, rhs: IntegerType) -> IntegerType {
1042        match (self, rhs) {
1043            (x, y) if x == y => x,
1044            (IntegerType::Uint8, _) | (_, IntegerType::Uint8) => IntegerType::Uint8,
1045            (IntegerType::Int8, _) | (_, IntegerType::Int8) => IntegerType::Int8,
1046            (IntegerType::Uint16, _) | (_, IntegerType::Uint16) => IntegerType::Uint16,
1047            (IntegerType::Int16, _) | (_, IntegerType::Int16) => IntegerType::Int16,
1048            (IntegerType::Uint32, _) | (_, IntegerType::Uint32) => IntegerType::Uint32,
1049            (IntegerType::Int32, _) | (_, IntegerType::Int32) => IntegerType::Int32,
1050            (IntegerType::Uint64, _) | (_, IntegerType::Uint64) => IntegerType::Uint64,
1051            (IntegerType::Int64, _) | (_, IntegerType::Int64) => IntegerType::Int64,
1052            _ => IntegerType::Unbounded,
1053        }
1054    }
1055}
1056
1057/// The possible types of an ASN1 value.
1058#[cfg_attr(test, derive(EnumDebug))]
1059#[cfg_attr(not(test), derive(Debug))]
1060#[derive(Clone, PartialEq)]
1061pub enum ASN1Value {
1062    All,
1063    Null,
1064    Boolean(bool),
1065    Choice {
1066        type_name: Option<String>,
1067        variant_name: String,
1068        inner_value: Box<ASN1Value>,
1069    },
1070    /// In ASN.1, value definitions are ambiguous between SEQUENCE, SET, SEQUENCE OF, and SET OF
1071    /// For example, `{ my-elem FALSE }` could be a value of all four types
1072    SequenceOrSet(Vec<(Option<String>, Box<ASN1Value>)>),
1073    Integer(i128),
1074    Real(f64),
1075    String(String),
1076    BitString(Vec<bool>),
1077    BitStringNamedBits(Vec<String>),
1078    OctetString(Vec<u8>),
1079    EnumeratedValue {
1080        enumerated: String,
1081        enumerable: String,
1082    },
1083    Time(String),
1084    ElsewhereDeclaredValue {
1085        module: Option<String>,
1086        parent: Option<String>,
1087        identifier: String,
1088    },
1089    ObjectIdentifier(ObjectIdentifierValue),
1090    /// In ASN1 value declarations, the value type is not straighforward to parse.
1091    /// For example, in the following ASN1
1092    /// ```ignore
1093    /// ExampleInt ::= INTEGER
1094    /// ExampleSubset ::= ExampleInt (1..500)
1095    /// AnotherSubset ::= ExampleSubset (2..200)
1096    /// ExampleSet ::= SET {
1097    ///     int AnotherSubset DEFAULT 3
1098    /// }
1099    /// ```
1100    /// the relation of the default value to `ExampleSubset` will not be picked up by the lexer.
1101    /// However, in some representations, this relation is critical information.
1102    LinkedNestedValue {
1103        /// typereferences of supertypes
1104        supertypes: Vec<String>,
1105        value: Box<ASN1Value>,
1106    },
1107    /// Integer values need type information that will not always be picked up by the lexer on first pass.
1108    LinkedIntValue {
1109        integer_type: IntegerType,
1110        value: i128,
1111    },
1112    /// Struct-like values such as SEQUENCE values need type information that will not always be picked up by the lexer on first pass.
1113    /// Contains a vector of the struct-like's fields, with the field name, the field type, and the field value as a tuple
1114    LinkedStructLikeValue(Vec<(String, ASN1Type, StructLikeFieldValue)>),
1115    /// Array-like values such as SEQUENCE OF values need type information that will not always be picked up by the lexer on first pass.
1116    LinkedArrayLikeValue(Vec<Box<ASN1Value>>),
1117    /// Character string values such as UTF8String values need type information that will not always be picked up by the lexer on first pass.
1118    LinkedCharStringValue(CharacterStringType, String),
1119    LinkedElsewhereDefinedValue {
1120        parent: Option<String>,
1121        identifier: String,
1122        can_be_const: bool,
1123    },
1124}
1125
1126/// Representation of a field value of a struct-like ASN1 value
1127#[cfg_attr(test, derive(EnumDebug))]
1128#[cfg_attr(not(test), derive(Debug))]
1129#[derive(Clone, PartialEq)]
1130pub enum StructLikeFieldValue {
1131    Explicit(Box<ASN1Value>),
1132    Implicit(Box<ASN1Value>),
1133}
1134
1135impl StructLikeFieldValue {
1136    pub fn into_value(self) -> ASN1Value {
1137        match self {
1138            StructLikeFieldValue::Explicit(v) | StructLikeFieldValue::Implicit(v) => *v,
1139        }
1140    }
1141
1142    pub fn value(&self) -> &ASN1Value {
1143        match self {
1144            StructLikeFieldValue::Explicit(v) | StructLikeFieldValue::Implicit(v) => v,
1145        }
1146    }
1147
1148    pub fn value_mut(&mut self) -> &mut ASN1Value {
1149        match self {
1150            StructLikeFieldValue::Explicit(ref mut v)
1151            | StructLikeFieldValue::Implicit(ref mut v) => &mut *v,
1152        }
1153    }
1154}
1155
1156impl AsMut<ASN1Value> for ASN1Value {
1157    fn as_mut(&mut self) -> &mut ASN1Value {
1158        self
1159    }
1160}
1161
1162impl ASN1Value {
1163    pub fn max(
1164        &self,
1165        other: &ASN1Value,
1166        char_set: Option<&BTreeMap<usize, char>>,
1167    ) -> Result<ASN1Value, GrammarError> {
1168        self.min_max(other, char_set, false)
1169    }
1170
1171    pub fn min(
1172        &self,
1173        other: &ASN1Value,
1174        char_set: Option<&BTreeMap<usize, char>>,
1175    ) -> Result<ASN1Value, GrammarError> {
1176        self.min_max(other, char_set, true)
1177    }
1178
1179    fn min_max(
1180        &self,
1181        other: &ASN1Value,
1182        char_set: Option<&BTreeMap<usize, char>>,
1183        getting_mininum: bool,
1184    ) -> Result<ASN1Value, GrammarError> {
1185        match (self, other, char_set) {
1186            (ASN1Value::Integer(s), ASN1Value::Integer(o), _) => {
1187                if getting_mininum {
1188                    Ok(ASN1Value::Integer(*s.min(o)))
1189                } else {
1190                    Ok(ASN1Value::Integer(*s.max(o)))
1191                }
1192            }
1193            (ASN1Value::String(s), ASN1Value::String(o), Some(set)) => {
1194                if s.len() != 1 || o.len() != 1 {
1195                    return Err(grammar_error!(
1196                        UnpackingError,
1197                        "Unsupported operation for ASN1Values {self:?} and {other:?}"
1198                    ));
1199                }
1200                let s_as_char = s.chars().next().unwrap();
1201                let o_as_char = o.chars().next().unwrap();
1202                match (
1203                    set.iter().find(|(_, c)| s_as_char == **c),
1204                    set.iter().find(|(_, c)| o_as_char == **c),
1205                ) {
1206                    (Some((self_i, _)), Some((other_i, _))) => {
1207                        let return_self = if getting_mininum {
1208                            self_i <= other_i
1209                        } else {
1210                            self_i >= other_i
1211                        };
1212                        if return_self {
1213                            Ok(self.clone())
1214                        } else {
1215                            Ok(other.clone())
1216                        }
1217                    }
1218                    _ => Err(grammar_error!(
1219                            UnpackingError,
1220                            "Failed to find ASN1Values {self:?} and {other:?} in character set {char_set:?}",
1221                        )),
1222                }
1223            }
1224            _ => Err(grammar_error!(
1225                UnpackingError,
1226                "Unsupported operation for ASN1Values {self:?} and {other:?}",
1227            )),
1228        }
1229    }
1230
1231    pub fn unwrap_as_integer(&self) -> Result<i128, GrammarError> {
1232        if let ASN1Value::Integer(i) = self {
1233            Ok(*i)
1234        } else {
1235            Err(grammar_error!(
1236                UnpackingError,
1237                "Cannot unwrap {self:?} as integer!"
1238            ))
1239        }
1240    }
1241}
1242
1243/// Intermediate placeholder for a type declared in
1244/// some other part of the ASN1 specification that is
1245/// being parsed or in one of its imports.
1246#[derive(Debug, Clone, PartialEq)]
1247pub struct DeclarationElsewhere {
1248    /// Chain of parent declaration leading back to a basic ASN1 type
1249    pub parent: Option<String>,
1250    /// Name of the module where the identifier should be found.
1251    pub module: Option<String>,
1252    pub identifier: String,
1253    pub constraints: Vec<Constraint>,
1254}
1255
1256/// Tag classes
1257#[derive(Debug, Clone, Copy, PartialEq)]
1258pub enum TagClass {
1259    Universal,
1260    Application,
1261    Private,
1262    ContextSpecific,
1263}
1264
1265/// Representation of a tag
1266#[derive(Debug, Clone, PartialEq)]
1267pub struct AsnTag {
1268    pub environment: TaggingEnvironment,
1269    pub tag_class: TagClass,
1270    pub id: u64,
1271}
1272
1273impl From<((Option<&str>, u64), Option<TaggingEnvironment>)> for AsnTag {
1274    fn from(value: ((Option<&str>, u64), Option<TaggingEnvironment>)) -> Self {
1275        let tag_class = match value.0 .0 {
1276            Some("APPLICATION") => TagClass::Application,
1277            Some("UNIVERSAL") => TagClass::Universal,
1278            Some("PRIVATE") => TagClass::Private,
1279            _ => TagClass::ContextSpecific,
1280        };
1281        AsnTag {
1282            tag_class,
1283            id: value.0 .1,
1284            environment: value.1.unwrap_or(TaggingEnvironment::Automatic),
1285        }
1286    }
1287}