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