Skip to main content

asn1rs_model/model/
choice.rs

1use crate::model::lor::{Error as ResolveError, ResolveState, Resolved, Resolver, Unresolved};
2use crate::model::{Asn, Error, Model, PeekableTokens, Tag, TagProperty, Type};
3use crate::parser::Token;
4use std::convert::TryFrom;
5
6use std::iter::Peekable;
7
8#[derive(Debug, Clone, PartialOrd, PartialEq)]
9pub struct Choice<RS: ResolveState = Resolved> {
10    variants: Vec<ChoiceVariant<RS>>,
11    extension_after: Option<usize>,
12}
13
14impl<RS: ResolveState> From<Vec<ChoiceVariant<RS>>> for Choice<RS> {
15    fn from(variants: Vec<ChoiceVariant<RS>>) -> Self {
16        Self {
17            variants,
18            extension_after: None,
19        }
20    }
21}
22
23impl<RS: ResolveState> Choice<RS> {
24    pub fn from_variants(variants: impl Iterator<Item = ChoiceVariant<RS>>) -> Self {
25        Self {
26            variants: variants.collect(),
27            extension_after: None,
28        }
29    }
30
31    pub fn with_extension_after(mut self, extension_after: usize) -> Self {
32        self.extension_after = Some(extension_after);
33        self
34    }
35
36    pub fn with_maybe_extension_after(mut self, extension_after: Option<usize>) -> Self {
37        self.extension_after = extension_after;
38        self
39    }
40
41    pub fn len(&self) -> usize {
42        self.variants.len()
43    }
44
45    pub fn is_empty(&self) -> bool {
46        self.variants.is_empty()
47    }
48
49    pub fn variants(&self) -> impl Iterator<Item = &ChoiceVariant<RS>> {
50        self.variants.iter()
51    }
52
53    pub fn is_extensible(&self) -> bool {
54        self.extension_after.is_some()
55    }
56
57    pub fn extension_after_index(&self) -> Option<usize> {
58        self.extension_after
59    }
60}
61
62impl<T: Iterator<Item = Token>> TryFrom<&mut Peekable<T>> for Choice<Unresolved> {
63    type Error = Error;
64
65    fn try_from(iter: &mut Peekable<T>) -> Result<Self, Self::Error> {
66        iter.next_separator_eq_or_err('{')?;
67        let mut choice = Choice {
68            variants: Vec::new(),
69            extension_after: None,
70        };
71
72        loop {
73            if let Ok(extension_marker) = iter.next_if_separator_and_eq('.') {
74                if choice.variants.is_empty() || choice.extension_after.is_some() {
75                    return Err(Error::invalid_position_for_extension_marker(
76                        extension_marker,
77                    ));
78                } else {
79                    iter.next_separator_eq_or_err('.')?;
80                    iter.next_separator_eq_or_err('.')?;
81                    choice.extension_after = Some(choice.variants.len() - 1);
82                }
83            } else {
84                let name = iter.next_text_or_err()?;
85                let (token, tag) = Model::<Asn<Unresolved>>::next_with_opt_tag(iter)?;
86                let r#type = Model::<Asn<Unresolved>>::read_role_given_text(
87                    iter,
88                    token.into_text_or_else(Error::no_text)?,
89                )?;
90                choice.variants.push(ChoiceVariant { name, tag, r#type });
91            }
92
93            loop_ctrl_separator!(iter.next_or_err()?);
94        }
95
96        Ok(choice)
97    }
98}
99
100impl Choice<Unresolved> {
101    pub fn try_resolve<
102        R: Resolver<<Resolved as ResolveState>::SizeType>
103            + Resolver<<Resolved as ResolveState>::RangeType>
104            + Resolver<<Resolved as ResolveState>::ConstType>
105            + Resolver<Type<Unresolved>>,
106    >(
107        &self,
108        resolver: &R,
109    ) -> Result<Choice<Resolved>, ResolveError> {
110        Ok(Choice {
111            variants: self
112                .variants
113                .iter()
114                .map(|v| v.try_resolve(resolver))
115                .collect::<Result<Vec<_>, _>>()?,
116            extension_after: self.extension_after,
117        })
118    }
119}
120
121#[derive(Debug, Clone, PartialOrd, PartialEq)]
122pub struct ChoiceVariant<RS: ResolveState = Resolved> {
123    pub name: String,
124    pub tag: Option<Tag>,
125    pub r#type: Type<RS>,
126}
127
128impl<RS: ResolveState> ChoiceVariant<RS> {
129    #[cfg(test)]
130    pub fn name_type<I: ToString>(name: I, r#type: Type<RS>) -> Self {
131        ChoiceVariant {
132            name: name.to_string(),
133            tag: None,
134            r#type,
135        }
136    }
137
138    pub fn name(&self) -> &str {
139        &self.name
140    }
141
142    pub fn r#type(&self) -> &Type<RS> {
143        &self.r#type
144    }
145}
146
147impl<RS: ResolveState> TagProperty for ChoiceVariant<RS> {
148    fn tag(&self) -> Option<Tag> {
149        self.tag
150    }
151
152    fn set_tag(&mut self, tag: Tag) {
153        self.tag = Some(tag)
154    }
155
156    fn reset_tag(&mut self) {
157        self.tag = None
158    }
159}
160
161impl ChoiceVariant<Unresolved> {
162    pub fn try_resolve<
163        R: Resolver<<Resolved as ResolveState>::SizeType>
164            + Resolver<<Resolved as ResolveState>::RangeType>
165            + Resolver<<Resolved as ResolveState>::ConstType>
166            + Resolver<Type<Unresolved>>,
167    >(
168        &self,
169        resolver: &R,
170    ) -> Result<ChoiceVariant<Resolved>, ResolveError> {
171        Ok(ChoiceVariant {
172            name: self.name.clone(),
173            tag: self.tag,
174            r#type: self.r#type.try_resolve(resolver)?,
175        })
176    }
177}
178
179#[cfg(test)]
180mod tests {
181    use super::*;
182    use crate::model::tag::tests::test_property;
183
184    #[test]
185    pub fn test_tag_property_choice_variant() {
186        test_property(ChoiceVariant::<Resolved>::name_type(
187            "VariantName".to_string(),
188            Type::Boolean,
189        ));
190    }
191}