mod any;
mod instance;
mod open;
mod prefix;
mod tag;
pub mod constraints;
pub mod fields;
pub mod variants;
pub(crate) mod constructed;
pub(crate) mod date;
pub(crate) mod integer;
pub(crate) mod oid;
pub(crate) mod strings;
use crate::macros::{constraints, size_constraint, value_constraint};
use alloc::boxed::Box;
pub use {
self::{
any::Any,
constraints::{Constraint, Constraints, Extensible},
constructed::{Constructed, SequenceOf, SetOf},
instance::InstanceOf,
integer::{ConstrainedInteger, Integer, IntegerType},
oid::{ObjectIdentifier, Oid},
open::Open,
prefix::{Explicit, Implicit},
strings::{
BitStr, BitString, BmpString, FixedBitString, FixedOctetString, GeneralString,
Ia5String, NumericString, OctetString, PrintableString, TeletexString, Utf8String,
VisibleString,
},
tag::{Class, Tag, TagTree},
},
rasn_derive::AsnType,
};
pub type UniversalString = Implicit<tag::UNIVERSAL_STRING, Utf8String>;
pub type UtcTime = chrono::DateTime<chrono::Utc>;
pub type GeneralizedTime = chrono::DateTime<chrono::FixedOffset>;
pub type Date = chrono::NaiveDate;
pub trait AsnType {
const TAG: Tag;
const TAG_TREE: TagTree = TagTree::Leaf(Self::TAG);
const CONSTRAINTS: Constraints = Constraints::NONE;
const IDENTIFIER: Option<&'static str> = None;
fn is_present(&self) -> bool {
true
}
}
pub trait Choice: Sized {
const VARIANTS: &'static [TagTree];
const VARIANCE_CONSTRAINT: Constraints;
const EXTENDED_VARIANTS: Option<&'static [TagTree]> = None;
const IDENTIFIERS: &'static [&'static str];
}
pub trait DecodeChoice: Choice + crate::Decode {
fn from_tag<D: crate::Decoder>(decoder: &mut D, tag: Tag) -> Result<Self, D::Error>;
}
pub trait Enumerated: Sized + 'static + PartialEq + Copy + core::fmt::Debug {
const VARIANTS: &'static [Self];
const EXTENDED_VARIANTS: Option<&'static [Self]>;
const DISCRIMINANTS: &'static [(Self, isize)];
const EXTENDED_DISCRIMINANTS: Option<&'static [(Self, isize)]>;
const IDENTIFIERS: &'static [&'static str];
fn variance() -> usize {
Self::VARIANTS.len()
}
fn extended_variance() -> usize {
Self::EXTENDED_VARIANTS.map_or(0, |array| array.len())
}
fn complete_variance() -> usize {
Self::variance() + Self::extended_variance()
}
fn is_extended_variant(&self) -> bool {
Self::EXTENDED_VARIANTS.is_some_and(|array| array.iter().any(|variant| variant == self))
}
fn enumeration_index(&self) -> usize {
if self.is_extended_variant() {
Self::EXTENDED_VARIANTS
.unwrap()
.iter()
.position(|lhs| lhs == self)
.unwrap()
} else {
Self::VARIANTS
.iter()
.position(|lhs| lhs == self)
.expect("Variant not defined in Enumerated::VARIANTS")
}
}
fn discriminant(&self) -> isize {
Self::DISCRIMINANTS
.iter()
.chain(
Self::EXTENDED_DISCRIMINANTS
.iter()
.flat_map(|array| array.iter()),
)
.find_map(|(lhs, value)| (lhs == self).then_some(*value))
.expect("variant not defined in `Enumerated`")
}
fn from_discriminant(value: isize) -> Option<Self> {
Self::DISCRIMINANTS
.iter()
.chain(
Self::EXTENDED_DISCRIMINANTS
.iter()
.flat_map(|array| array.iter()),
)
.find_map(|(variant, discriminant)| (value == *discriminant).then_some(*variant))
}
fn from_enumeration_index(index: usize) -> Option<Self> {
Self::VARIANTS.get(index).copied()
}
fn from_extended_enumeration_index(index: usize) -> Option<Self> {
Self::EXTENDED_VARIANTS.and_then(|array| array.get(index).copied())
}
fn identifier(&self) -> &'static str {
let index = if self.is_extended_variant() {
Self::EXTENDED_VARIANTS
.unwrap()
.iter()
.position(|lhs| lhs == self)
.unwrap()
+ Self::VARIANTS.len()
} else {
Self::VARIANTS
.iter()
.position(|lhs| lhs == self)
.expect("Variant not defined in Enumerated::VARIANTS")
};
Self::IDENTIFIERS[index]
}
fn from_identifier(identifier: &str) -> Option<Self> {
Self::IDENTIFIERS
.iter()
.enumerate()
.find(|id| id.1.eq(&identifier))
.and_then(|(i, _)| {
if i < Self::VARIANTS.len() {
Self::VARIANTS.get(i).copied()
} else {
Self::EXTENDED_VARIANTS
.and_then(|array| array.get(i - Self::VARIANTS.len()).copied())
}
})
}
}
macro_rules! asn_type {
($($name:ty: $value:ident),+) => {
$(
impl AsnType for $name {
const TAG: Tag = Tag::$value;
}
)+
}
}
asn_type! {
bool: BOOL,
Integer: INTEGER,
OctetString: OCTET_STRING,
ObjectIdentifier: OBJECT_IDENTIFIER,
Oid: OBJECT_IDENTIFIER,
Utf8String: UTF8_STRING,
UtcTime: UTC_TIME,
GeneralizedTime: GENERALIZED_TIME,
(): NULL,
&'_ str: UTF8_STRING
}
macro_rules! asn_integer_type {
($($int:ty),+ $(,)?) => {
$(
impl AsnType for $int {
const TAG: Tag = Tag::INTEGER;
const CONSTRAINTS: Constraints = constraints!(value_constraint!((<$int>::MIN as i128), (<$int>::MAX as i128)));
}
)+
}
}
asn_integer_type! {
i8,
i16,
i32,
i64,
i128,
isize,
u8,
u16,
u32,
u64,
u128, usize,
}
impl AsnType for num_bigint::BigInt {
const TAG: Tag = Tag::INTEGER;
}
impl AsnType for str {
const TAG: Tag = Tag::UTF8_STRING;
}
impl<T: AsnType> AsnType for &'_ T {
const TAG: Tag = T::TAG;
const TAG_TREE: TagTree = T::TAG_TREE;
fn is_present(&self) -> bool {
(*self).is_present()
}
}
impl<T: AsnType> AsnType for Box<T> {
const TAG: Tag = T::TAG;
const TAG_TREE: TagTree = T::TAG_TREE;
}
impl<T: AsnType> AsnType for alloc::vec::Vec<T> {
const TAG: Tag = Tag::SEQUENCE;
}
impl<T: AsnType> AsnType for Option<T> {
const TAG: Tag = T::TAG;
const TAG_TREE: TagTree = T::TAG_TREE;
fn is_present(&self) -> bool {
self.is_some()
}
}
impl<T> AsnType for SetOf<T> {
const TAG: Tag = Tag::SET;
}
impl<T: AsnType, const N: usize> AsnType for [T; N] {
const TAG: Tag = Tag::SEQUENCE;
const CONSTRAINTS: Constraints = constraints!(size_constraint!(N));
}
impl<T> AsnType for &'_ [T] {
const TAG: Tag = Tag::SEQUENCE;
}
impl AsnType for Any {
const TAG: Tag = Tag::EOC;
const TAG_TREE: TagTree = TagTree::Choice(&[]);
}