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