asn1_rs/asn1_types/tagged/optional.rs
1use crate::*;
2
3/// Helper object to parse TAGGED OPTIONAL types (explicit or implicit)
4///
5/// This object can be used similarly to a builder pattern, to specify the expected class and
6/// tag of the object to parse, and the content parsing function.
7///
8/// The content parsing function takes two arguments: the outer header, and the data.
9///
10/// It can be used for both EXPLICIT or IMPLICIT tagged objects by using parsing functions that
11/// expect a header (or not) in the contents.
12///
13/// The [`OptTaggedParser::from`] method is a shortcut to build an object with `ContextSpecific`
14/// class and the given tag. The [`OptTaggedParser::new`] method is more generic.
15///
16/// See also [`OptTaggedExplicit`] and [`OptTaggedImplicit`] for alternatives that implement [`FromBer`]/
17/// [`FromDer`].
18///
19/// # Examples
20///
21/// To parse a `[APPLICATION 0] EXPLICIT INTEGER OPTIONAL` object:
22///
23/// ```rust
24/// use asn1_rs::{Class, FromDer, Integer, Tag, OptTaggedParser};
25///
26/// let bytes = &[0x60, 0x03, 0x2, 0x1, 0x2];
27///
28/// let (_, tagged) = OptTaggedParser::new(Class::Application, Tag(0))
29/// .parse_der(bytes, |_, data| Integer::from_der(data))
30/// .unwrap();
31///
32/// assert_eq!(tagged, Some(Integer::from(2)));
33/// ```
34///
35/// To parse a `[0] IMPLICIT INTEGER OPTIONAL` object:
36///
37/// ```rust
38/// use asn1_rs::{Error, Integer, OptTaggedParser};
39///
40/// let bytes = &[0xa0, 0x1, 0x2];
41///
42/// let (_, tagged) = OptTaggedParser::from(0)
43/// .parse_der::<_, Error, _>(bytes, |_, data| Ok((&[], Integer::new(data))))
44/// .unwrap();
45///
46/// assert_eq!(tagged, Some(Integer::from(2)));
47/// ```
48#[derive(Debug)]
49pub struct OptTaggedParser {
50 /// The expected class for the object to parse
51 pub class: Class,
52 /// The expected tag for the object to parse
53 pub tag: Tag,
54}
55
56impl OptTaggedParser {
57 /// Build a new `OptTaggedParser` object.
58 ///
59 /// If using `Class::ContextSpecific`, using [`OptTaggedParser::from`] with either a `Tag` or `u32` is
60 /// a shorter way to build this object.
61 pub const fn new(class: Class, tag: Tag) -> Self {
62 OptTaggedParser { class, tag }
63 }
64
65 pub const fn universal(tag: u32) -> Self {
66 Self::new(Class::Universal, Tag(tag))
67 }
68
69 pub const fn tagged(tag: u32) -> Self {
70 Self::new(Class::ContextSpecific, Tag(tag))
71 }
72
73 pub const fn application(tag: u32) -> Self {
74 Self::new(Class::Application, Tag(tag))
75 }
76
77 pub const fn private(tag: u32) -> Self {
78 Self::new(Class::Private, Tag(tag))
79 }
80
81 /// Parse input as BER, and apply the provided function to parse object.
82 ///
83 /// Returns the remaining bytes, and `Some(T)` if expected tag was found, else `None`.
84 ///
85 /// This function returns an error if tag was found but has a different class, or if parsing fails.
86 ///
87 /// # Examples
88 ///
89 /// To parse a `[0] EXPLICIT INTEGER OPTIONAL` object:
90 ///
91 /// ```rust
92 /// use asn1_rs::{FromBer, Integer, OptTaggedParser};
93 ///
94 /// let bytes = &[0xa0, 0x03, 0x2, 0x1, 0x2];
95 ///
96 /// let (_, tagged) = OptTaggedParser::from(0)
97 /// .parse_ber(bytes, |_, data| Integer::from_ber(data))
98 /// .unwrap();
99 ///
100 /// assert_eq!(tagged, Some(Integer::from(2)));
101 /// ```
102 pub fn parse_ber<'a, T, E, F>(&self, bytes: &'a [u8], f: F) -> ParseResult<'a, Option<T>, E>
103 where
104 F: Fn(Header, &'a [u8]) -> ParseResult<'a, T, E>,
105 E: From<Error>,
106 {
107 if bytes.is_empty() {
108 return Ok((bytes, None));
109 }
110 let (rem, any) = Any::from_ber(bytes).map_err(Err::convert)?;
111 if any.tag() != self.tag {
112 return Ok((bytes, None));
113 }
114 if any.class() != self.class {
115 return Err(Err::Error(
116 Error::unexpected_class(Some(self.class), any.class()).into(),
117 ));
118 }
119 let Any { header, data } = any;
120 let (_, res) = f(header, data)?;
121 Ok((rem, Some(res)))
122 }
123
124 /// Parse input as DER, and apply the provided function to parse object.
125 ///
126 /// Returns the remaining bytes, and `Some(T)` if expected tag was found, else `None`.
127 ///
128 /// This function returns an error if tag was found but has a different class, or if parsing fails.
129 ///
130 /// # Examples
131 ///
132 /// To parse a `[0] EXPLICIT INTEGER OPTIONAL` object:
133 ///
134 /// ```rust
135 /// use asn1_rs::{FromDer, Integer, OptTaggedParser};
136 ///
137 /// let bytes = &[0xa0, 0x03, 0x2, 0x1, 0x2];
138 ///
139 /// let (_, tagged) = OptTaggedParser::from(0)
140 /// .parse_der(bytes, |_, data| Integer::from_der(data))
141 /// .unwrap();
142 ///
143 /// assert_eq!(tagged, Some(Integer::from(2)));
144 /// ```
145 pub fn parse_der<'a, T, E, F>(&self, bytes: &'a [u8], f: F) -> ParseResult<'a, Option<T>, E>
146 where
147 F: Fn(Header, &'a [u8]) -> ParseResult<'a, T, E>,
148 E: From<Error>,
149 {
150 if bytes.is_empty() {
151 return Ok((bytes, None));
152 }
153 let (rem, any) = Any::from_der(bytes).map_err(Err::convert)?;
154 if any.tag() != self.tag {
155 return Ok((bytes, None));
156 }
157 if any.class() != self.class {
158 return Err(Err::Error(
159 Error::unexpected_class(Some(self.class), any.class()).into(),
160 ));
161 }
162 let Any { header, data } = any;
163 let (_, res) = f(header, data)?;
164 Ok((rem, Some(res)))
165 }
166}
167
168impl From<Tag> for OptTaggedParser {
169 /// Build a `TaggedOptional` object with class `ContextSpecific` and given tag
170 #[inline]
171 fn from(tag: Tag) -> Self {
172 OptTaggedParser::new(Class::ContextSpecific, tag)
173 }
174}
175
176impl From<u32> for OptTaggedParser {
177 /// Build a `TaggedOptional` object with class `ContextSpecific` and given tag
178 #[inline]
179 fn from(tag: u32) -> Self {
180 OptTaggedParser::new(Class::ContextSpecific, Tag(tag))
181 }
182}
183
184/// A helper object to parse `[ n ] EXPLICIT T OPTIONAL`
185///
186/// A helper object implementing [`FromBer`] and [`FromDer`], to parse tagged
187/// optional values.
188///
189/// This helper expects context-specific tags.
190/// Use `Option<` [`TaggedValue`] `>` for a more generic implementation.
191///
192/// # Examples
193///
194/// To parse a `[0] EXPLICIT INTEGER OPTIONAL` object:
195///
196/// ```rust
197/// use asn1_rs::{Error, FromBer, Integer, OptTaggedExplicit, TaggedValue};
198///
199/// let bytes = &[0xa0, 0x03, 0x2, 0x1, 0x2];
200///
201/// // If tagged object is present (and has expected tag), parsing succeeds:
202/// let (_, tagged) = OptTaggedExplicit::<Integer, Error, 0>::from_ber(bytes).unwrap();
203/// assert_eq!(tagged, Some(TaggedValue::explicit(Integer::from(2))));
204///
205/// // If tagged object is not present or has different tag, parsing
206/// // also succeeds (returning None):
207/// let (_, tagged) = OptTaggedExplicit::<Integer, Error, 0>::from_ber(&[]).unwrap();
208/// assert_eq!(tagged, None);
209/// let (_, tagged) = OptTaggedExplicit::<Integer, Error, 1>::from_ber(bytes).unwrap();
210/// assert_eq!(tagged, None);
211/// ```
212pub type OptTaggedExplicit<T, E, const TAG: u32> = Option<TaggedExplicit<T, E, TAG>>;
213
214/// A helper object to parse `[ n ] IMPLICIT T OPTIONAL`
215///
216/// A helper object implementing [`FromBer`] and [`FromDer`], to parse tagged
217/// optional values.
218///
219/// This helper expects context-specific tags.
220/// Use `Option<` [`TaggedValue`] `>` for a more generic implementation.
221///
222/// # Examples
223///
224/// To parse a `[0] IMPLICIT INTEGER OPTIONAL` object:
225///
226/// ```rust
227/// use asn1_rs::{Error, FromBer, Integer, OptTaggedImplicit, TaggedValue};
228///
229/// let bytes = &[0xa0, 0x1, 0x2];
230///
231/// let (_, tagged) = OptTaggedImplicit::<Integer, Error, 0>::from_ber(bytes).unwrap();
232/// assert_eq!(tagged, Some(TaggedValue::implicit(Integer::from(2))));
233///
234/// // If tagged object is not present or has different tag, parsing
235/// // also succeeds (returning None):
236/// let (_, tagged) = OptTaggedImplicit::<Integer, Error, 0>::from_ber(&[]).unwrap();
237/// assert_eq!(tagged, None);
238/// ```
239pub type OptTaggedImplicit<T, E, const TAG: u32> = Option<TaggedImplicit<T, E, TAG>>;