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