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>>;