Skip to main content

rasn/
types.rs

1//! # ASN.1 Data Types
2//! The `types` modules is a collection of Rust types and data structures that
3//! are defined to represent various ASN.1 data types, and renamed to use
4//! ASN.1's terminology.
5
6mod any;
7mod identifier;
8mod instance;
9mod json;
10mod open;
11mod prefix;
12mod tag;
13
14pub mod constraints;
15pub mod fields;
16pub mod variants;
17
18pub(crate) mod constructed;
19pub(crate) mod date;
20pub(crate) mod integer;
21pub(crate) mod oid;
22
23pub(crate) mod real;
24
25pub(crate) mod strings;
26
27use crate::macros::constraints;
28use alloc::borrow::{Cow, ToOwned};
29use alloc::boxed::Box;
30
31pub use {
32    self::{
33        any::Any,
34        constraints::{Constraint, Constraints, Extensible, InnerSubtypeConstraint},
35        constructed::{Constructed, SequenceOf, SetOf},
36        identifier::Identifier,
37        instance::InstanceOf,
38        integer::{ConstrainedInteger, Integer, IntegerType},
39        oid::{ObjectIdentifier, Oid},
40        open::Open,
41        prefix::{Explicit, Implicit},
42        strings::{
43            BitStr, BitString, BmpString, FixedBitString, FixedOctetString, GeneralString,
44            GraphicString, Ia5String, NumericString, OctetString, PrintableString, TeletexString,
45            Utf8String, VisibleString,
46        },
47        tag::{Class, Tag, TagTree},
48    },
49    rasn_derive::AsnType,
50};
51
52pub use self::real::RealType;
53
54///  The `UniversalString` type.
55pub type UniversalString = Implicit<tag::UNIVERSAL_STRING, Utf8String>;
56///  The `UTCTime` type.
57pub type UtcTime = chrono::DateTime<chrono::Utc>;
58///  The `GeneralizedTime` type.
59pub type GeneralizedTime = chrono::DateTime<chrono::FixedOffset>;
60/// The `Date` type.
61pub type Date = chrono::NaiveDate;
62
63/// A trait representing any type that can represented in ASN.1.
64pub trait AsnType {
65    /// The associated tag for the type.
66    ///
67    /// **Note** When implementing CHOICE types, this should be set to
68    /// [`Tag::EOC`] and instead set the [`Self::TAG_TREE`] constant to contain
69    /// all variants.
70    const TAG: Tag;
71    /// The root of this type's tree of tag's if it a CHOICE type, otherwise its
72    /// `Leaf` that points [`Self::TAG`].
73    const TAG_TREE: TagTree = TagTree::Leaf(Self::TAG);
74
75    /// The set of constraints for values of the given type.
76    const CONSTRAINTS: Constraints = Constraints::NONE;
77
78    /// Identifier of an ASN.1 type as specified in the original specification
79    /// if not identical with the identifier of `Self`
80    const IDENTIFIER: Identifier = Identifier::EMPTY;
81
82    /// Whether the type is choice type. PER/OER encoding rules require this knowledge.
83    const IS_CHOICE: bool = false;
84
85    /// Whether the type is present with value. `OPTIONAL` fields are common in `SEQUENCE` or `SET`.
86    ///
87    /// Custom implementation is only used for `OPTIONAL` type.
88    fn is_present(&self) -> bool {
89        true
90    }
91}
92
93/// A `CHOICE` value.
94pub trait Choice: Sized {
95    /// Variants contained in the "root component list".
96    const VARIANTS: &'static [TagTree];
97    /// Constraint for the choice type, based on the number of root components. Used for PER encoding.
98    const VARIANCE_CONSTRAINT: Constraints;
99    /// Variants contained in the list of extensions.
100    const EXTENDED_VARIANTS: Option<&'static [TagTree]> = None;
101    /// Variant identifiers for text-based encoding rules
102    const IDENTIFIERS: &'static [&'static str];
103}
104
105/// A `CHOICE` value.
106pub trait DecodeChoice: Choice + crate::Decode {
107    /// Decode the choice value based on the provided `tag`.
108    fn from_tag<D: crate::Decoder>(decoder: &mut D, tag: Tag) -> Result<Self, D::Error>;
109}
110
111/// A `ENUMERATED` value.
112pub trait Enumerated: Sized + 'static + PartialEq + Copy + core::fmt::Debug + AsnType {
113    /// Variants contained in the "root component list".
114    const VARIANTS: &'static [Self];
115    /// Variants contained in the list of extensions.
116    const EXTENDED_VARIANTS: Option<&'static [Self]>;
117
118    /// Variants contained in the "root component list" mapped to their respective discriminant.
119    const DISCRIMINANTS: &'static [(Self, isize)];
120    /// Variants contained in the list of extensions mapped to their respective discriminant, if
121    /// present.
122    const EXTENDED_DISCRIMINANTS: Option<&'static [(Self, isize)]>;
123
124    /// Identifiers of enum variants
125    const IDENTIFIERS: &'static [&'static str];
126
127    /// Returns the number of "root" variants for a given type.
128    fn variance() -> usize {
129        Self::VARIANTS.len()
130    }
131
132    /// Returns the number of "extended" variants for a given type.
133    #[must_use]
134    fn extended_variance() -> usize {
135        Self::EXTENDED_VARIANTS.map_or(0, <[Self]>::len)
136    }
137
138    /// Returns the number of "root" and "extended" variants for a given type.
139    #[must_use]
140    fn complete_variance() -> usize {
141        Self::variance() + Self::extended_variance()
142    }
143
144    /// Whether `self` is a variant contained in `Self::EXTENDED_VARIANTS`.
145    fn is_extended_variant(&self) -> bool {
146        Self::EXTENDED_VARIANTS.is_some_and(|array| array.iter().any(|variant| variant == self))
147    }
148
149    /// Returns the enumeration for the variant, if it's an extended variant
150    /// then it will return it's extended enumeration index.
151    fn enumeration_index(&self) -> usize {
152        if self.is_extended_variant() {
153            Self::EXTENDED_VARIANTS
154                .unwrap()
155                .iter()
156                .position(|lhs| lhs == self)
157                .unwrap()
158        } else {
159            Self::VARIANTS
160                .iter()
161                .position(|lhs| lhs == self)
162                .expect("Variant not defined in Enumerated::VARIANTS")
163        }
164    }
165
166    /// Returns the discriminant value of `self`.
167    fn discriminant(&self) -> isize {
168        Self::DISCRIMINANTS
169            .iter()
170            .chain(
171                Self::EXTENDED_DISCRIMINANTS
172                    .iter()
173                    .flat_map(|array| array.iter()),
174            )
175            .find_map(|(lhs, value)| (lhs == self).then_some(*value))
176            .expect("variant not defined in `Enumerated`")
177    }
178
179    /// Returns a variant, if the provided discriminant matches any variant.
180    fn from_discriminant(value: isize) -> Option<Self> {
181        Self::DISCRIMINANTS
182            .iter()
183            .chain(
184                Self::EXTENDED_DISCRIMINANTS
185                    .iter()
186                    .flat_map(|array| array.iter()),
187            )
188            .find_map(|(variant, discriminant)| (value == *discriminant).then_some(*variant))
189    }
190
191    /// Returns a variant, if the index matches any "root" variant.
192    fn from_enumeration_index(index: usize) -> Option<Self> {
193        Self::VARIANTS.get(index).copied()
194    }
195
196    /// Returns a variant, if the index matches any "extended" variant.
197    #[must_use]
198    fn from_extended_enumeration_index(index: usize) -> Option<Self> {
199        Self::EXTENDED_VARIANTS.and_then(|array| array.get(index).copied())
200    }
201
202    /// Returns the variant identifier
203    fn identifier(&self) -> &'static str {
204        let index = if self.is_extended_variant() {
205            Self::EXTENDED_VARIANTS
206                .unwrap()
207                .iter()
208                .position(|lhs| lhs == self)
209                .unwrap()
210                + Self::VARIANTS.len()
211        } else {
212            Self::VARIANTS
213                .iter()
214                .position(|lhs| lhs == self)
215                .expect("Variant not defined in Enumerated::VARIANTS")
216        };
217        Self::IDENTIFIERS[index]
218    }
219
220    /// Returns a variant, if the provided identifier matches any variant.
221    #[must_use]
222    fn from_identifier(identifier: &str) -> Option<Self> {
223        Self::IDENTIFIERS
224            .iter()
225            .enumerate()
226            .find(|id| id.1.eq(&identifier))
227            .and_then(|(i, _)| {
228                if i < Self::VARIANTS.len() {
229                    Self::VARIANTS.get(i).copied()
230                } else {
231                    Self::EXTENDED_VARIANTS
232                        .and_then(|array| array.get(i - Self::VARIANTS.len()).copied())
233                }
234            })
235    }
236}
237
238macro_rules! asn_type {
239    ($($name:ty: $value:ident),+) => {
240        $(
241            impl AsnType for $name {
242                const TAG: Tag = Tag::$value;
243                const IDENTIFIER: Identifier = Identifier::$value;
244            }
245        )+
246    }
247}
248
249asn_type! {
250    bool: BOOL,
251    Integer: INTEGER,
252    OctetString: OCTET_STRING,
253    ObjectIdentifier: OBJECT_IDENTIFIER,
254    Oid: OBJECT_IDENTIFIER,
255    Utf8String: UTF8_STRING,
256    UtcTime: UTC_TIME,
257    GeneralizedTime: GENERALIZED_TIME,
258    (): NULL,
259    &'_ str: UTF8_STRING
260
261}
262
263macro_rules! asn_integer_type {
264    ($($int:ty),+ $(,)?) => {
265        $(
266            impl AsnType for $int {
267                const TAG: Tag = Tag::INTEGER;
268                const IDENTIFIER: Identifier = Identifier::INTEGER;
269                #[allow(clippy::cast_possible_wrap)]
270                const CONSTRAINTS: Constraints = constraints!(value_constraint!((<$int>::MIN as i128), (<$int>::MAX as i128)));
271            }
272        )+
273    }
274}
275
276asn_integer_type! {
277    i8,
278    i16,
279    i32,
280    i64,
281    i128,
282    isize,
283    u8,
284    u16,
285    u32,
286    u64,
287    u128, // TODO upper constraint truncated
288    usize,
289}
290impl AsnType for num_bigint::BigInt {
291    const TAG: Tag = Tag::INTEGER;
292    const IDENTIFIER: Identifier = Identifier::INTEGER;
293}
294
295impl AsnType for str {
296    const TAG: Tag = Tag::UTF8_STRING;
297    const IDENTIFIER: Identifier = Identifier::UTF8_STRING;
298}
299
300impl<T: AsnType> AsnType for &'_ T {
301    const TAG: Tag = T::TAG;
302    const TAG_TREE: TagTree = T::TAG_TREE;
303    const IDENTIFIER: Identifier = T::IDENTIFIER;
304
305    fn is_present(&self) -> bool {
306        (*self).is_present()
307    }
308}
309
310impl<T: AsnType> AsnType for Box<T> {
311    const TAG: Tag = T::TAG;
312    const TAG_TREE: TagTree = T::TAG_TREE;
313    const IDENTIFIER: Identifier = T::IDENTIFIER;
314}
315
316impl<'a, T: 'a + ToOwned + AsnType> AsnType for Cow<'a, T> {
317    const TAG: Tag = T::TAG;
318    const TAG_TREE: TagTree = T::TAG_TREE;
319    const IDENTIFIER: Identifier = T::IDENTIFIER;
320}
321
322impl<T: AsnType> AsnType for alloc::vec::Vec<T> {
323    const TAG: Tag = Tag::SEQUENCE;
324    const IDENTIFIER: Identifier = Identifier::SEQUENCE_OF;
325}
326
327impl<T: AsnType> AsnType for Option<T> {
328    const TAG: Tag = T::TAG;
329    const TAG_TREE: TagTree = T::TAG_TREE;
330    const IDENTIFIER: Identifier = T::IDENTIFIER;
331
332    fn is_present(&self) -> bool {
333        self.is_some()
334    }
335}
336
337impl<T> AsnType for SetOf<T> {
338    const TAG: Tag = Tag::SET;
339    const IDENTIFIER: Identifier = Identifier::SET_OF;
340}
341
342impl<T: AsnType, const N: usize> AsnType for [T; N] {
343    const TAG: Tag = Tag::SEQUENCE;
344    const CONSTRAINTS: Constraints = constraints!(size_constraint!(N));
345    const IDENTIFIER: Identifier = Identifier::SEQUENCE_OF;
346}
347
348impl<T> AsnType for &'_ [T] {
349    const TAG: Tag = Tag::SEQUENCE;
350    const IDENTIFIER: Identifier = Identifier::SEQUENCE_OF;
351}
352
353impl AsnType for Any {
354    const TAG: Tag = Tag::EOC;
355    const TAG_TREE: TagTree = TagTree::Choice(&[]);
356}
357
358#[cfg(feature = "f32")]
359impl AsnType for f32 {
360    const TAG: Tag = Tag::REAL;
361    const IDENTIFIER: Identifier = Identifier::REAL;
362}
363
364#[cfg(feature = "f64")]
365impl AsnType for f64 {
366    const TAG: Tag = Tag::REAL;
367    const IDENTIFIER: Identifier = Identifier::REAL;
368}
369
370impl<T> AsnType for core::marker::PhantomData<T> {
371    const TAG: Tag = Tag::NULL;
372    const TAG_TREE: TagTree = TagTree::Leaf(Tag::NULL);
373}