asn1rs_model/model/
choice.rs1use 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}