#![doc = include_str!("../README.md")]
#![cfg_attr(not(test), no_std)]
#![warn(missing_docs)]
#![allow(
clippy::missing_errors_doc,
clippy::float_cmp,
clippy::no_effect_underscore_binding,
clippy::items_after_statements
)]
extern crate alloc;
#[macro_use]
pub mod macros;
mod bits;
mod codec;
pub mod de;
pub mod enc;
pub mod error;
mod num;
mod per;
pub mod types;
pub mod aper;
pub mod avn;
pub mod ber;
pub mod cer;
pub mod coer;
pub mod der;
pub mod jer;
pub mod oer;
pub mod uper;
pub mod xer;
#[doc(inline)]
pub use self::{
codec::Codec,
de::{Decode, Decoder},
enc::{Encode, Encoder},
types::AsnType,
};
#[doc(inline)]
#[cfg(feature = "compiler")]
#[cfg_attr(docsrs, doc(cfg(feature = "compiler")))]
pub use rasn_compiler as compiler;
pub mod prelude {
pub use crate::{
de::{Decode, Decoder},
enc::{Encode, Encoder},
macros,
types::*,
};
}
#[cfg(test)]
mod tests {
use super::prelude::*;
#[track_caller]
fn round_trip<T: Decode + Encode + PartialEq + core::fmt::Debug>(value: &T) {
macro_rules! codecs {
($($codec:ident),+ $(,)?) => {
$(
pretty_assertions::assert_eq!(
value,
&match crate::$codec::decode::<T>(
&match crate::$codec::encode(value).map_err(|error| error.to_string()) {
Ok(value) => value,
Err(error) => panic!("error encoding: {}", error),
}
) {
Ok(value) => value,
Err(error) => panic!("error decoding: {}", error),
}
);
)+
}
}
codecs!(uper, aper, oer, coer, ber);
}
#[test]
fn null() {
round_trip(&());
}
#[test]
fn bool() {
round_trip(&true);
round_trip(&false);
}
macro_rules! integer_tests {
($($integer:ident),*) => {
$(
#[test]
fn $integer() {
let min = <$integer>::MIN;
let max = <$integer>::MAX;
let half_max = <$integer>::MAX / 2;
let half_min = <$integer>::MIN / 2;
round_trip(&min);
round_trip(&half_min);
round_trip(&half_max);
round_trip(&max);
}
)*
}
}
integer_tests! {
i8,
i16,
i32,
i64,
isize,
u8,
u16,
u32,
u64,
usize
}
#[test]
fn integer() {
round_trip(&89);
round_trip(&256);
round_trip(&u64::MAX);
round_trip(&i64::MIN);
}
#[test]
fn semi_constrained_integer() {
#[derive(PartialEq, Debug)]
struct CustomInt(i32);
impl crate::AsnType for CustomInt {
const TAG: Tag = Tag::INTEGER;
const CONSTRAINTS: Constraints =
macros::constraints!(macros::value_constraint!(start: 127));
}
impl crate::Encode for CustomInt {
fn encode_with_tag_and_constraints<'b, E: crate::Encoder<'b>>(
&self,
encoder: &mut E,
tag: Tag,
constraints: Constraints,
_: Identifier,
) -> Result<(), E::Error> {
encoder
.encode_integer::<i128>(tag, constraints, &self.0.into(), Identifier::EMPTY)
.map(drop)
}
}
impl crate::Decode for CustomInt {
fn decode_with_tag_and_constraints<D: crate::Decoder>(
decoder: &mut D,
tag: Tag,
constraints: Constraints,
) -> Result<Self, D::Error> {
Ok(Self(decoder.decode_integer::<i32>(tag, constraints)?))
}
}
round_trip(&CustomInt(256));
round_trip(&CustomInt(i32::MAX));
}
#[test]
fn bit_string() {
round_trip(&BitString::from_slice(&[1u8, 2, 3, 4, 5]));
round_trip(&BitString::from_slice(&[5u8, 4, 3, 2, 1]));
}
#[test]
fn octet_string() {
round_trip(&OctetString::from(vec![1u8, 2, 3, 4, 5]));
round_trip(&OctetString::from(vec![5u8, 4, 3, 2, 1]));
}
#[test]
fn utf8_string() {
round_trip(&crate::types::Utf8String::from("Jones"));
}
#[test]
fn visible_string() {
round_trip(&crate::types::Utf8String::from("Jones"));
}
#[test]
fn long_sequence_of() {
round_trip(&vec![5u8; 0xffff]);
}
#[test]
fn object_identifier() {
round_trip(&ObjectIdentifier::new(vec![1, 2]).unwrap());
round_trip(&ObjectIdentifier::new(vec![1, 2, 840]).unwrap());
round_trip(&ObjectIdentifier::new(vec![1, 2, 840, 113_549]).unwrap());
round_trip(&ObjectIdentifier::new(vec![1, 2, 840, 113_549, 1]).unwrap());
round_trip(&ObjectIdentifier::new(vec![0, 3, 0, 3]).unwrap());
}
#[test]
fn enumerated() {
#[derive(AsnType, Clone, Copy, Debug, Decode, Encode, PartialEq)]
#[rasn(enumerated, crate_root = "crate")]
enum Day {
Mon,
Tues,
Weds,
Thurs,
Fri,
Sat,
Sun,
}
round_trip(&Day::Mon);
round_trip(&Day::Tues);
round_trip(&Day::Sat);
}
#[test]
fn decode_with_iterator() {
use crate::types::Integer;
macro_rules! test_codec_iter {
($codec:ident, $codec_enum:expr) => {
let mut data = vec![];
let integer_before1 = Integer::from(i64::from(i32::MIN) - 1);
let integer_before2 = Integer::from(i64::from(i32::MAX) - 1);
let integer_before3 = Integer::from(i64::from(i32::MIN) - i64::from(i16::MIN));
data.extend(crate::$codec::encode(&integer_before1).unwrap());
data.extend(crate::$codec::encode(&integer_before2).unwrap());
let mut iter = crate::de::iter(&data, $codec_enum);
let decoded: Integer = iter.next().unwrap().unwrap();
assert_eq!(integer_before1, decoded);
let int3_bytes = crate::$codec::encode(&integer_before3).unwrap();
iter.append_bytes(&int3_bytes);
let decoded: Integer = iter.next().unwrap().unwrap();
assert_eq!(integer_before2, decoded);
let decoded: Integer = iter.next().unwrap().unwrap();
assert_eq!(integer_before3, decoded);
};
}
test_codec_iter!(oer, crate::Codec::Oer);
test_codec_iter!(coer, crate::Codec::Coer);
test_codec_iter!(uper, crate::Codec::Uper);
test_codec_iter!(aper, crate::Codec::Aper);
test_codec_iter!(ber, crate::Codec::Ber);
test_codec_iter!(cer, crate::Codec::Cer);
test_codec_iter!(der, crate::Codec::Der);
}
}