1mod 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
54pub type UniversalString = Implicit<tag::UNIVERSAL_STRING, Utf8String>;
56pub type UtcTime = chrono::DateTime<chrono::Utc>;
58pub type GeneralizedTime = chrono::DateTime<chrono::FixedOffset>;
60pub type Date = chrono::NaiveDate;
62
63pub trait AsnType {
65 const TAG: Tag;
71 const TAG_TREE: TagTree = TagTree::Leaf(Self::TAG);
74
75 const CONSTRAINTS: Constraints = Constraints::NONE;
77
78 const IDENTIFIER: Identifier = Identifier::EMPTY;
81
82 const IS_CHOICE: bool = false;
84
85 fn is_present(&self) -> bool {
89 true
90 }
91}
92
93pub trait Choice: Sized {
95 const VARIANTS: &'static [TagTree];
97 const VARIANCE_CONSTRAINT: Constraints;
99 const EXTENDED_VARIANTS: Option<&'static [TagTree]> = None;
101 const IDENTIFIERS: &'static [&'static str];
103}
104
105pub trait DecodeChoice: Choice + crate::Decode {
107 fn from_tag<D: crate::Decoder>(decoder: &mut D, tag: Tag) -> Result<Self, D::Error>;
109}
110
111pub trait Enumerated: Sized + 'static + PartialEq + Copy + core::fmt::Debug + AsnType {
113 const VARIANTS: &'static [Self];
115 const EXTENDED_VARIANTS: Option<&'static [Self]>;
117
118 const DISCRIMINANTS: &'static [(Self, isize)];
120 const EXTENDED_DISCRIMINANTS: Option<&'static [(Self, isize)]>;
123
124 const IDENTIFIERS: &'static [&'static str];
126
127 fn variance() -> usize {
129 Self::VARIANTS.len()
130 }
131
132 #[must_use]
134 fn extended_variance() -> usize {
135 Self::EXTENDED_VARIANTS.map_or(0, <[Self]>::len)
136 }
137
138 #[must_use]
140 fn complete_variance() -> usize {
141 Self::variance() + Self::extended_variance()
142 }
143
144 fn is_extended_variant(&self) -> bool {
146 Self::EXTENDED_VARIANTS.is_some_and(|array| array.iter().any(|variant| variant == self))
147 }
148
149 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 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 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 fn from_enumeration_index(index: usize) -> Option<Self> {
193 Self::VARIANTS.get(index).copied()
194 }
195
196 #[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 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 #[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, 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}