Skip to main content

asn1rs_model/model/
tag.rs

1use crate::model::{Error, PeekableTokens};
2use crate::parser::Token;
3use std::convert::TryFrom;
4use std::iter::Peekable;
5
6///ITU-T X.680 | ISO/IEC 8824-1, chapter 8
7///
8/// # Ordering
9/// According to ITU-T X.680 | ISO/IEC 8824-1, 8.6, the canonical order is
10/// a) Universal, Application, ContextSpecific and Private and
11/// b) within each class, the numbers shall be ordered ascending
12///
13/// ```rust
14/// use asn1rs_model::model::Tag;
15/// let mut tags = vec![
16///     Tag::Universal(1),
17///     Tag::Application(0),
18///     Tag::Private(7),
19///     Tag::ContextSpecific(107),
20///     Tag::ContextSpecific(32),
21///     Tag::Universal(0),
22/// ];
23/// tags.sort();
24/// assert_eq!(tags, vec![
25///     Tag::Universal(0),
26///     Tag::Universal(1),
27///     Tag::Application(0),
28///     Tag::ContextSpecific(32),
29///     Tag::ContextSpecific(107),
30///     Tag::Private(7),
31/// ]);
32/// ```
33#[derive(Debug, Clone, Copy, PartialOrd, PartialEq, Ord, Eq, Hash)]
34pub enum Tag {
35    Universal(usize),
36    Application(usize),
37    ContextSpecific(usize),
38    Private(usize),
39}
40
41impl Tag {
42    pub const DEFAULT_BOOLEAN: Tag = Tag::Universal(1);
43    pub const DEFAULT_INTEGER: Tag = Tag::Universal(2);
44    pub const DEFAULT_BIT_STRING: Tag = Tag::Universal(3);
45    pub const DEFAULT_OCTET_STRING: Tag = Tag::Universal(4);
46    pub const DEFAULT_NULL: Tag = Tag::Universal(5);
47    pub const DEFAULT_ENUMERATED: Tag = Tag::Universal(10);
48    pub const DEFAULT_UTF8_STRING: Tag = Tag::Universal(12);
49    pub const DEFAULT_SEQUENCE: Tag = Tag::Universal(16);
50    pub const DEFAULT_SEQUENCE_OF: Tag = Tag::Universal(16);
51    pub const DEFAULT_SET: Tag = Tag::Universal(17);
52    pub const DEFAULT_SET_OF: Tag = Tag::Universal(17);
53
54    /// ITU-T Rec. X.680, 41
55    pub const DEFAULT_NUMERIC_STRING: Tag = Tag::Universal(18);
56    /// ITU-T Rec. X.680, 41
57    pub const DEFAULT_PRINTABLE_STRING: Tag = Tag::Universal(19);
58    /// ITU-T Rec. X.680, 41
59    pub const DEFAULT_TELETEXT_STRING: Tag = Tag::Universal(20);
60    /// ITU-T Rec. X.680, 41
61    pub const DEFAULT_VIDEOTEXT_STRING: Tag = Tag::Universal(21);
62    /// ITU-T Rec. X.680, 41
63    pub const DEFAULT_IA5_STRING: Tag = Tag::Universal(22);
64    /// ITU-T Rec. X.680, 41
65    pub const DEFAULT_GRAPHIC_STRING: Tag = Tag::Universal(25);
66    /// ITU-T Rec. X.680, 41
67    pub const DEFAULT_VISIBLE_STRING: Tag = Tag::Universal(26);
68    /// ITU-T Rec. X.680, 41
69    pub const DEFAULT_GENERAL_STRING: Tag = Tag::Universal(27);
70    /// ITU-T Rec. X.680, 41
71    pub const DEFAULT_UNIVERSAL_STRING: Tag = Tag::Universal(28);
72    /// ITU-T Rec. X.680, 41
73    pub const DEFAULT_BMP_STRING: Tag = Tag::Universal(30);
74}
75
76impl<T: Iterator<Item = Token>> TryFrom<&mut Peekable<T>> for Tag {
77    type Error = Error;
78
79    fn try_from(iter: &mut Peekable<T>) -> Result<Self, Self::Error> {
80        macro_rules! parse_tag_number {
81            () => {
82                parse_tag_number!(iter.next_or_err()?)
83            };
84            ($tag:expr) => {{
85                let tag = $tag;
86                tag.text()
87                    .and_then(|t| t.parse().ok())
88                    .ok_or_else(|| Error::invalid_tag(tag))?
89            }};
90        }
91
92        Ok(match iter.next_or_err()? {
93            t if t.eq_text_ignore_ascii_case("UNIVERSAL") => Tag::Universal(parse_tag_number!()),
94            t if t.eq_text_ignore_ascii_case("APPLICATION") => {
95                Tag::Application(parse_tag_number!())
96            }
97            t if t.eq_text_ignore_ascii_case("PRIVATE") => Tag::Private(parse_tag_number!()),
98            t if t.text().is_some() => Tag::ContextSpecific(parse_tag_number!(t)),
99            t => return Err(Error::no_text(t)),
100        })
101    }
102}
103
104pub trait TagProperty {
105    fn tag(&self) -> Option<Tag>;
106
107    fn set_tag(&mut self, tag: Tag);
108
109    fn reset_tag(&mut self);
110
111    fn with_tag_opt(self, tag: Option<Tag>) -> Self
112    where
113        Self: Sized,
114    {
115        if let Some(tag) = tag {
116            self.with_tag(tag)
117        } else {
118            self.without_tag()
119        }
120    }
121
122    fn with_tag(mut self, tag: Tag) -> Self
123    where
124        Self: Sized,
125    {
126        self.set_tag(tag);
127        self
128    }
129
130    fn without_tag(mut self) -> Self
131    where
132        Self: Sized,
133    {
134        self.reset_tag();
135        self
136    }
137}
138
139#[cfg(test)]
140pub(crate) mod tests {
141    use super::*;
142
143    pub(crate) fn test_property<T: TagProperty>(mut property: T)
144    where
145        T: Sized,
146    {
147        property.set_tag(Tag::Universal(22));
148        assert_eq!(Some(Tag::Universal(22)), property.tag());
149
150        property.reset_tag();
151        assert_eq!(None, property.tag());
152
153        let property = property.with_tag_opt(Some(Tag::Application(1337)));
154        assert_eq!(Some(Tag::Application(1337)), property.tag());
155
156        let property = property.without_tag();
157        assert_eq!(None, property.tag());
158
159        let property = property.with_tag(Tag::Private(42));
160        assert_eq!(Some(Tag::Private(42)), property.tag());
161    }
162}