asn1rs_model/model/
tag.rs1use crate::model::{Error, PeekableTokens};
2use crate::parser::Token;
3use std::convert::TryFrom;
4use std::iter::Peekable;
5
6#[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 pub const DEFAULT_NUMERIC_STRING: Tag = Tag::Universal(18);
56 pub const DEFAULT_PRINTABLE_STRING: Tag = Tag::Universal(19);
58 pub const DEFAULT_TELETEXT_STRING: Tag = Tag::Universal(20);
60 pub const DEFAULT_VIDEOTEXT_STRING: Tag = Tag::Universal(21);
62 pub const DEFAULT_IA5_STRING: Tag = Tag::Universal(22);
64 pub const DEFAULT_GRAPHIC_STRING: Tag = Tag::Universal(25);
66 pub const DEFAULT_VISIBLE_STRING: Tag = Tag::Universal(26);
68 pub const DEFAULT_GENERAL_STRING: Tag = Tag::Universal(27);
70 pub const DEFAULT_UNIVERSAL_STRING: Tag = Tag::Universal(28);
72 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}