Skip to main content

asn1rs_model/model/
tag_resolver.rs

1use crate::model::charset::Charset;
2use crate::model::{Asn, Definition, Model, Tag, TagProperty, Type};
3
4pub struct TagResolver<'a> {
5    model: &'a Model<Asn>,
6    scope: &'a [&'a Model<Asn>],
7}
8
9impl TagResolver<'_> {
10    pub const fn new<'a>(model: &'a Model<Asn>, scope: &'a [&'a Model<Asn>]) -> TagResolver<'a> {
11        TagResolver { model, scope }
12    }
13
14    pub fn resolve_default(ty: &Type) -> Option<Tag> {
15        let model = Model::<Asn>::default();
16        TagResolver {
17            model: &model,
18            scope: &[],
19        }
20        .resolve_type_tag(ty)
21    }
22
23    /// ITU-T X.680 | ISO/IEC 8824-1, 8.6
24    /// ITU-T X.680 | ISO/IEC 8824-1, 41, table 8
25    pub fn resolve_tag(&self, ty: &str) -> Option<Tag> {
26        self.model
27            .imports
28            .iter()
29            .find(|import| import.what.iter().any(|what| what.eq(ty)))
30            .map(|import| &import.from)
31            .and_then(|model_name| self.scope.iter().find(|model| model.name.eq(model_name)))
32            .and_then(|model| {
33                TagResolver {
34                    model,
35                    scope: self.scope,
36                }
37                .resolve_tag(ty)
38            })
39            .or_else(|| {
40                self.model.definitions.iter().find(|d| d.0.eq(ty)).and_then(
41                    |Definition(_name, asn)| asn.tag.or_else(|| self.resolve_type_tag(&asn.r#type)),
42                )
43            })
44    }
45
46    /// ITU-T X.680 | ISO/IEC 8824-1, 8.6
47    /// ITU-T X.680 | ISO/IEC 8824-1, 41, table 8
48    pub fn resolve_no_default(&self, ty: &Type) -> Option<Tag> {
49        let default = Self::resolve_default(ty);
50        let resolved = self.resolve_type_tag(ty);
51        resolved.filter(|r| default.ne(&Some(*r)))
52    }
53
54    /// ITU-T X.680 | ISO/IEC 8824-1, 8.6
55    /// ITU-T X.680 | ISO/IEC 8824-1, 41, table 8
56    pub fn resolve_type_tag(&self, ty: &Type) -> Option<Tag> {
57        match ty {
58            Type::Boolean => Some(Tag::DEFAULT_BOOLEAN),
59            Type::Integer(_) => Some(Tag::DEFAULT_INTEGER),
60            Type::BitString(_) => Some(Tag::DEFAULT_BIT_STRING),
61            Type::OctetString(_) => Some(Tag::DEFAULT_OCTET_STRING),
62            Type::Enumerated(_) => Some(Tag::DEFAULT_ENUMERATED),
63            Type::String(_, Charset::Numeric) => Some(Tag::DEFAULT_NUMERIC_STRING),
64            Type::String(_, Charset::Printable) => Some(Tag::DEFAULT_PRINTABLE_STRING),
65            Type::String(_, Charset::Visible) => Some(Tag::DEFAULT_VISIBLE_STRING),
66            Type::String(_, Charset::Utf8) => Some(Tag::DEFAULT_UTF8_STRING),
67            Type::String(_, Charset::Ia5) => Some(Tag::DEFAULT_IA5_STRING),
68            Type::Null => Some(Tag::DEFAULT_NULL),
69            Type::Optional(inner) => self.resolve_type_tag(inner),
70            Type::Default(inner, ..) => self.resolve_type_tag(inner),
71            Type::Sequence(_) => Some(Tag::DEFAULT_SEQUENCE),
72            Type::SequenceOf(_, _) => Some(Tag::DEFAULT_SEQUENCE_OF),
73            Type::Set(_) => Some(Tag::DEFAULT_SET),
74            Type::SetOf(_, _) => Some(Tag::DEFAULT_SET_OF),
75            Type::Choice(choice) => {
76                let mut tags = choice
77                    .variants()
78                    .take(
79                        choice
80                            .extension_after_index()
81                            .map(|extension_after| extension_after + 1)
82                            .unwrap_or_else(|| choice.len()),
83                    )
84                    .map(|v| v.tag().or_else(|| self.resolve_type_tag(v.r#type())))
85                    .collect::<Option<Vec<Tag>>>()?;
86                tags.sort();
87                if cfg!(feature = "debug-proc-macro") {
88                    println!("resolved::::{:?}", tags);
89                }
90                tags.into_iter().next()
91            }
92            Type::TypeReference(inner, tag) => {
93                let tag = (*tag).or_else(|| self.resolve_tag(inner.as_str()));
94                if cfg!(feature = "debug-proc-macro") {
95                    println!("resolved :: {}::Tag = {:?}", inner, tag);
96                }
97                tag
98            }
99        }
100    }
101}