rasn/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), no_std)]
3
4extern crate alloc;
5
6#[cfg(test)]
7macro_rules! round_trip {
8    ($codec:ident, $typ:ty, $value:expr, $expected:expr) => {{
9        let value: $typ = $value;
10        let expected: &[u8] = $expected;
11        let result = crate::$codec::encode(&value);
12        let actual_encoding = match result {
13            Ok(actual_encoding) => {
14                pretty_assertions::assert_eq!(expected, &*actual_encoding);
15                actual_encoding
16            }
17            Err(error) => {
18                panic!("Unexpected encoding error: {:?}", error);
19            }
20        };
21        let decoded_value: $typ = crate::$codec::decode(&actual_encoding).unwrap();
22        pretty_assertions::assert_eq!(value, decoded_value);
23    }};
24}
25#[cfg(test)]
26macro_rules! encode_error {
27    ($codec:ident, $typ:ty, $value:expr) => {{
28        let value: $typ = $value;
29        let result = crate::$codec::encode(&value);
30        match result {
31            Ok(actual_encoding) => {
32                panic!(
33                    "Expected an encoding error but got a valid encoding: {:?}",
34                    &*actual_encoding
35                );
36            }
37            Err(_) => {
38                // Expected an encoding error, so we're good!
39            }
40        }
41    }};
42}
43#[cfg(test)]
44macro_rules! decode_error {
45    ($codec:ident, $typ:ty, $value:expr) => {{
46        match crate::$codec::decode::<$typ>($value) {
47            Ok(_) => {
48                panic!("Unexpected decoding success!");
49            }
50            Err(_) => {
51                // Expected a deoding error, so we're good!
52            }
53        }
54    }};
55}
56#[cfg(test)]
57macro_rules! decode_ok {
58    ($codec:ident, $typ:ty, $value:expr, $expected:expr) => {{
59        match crate::$codec::decode::<$typ>($value) {
60            Ok(result) => {
61                pretty_assertions::assert_eq!(result, $expected);
62            }
63            Err(_) => {
64                panic!("Unexpected decoding failure!");
65            }
66        }
67    }};
68}
69
70#[cfg(test)]
71macro_rules! round_trip_with_constraints {
72    ($codec:ident, $typ:ty, $constraints:expr, $value:expr, $expected:expr) => {{
73        let value: $typ = $value;
74        let expected: &[u8] = $expected;
75        let actual_encoding = crate::$codec::encode_with_constraints($constraints, &value).unwrap();
76
77        pretty_assertions::assert_eq!(expected, &*actual_encoding);
78
79        let decoded_value: $typ =
80            crate::$codec::decode_with_constraints($constraints, &actual_encoding).unwrap();
81
82        pretty_assertions::assert_eq!(value, decoded_value);
83    }};
84}
85#[cfg(test)]
86macro_rules! encode_error_with_constraints {
87    ($codec:ident, $typ:ty, $constraints:expr, $value:expr) => {{
88        let value: $typ = $value;
89        let result = crate::$codec::encode_with_constraints($constraints, &value);
90        match result {
91            Ok(actual_encoding) => {
92                panic!(
93                    "Expected an encoding error but got a valid encoding: {:?}",
94                    &*actual_encoding
95                );
96            }
97            Err(_) => {
98                // Expected an encoding error, so we're good!
99            }
100        }
101    }};
102}
103
104pub mod codec;
105pub mod de;
106pub mod enc;
107pub mod types;
108
109// Data Formats
110
111mod per;
112
113pub mod aper;
114pub mod ber;
115mod bits;
116pub mod cer;
117pub mod coer;
118pub mod der;
119pub mod error;
120pub mod jer;
121mod num;
122pub mod oer;
123pub mod uper;
124
125#[doc(inline)]
126pub use self::{
127    codec::Codec,
128    de::{Decode, Decoder},
129    enc::{Encode, Encoder},
130    types::{AsnType, Tag, TagTree},
131};
132
133/// A prelude containing the codec traits and all types defined in the [`types`]
134/// module.
135pub mod prelude {
136    pub use crate::{
137        de::{Decode, Decoder},
138        enc::{Encode, Encoder},
139        types::*,
140    };
141}
142
143#[cfg(test)]
144mod tests {
145    use super::prelude::*;
146
147    #[track_caller]
148    fn round_trip<T: Decode + Encode + PartialEq + core::fmt::Debug>(value: &T) {
149        macro_rules! codecs {
150            ($($codec:ident),+ $(,)?) => {
151                $(
152                    pretty_assertions::assert_eq!(
153                        value,
154                        &match crate::$codec::decode::<T>(
155                            &match crate::$codec::encode(value).map_err(|error| error.to_string()) {
156                                Ok(value) => value,
157                                Err(error) => panic!("error encoding: {}", error),
158                            }
159                        ) {
160                            Ok(value) => value,
161                            Err(error) => panic!("error decoding: {}", error),
162                        }
163                    );
164                )+
165            }
166        }
167
168        codecs!(uper, aper);
169    }
170
171    #[test]
172    fn null() {
173        round_trip(&());
174    }
175
176    #[test]
177    fn bool() {
178        round_trip(&true);
179        round_trip(&false);
180    }
181
182    macro_rules! integer_tests {
183        ($($integer:ident),*) => {
184            $(
185                #[test]
186                fn $integer() {
187                    let min = <$integer>::MIN;
188                    let max = <$integer>::MAX;
189                    let half_max = <$integer>::MAX / 2;
190                    let half_min = <$integer>::MIN / 2;
191
192                    round_trip(&min);
193                    round_trip(&half_min);
194                    round_trip(&half_max);
195                    round_trip(&max);
196                }
197            )*
198        }
199    }
200
201    integer_tests! {
202        i8,
203        i16,
204        i32,
205        i64,
206        isize,
207        u8,
208        u16,
209        u32,
210        u64,
211        usize
212    }
213
214    #[test]
215    fn integer() {
216        round_trip(&Integer::from(89));
217        round_trip(&Integer::from(256));
218        round_trip(&Integer::from(u64::MAX));
219        round_trip(&Integer::from(i64::MIN));
220    }
221
222    #[test]
223    fn semi_constrained_integer() {
224        #[derive(PartialEq, Debug)]
225        struct CustomInt(i32);
226
227        impl crate::AsnType for CustomInt {
228            const TAG: Tag = Tag::INTEGER;
229            const CONSTRAINTS: Constraints<'static> =
230                Constraints::new(&[Constraint::Value(constraints::Extensible::new(
231                    constraints::Value::new(constraints::Bounded::start_from(127)),
232                ))]);
233        }
234
235        impl crate::Encode for CustomInt {
236            fn encode_with_tag_and_constraints<E: crate::Encoder>(
237                &self,
238                encoder: &mut E,
239                tag: Tag,
240                constraints: Constraints,
241            ) -> Result<(), E::Error> {
242                encoder
243                    .encode_integer(tag, constraints, &self.0.into())
244                    .map(drop)
245            }
246        }
247
248        impl crate::Decode for CustomInt {
249            fn decode_with_tag_and_constraints<D: crate::Decoder>(
250                decoder: &mut D,
251                tag: Tag,
252                constraints: Constraints,
253            ) -> Result<Self, D::Error> {
254                Ok(Self(decoder.decode_integer::<i32>(tag, constraints)?))
255            }
256        }
257
258        round_trip(&CustomInt(256));
259        round_trip(&CustomInt(i32::MAX));
260    }
261
262    #[test]
263    fn bit_string() {
264        round_trip(&BitString::from_slice(&[1u8, 2, 3, 4, 5]));
265        round_trip(&BitString::from_slice(&[5u8, 4, 3, 2, 1]));
266    }
267
268    #[test]
269    fn octet_string() {
270        round_trip(&OctetString::from(vec![1u8, 2, 3, 4, 5]));
271        round_trip(&OctetString::from(vec![5u8, 4, 3, 2, 1]));
272    }
273
274    #[test]
275    fn utf8_string() {
276        round_trip(&crate::types::Utf8String::from("Jones"));
277    }
278
279    #[test]
280    fn visible_string() {
281        round_trip(&crate::types::Utf8String::from("Jones"));
282    }
283
284    #[test]
285    fn long_sequence_of() {
286        round_trip(&vec![5u8; 0xffff]);
287    }
288
289    #[test]
290    fn object_identifier() {
291        round_trip(&ObjectIdentifier::new(vec![1, 2]).unwrap());
292        round_trip(&ObjectIdentifier::new(vec![1, 2, 840]).unwrap());
293        round_trip(&ObjectIdentifier::new(vec![1, 2, 840, 113549]).unwrap());
294        round_trip(&ObjectIdentifier::new(vec![1, 2, 840, 113549, 1]).unwrap());
295        round_trip(&ObjectIdentifier::new(vec![0, 3, 0, 3]).unwrap());
296    }
297
298    #[test]
299    fn enumerated() {
300        #[derive(AsnType, Clone, Copy, Debug, Decode, Encode, PartialEq)]
301        #[rasn(enumerated, crate_root = "crate")]
302        enum Day {
303            Mon,
304            Tues,
305            Weds,
306            Thurs,
307            Fri,
308            Sat,
309            Sun,
310        }
311
312        round_trip(&Day::Mon);
313        round_trip(&Day::Tues);
314        round_trip(&Day::Sat);
315    }
316}