rasn_compiler/validator/linking/
information_object.rs

1use std::collections::BTreeMap;
2
3use crate::intermediate::{information_object::*, *};
4
5use super::{
6    utils::{resolve_custom_syntax, walk_object_field_ref_path},
7    GrammarError, GrammarErrorType,
8};
9
10impl ToplevelInformationDefinition {
11    pub fn resolve_class_reference(mut self, tlds: &BTreeMap<String, ToplevelDefinition>) -> Self {
12        if let ClassLink::ByName(name) = &self.class {
13            if let Some(ToplevelDefinition::Class(c)) = tlds.get(name) {
14                self.class = ClassLink::ByReference(c.definition.clone());
15            }
16        }
17        self
18    }
19
20    /// Collects supertypes of ASN1 values.
21    /// In `ToplevelTypeDefinition`s, values will appear only as `DEFAULT`
22    /// values in `SET`s or `SEQUENCE`s.
23    pub fn collect_supertypes(
24        &mut self,
25        tlds: &BTreeMap<String, ToplevelDefinition>,
26    ) -> Result<(), GrammarError> {
27        match (&mut self.value, &self.class) {
28            (ASN1Information::Object(ref mut o), ClassLink::ByReference(class)) => {
29                match resolve_and_link(&mut o.fields, class, tlds)? {
30                    Some(ToplevelInformationDefinition {
31                        value: ASN1Information::Object(obj),
32                        ..
33                    }) => {
34                        self.value = ASN1Information::ObjectSet(ObjectSet {
35                            values: vec![ObjectSetValue::Inline(obj.fields.clone())],
36                            extensible: None,
37                        });
38                    }
39                    Some(ToplevelInformationDefinition {
40                        value: ASN1Information::ObjectSet(set),
41                        ..
42                    }) => {
43                        self.value = ASN1Information::ObjectSet(set.clone());
44                    }
45                    _ => (),
46                }
47                Ok(())
48            }
49            (ASN1Information::ObjectSet(ref mut o), ClassLink::ByReference(class)) => {
50                o.values.iter_mut().try_for_each(|value| match value {
51                    ObjectSetValue::Reference(_) => Ok(()),
52                    ObjectSetValue::Inline(ref mut fields) => {
53                        resolve_custom_syntax(fields, class)?;
54                        link_object_fields(fields, class, tlds)
55                    }
56                })
57            }
58            _ => Ok(()),
59        }
60    }
61}
62
63fn resolve_and_link(
64    fields: &mut InformationObjectFields,
65    class: &ObjectClassDefn,
66    tlds: &BTreeMap<String, ToplevelDefinition>,
67) -> Result<Option<ToplevelInformationDefinition>, GrammarError> {
68    match resolve_custom_syntax(fields, class) {
69        Ok(()) => link_object_fields(fields, class, tlds).map(|_| None),
70        Err(
71            err @ GrammarError {
72                kind: GrammarErrorType::SyntaxMismatch,
73                ..
74            },
75        ) => {
76            if let InformationObjectFields::CustomSyntax(c) = &fields {
77                if let Some(id) = c.first().and_then(SyntaxApplication::as_str_or_none) {
78                    if let Some(ToplevelDefinition::Object(tld)) = tlds.get(id) {
79                        let mut tld_clone = tld.clone().resolve_class_reference(tlds);
80                        tld_clone.collect_supertypes(tlds)?;
81                        return Ok(Some(tld_clone));
82                    }
83                }
84            }
85            Err(err)
86        }
87        Err(e) => Err(e),
88    }
89}
90
91fn link_object_fields(
92    fields: &mut InformationObjectFields,
93    class: &ObjectClassDefn,
94    tlds: &BTreeMap<String, ToplevelDefinition>,
95) -> Result<(), GrammarError> {
96    match fields {
97        InformationObjectFields::DefaultSyntax(ref mut fields) => {
98            fields.iter_mut().try_for_each(|field| match field {
99                InformationObjectField::FixedValueField(fixed) => class
100                    .fields
101                    .iter()
102                    .find_map(|f| {
103                        (f.identifier
104                            == ObjectFieldIdentifier::SingleValue(fixed.identifier.clone()))
105                        .then_some(f.ty.as_ref())
106                    })
107                    .flatten()
108                    .ok_or_else(|| {
109                        GrammarError::new(
110                            &format!(
111                                "Could not determine type of fixed value field {}",
112                                fixed.identifier
113                            ),
114                            GrammarErrorType::LinkerError,
115                        )
116                    })
117                    .and_then(|ty| {
118                        fixed
119                            .value
120                            .link_with_type(tlds, ty, Some(&ty.as_str().to_string()))
121                    }),
122                InformationObjectField::ObjectSetField(_) => Err(GrammarError::new(
123                    "Linking object set fields is not yet supported!",
124                    GrammarErrorType::NotYetInplemented,
125                )),
126                _ => Ok(()),
127            })
128        }
129        InformationObjectFields::CustomSyntax(_) => Err(GrammarError::new(
130            "Unexpectedly encountered unresolved custom syntax linking information object",
131            GrammarErrorType::LinkerError,
132        )),
133    }
134}
135
136impl ASN1Information {
137    pub fn link_object_set_reference(
138        &mut self,
139        tlds: &BTreeMap<String, ToplevelDefinition>,
140    ) -> bool {
141        match self {
142            ASN1Information::ObjectSet(s) => s.link_object_set_reference(tlds),
143            ASN1Information::Object(o) => o.link_object_set_reference(tlds),
144        }
145    }
146
147    pub fn references_object_set_by_name(&self) -> bool {
148        match self {
149            ASN1Information::ObjectSet(s) => s.references_object_set_by_name(),
150            ASN1Information::Object(o) => o.references_object_set_by_name(),
151        }
152    }
153}
154
155impl SyntaxApplication {
156    pub fn link_object_set_reference(
157        &mut self,
158        tlds: &BTreeMap<String, ToplevelDefinition>,
159    ) -> bool {
160        match self {
161            SyntaxApplication::ObjectSetDeclaration(o) => o.link_object_set_reference(tlds),
162            _ => false,
163        }
164    }
165
166    pub fn references_object_set_by_name(&self) -> bool {
167        match self {
168            SyntaxApplication::ObjectSetDeclaration(o) => o.references_object_set_by_name(),
169            _ => false,
170        }
171    }
172}
173
174impl ObjectClassDefn {
175    pub fn get_field<'a>(
176        &'a self,
177        path: &'a Vec<ObjectFieldIdentifier>,
178    ) -> Option<&'a InformationObjectClassField> {
179        walk_object_field_ref_path(&self.fields, path, 0)
180    }
181}
182
183impl InformationObject {
184    pub fn link_object_set_reference(
185        &mut self,
186        tlds: &BTreeMap<String, ToplevelDefinition>,
187    ) -> bool {
188        match &mut self.fields {
189            InformationObjectFields::DefaultSyntax(d) => d
190                .iter_mut()
191                .any(|field| field.link_object_set_reference(tlds)),
192            InformationObjectFields::CustomSyntax(c) => c
193                .iter_mut()
194                .any(|field| field.link_object_set_reference(tlds)),
195        }
196    }
197
198    pub fn references_object_set_by_name(&self) -> bool {
199        match &self.fields {
200            InformationObjectFields::DefaultSyntax(d) => {
201                d.iter().any(|field| field.references_object_set_by_name())
202            }
203            InformationObjectFields::CustomSyntax(c) => {
204                c.iter().any(|field| field.references_object_set_by_name())
205            }
206        }
207    }
208}
209
210impl ObjectSetValue {
211    pub fn link_object_set_reference(
212        &mut self,
213        tlds: &BTreeMap<String, ToplevelDefinition>,
214    ) -> Option<Vec<ObjectSetValue>> {
215        match self {
216            ObjectSetValue::Reference(id) => match tlds.get(id) {
217                Some(ToplevelDefinition::Object(ToplevelInformationDefinition {
218                    value: ASN1Information::Object(obj),
219                    ..
220                })) => {
221                    *self = ObjectSetValue::Inline(obj.fields.clone());
222                    None
223                }
224                Some(ToplevelDefinition::Object(ToplevelInformationDefinition {
225                    value: ASN1Information::ObjectSet(obj),
226                    ..
227                })) => Some(obj.values.clone()),
228                _ => None,
229            },
230            ObjectSetValue::Inline(InformationObjectFields::CustomSyntax(c)) => {
231                c.iter_mut()
232                    .any(|field| field.link_object_set_reference(tlds));
233                None
234            }
235            ObjectSetValue::Inline(InformationObjectFields::DefaultSyntax(d)) => {
236                d.iter_mut()
237                    .any(|field| field.link_object_set_reference(tlds));
238                None
239            }
240        }
241    }
242
243    pub fn references_object_set_by_name(&self) -> bool {
244        match self {
245            ObjectSetValue::Reference(_) => true,
246            ObjectSetValue::Inline(InformationObjectFields::CustomSyntax(c)) => {
247                c.iter().any(|field| field.references_object_set_by_name())
248            }
249            ObjectSetValue::Inline(InformationObjectFields::DefaultSyntax(d)) => {
250                d.iter().any(|field| field.references_object_set_by_name())
251            }
252        }
253    }
254}
255
256impl ObjectSet {
257    pub fn link_object_set_reference(
258        &mut self,
259        tlds: &BTreeMap<String, ToplevelDefinition>,
260    ) -> bool {
261        let mut flattened: Vec<_> = self
262            .values
263            .iter_mut()
264            .flat_map(|val| val.link_object_set_reference(tlds).unwrap_or_default())
265            .collect();
266        self.values.append(&mut flattened);
267        true
268    }
269
270    pub fn references_object_set_by_name(&self) -> bool {
271        self.values
272            .iter()
273            .any(|val| val.references_object_set_by_name())
274    }
275
276    pub fn resolve_object_set_references(
277        &mut self,
278        tlds: &BTreeMap<String, ToplevelDefinition>,
279    ) -> Result<(), GrammarError> {
280        let mut flattened_members = Vec::new();
281        let mut needs_recursing = false;
282        'resolving_references: for mut value in std::mem::take(&mut self.values) {
283            if let ObjectSetValue::Reference(id) = value {
284                match tlds.get(&id) {
285                    Some(ToplevelDefinition::Object(ToplevelInformationDefinition {
286                        value: ASN1Information::ObjectSet(set),
287                        ..
288                    })) => {
289                        set.values
290                            .iter()
291                            .for_each(|v| flattened_members.push(v.clone()));
292                        needs_recursing = true;
293                        continue 'resolving_references;
294                    }
295                    Some(ToplevelDefinition::Object(ToplevelInformationDefinition {
296                        value: ASN1Information::Object(obj),
297                        ..
298                    })) => value = ObjectSetValue::Inline(obj.fields.clone()),
299                    _ => {
300                        return Err(GrammarError::new(
301                            "Failed to resolve reference in object set.",
302                            GrammarErrorType::LinkerError,
303                        ))
304                    }
305                }
306            }
307            flattened_members.push(value)
308        }
309        self.values = flattened_members;
310        if needs_recursing {
311            self.resolve_object_set_references(tlds)
312        } else {
313            Ok(())
314        }
315    }
316}
317
318impl InformationObjectField {
319    pub fn link_object_set_reference(
320        &mut self,
321        tlds: &BTreeMap<String, ToplevelDefinition>,
322    ) -> bool {
323        match self {
324            InformationObjectField::ObjectSetField(ObjectSetField { value, .. }) => {
325                value.link_object_set_reference(tlds)
326            }
327            _ => false,
328        }
329    }
330
331    pub fn references_object_set_by_name(&self) -> bool {
332        match self {
333            InformationObjectField::ObjectSetField(ObjectSetField { value, .. }) => {
334                value.references_object_set_by_name()
335            }
336            _ => false,
337        }
338    }
339}