asn1rs_model/model/
enumerated.rs

1use crate::model::{Error, PeekableTokens};
2use crate::parser::Token;
3use std::convert::TryFrom;
4use std::iter::Peekable;
5
6#[derive(Debug, Clone, PartialOrd, PartialEq, Eq)]
7pub struct Enumerated {
8    variants: Vec<EnumeratedVariant>,
9    extension_after: Option<usize>,
10}
11
12impl From<Vec<EnumeratedVariant>> for Enumerated {
13    fn from(variants: Vec<EnumeratedVariant>) -> Self {
14        Self {
15            variants,
16            extension_after: None,
17        }
18    }
19}
20
21impl Enumerated {
22    pub fn from_variants(variants: impl Into<Vec<EnumeratedVariant>>) -> Self {
23        Self {
24            variants: variants.into(),
25            extension_after: None,
26        }
27    }
28
29    pub fn from_names<I: ToString>(variants: impl Iterator<Item = I>) -> Self {
30        Self {
31            variants: variants.map(EnumeratedVariant::from_name).collect(),
32            extension_after: None,
33        }
34    }
35
36    pub const fn with_extension_after(mut self, extension_after: usize) -> Self {
37        self.extension_after = Some(extension_after);
38        self
39    }
40
41    pub const fn with_maybe_extension_after(mut self, extension_after: Option<usize>) -> Self {
42        self.extension_after = extension_after;
43        self
44    }
45
46    pub fn len(&self) -> usize {
47        self.variants.len()
48    }
49
50    pub fn is_empty(&self) -> bool {
51        self.variants.is_empty()
52    }
53
54    pub fn variants(&self) -> impl Iterator<Item = &EnumeratedVariant> {
55        self.variants.iter()
56    }
57
58    pub fn is_extensible(&self) -> bool {
59        self.extension_after.is_some()
60    }
61
62    pub fn extension_after_index(&self) -> Option<usize> {
63        self.extension_after
64    }
65}
66
67impl<T: Iterator<Item = Token>> TryFrom<&mut Peekable<T>> for Enumerated {
68    type Error = Error;
69
70    fn try_from(iter: &mut Peekable<T>) -> Result<Self, Self::Error> {
71        iter.next_separator_eq_or_err('{')?;
72        let mut enumerated = Self {
73            variants: Vec::new(),
74            extension_after: None,
75        };
76
77        loop {
78            if let Ok(extension_marker) = iter.next_if_separator_and_eq('.') {
79                if enumerated.variants.is_empty() || enumerated.extension_after.is_some() {
80                    return Err(Error::invalid_position_for_extension_marker(
81                        extension_marker,
82                    ));
83                } else {
84                    iter.next_separator_eq_or_err('.')?;
85                    iter.next_separator_eq_or_err('.')?;
86                    enumerated.extension_after = Some(enumerated.variants.len() - 1);
87                    loop_ctrl_separator!(iter.next_or_err()?);
88                }
89            } else {
90                let variant_name = iter.next_text_or_err()?;
91                let token = iter.next_or_err()?;
92
93                if token.eq_separator(',') || token.eq_separator('}') {
94                    enumerated
95                        .variants
96                        .push(EnumeratedVariant::from_name(variant_name));
97                    loop_ctrl_separator!(token);
98                } else if token.eq_separator('(') {
99                    let token = iter.next_or_err()?;
100                    let number = token
101                        .text()
102                        .and_then(|t| t.parse::<usize>().ok())
103                        .ok_or_else(|| Error::invalid_number_for_enum_variant(token))?;
104                    iter.next_separator_eq_or_err(')')?;
105                    enumerated
106                        .variants
107                        .push(EnumeratedVariant::from_name_number(variant_name, number));
108                    loop_ctrl_separator!(iter.next_or_err()?);
109                } else {
110                    loop_ctrl_separator!(token);
111                }
112            }
113        }
114
115        Ok(enumerated)
116    }
117}
118
119#[derive(Debug, Clone, PartialOrd, PartialEq, Eq)]
120pub struct EnumeratedVariant {
121    pub(crate) name: String,
122    pub(crate) number: Option<usize>,
123}
124
125#[cfg(test)]
126impl<S: ToString> From<S> for EnumeratedVariant {
127    fn from(s: S) -> Self {
128        EnumeratedVariant::from_name(s)
129    }
130}
131
132impl EnumeratedVariant {
133    pub fn from_name<I: ToString>(name: I) -> Self {
134        Self {
135            name: name.to_string(),
136            number: None,
137        }
138    }
139
140    pub fn from_name_number<I: ToString>(name: I, number: usize) -> Self {
141        Self {
142            name: name.to_string(),
143            number: Some(number),
144        }
145    }
146
147    pub const fn with_number(self, number: usize) -> Self {
148        self.with_number_opt(Some(number))
149    }
150
151    pub const fn with_number_opt(mut self, number: Option<usize>) -> Self {
152        self.number = number;
153        self
154    }
155
156    pub fn name(&self) -> &str {
157        &self.name
158    }
159
160    pub fn number(&self) -> Option<usize> {
161        self.number
162    }
163}