rasn/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), no_std)]
3#![warn(missing_docs)]
4
5extern crate alloc;
6
7#[macro_use]
8pub mod macros;
9
10mod bits;
11mod codec;
12pub mod de;
13pub mod enc;
14pub mod error;
15mod num;
16mod per;
17pub mod types;
18
19// Data Formats
20
21pub mod aper;
22pub mod ber;
23pub mod cer;
24pub mod coer;
25pub mod der;
26pub mod jer;
27pub mod oer;
28pub mod uper;
29pub mod xer;
30
31#[doc(inline)]
32pub use self::{
33    codec::Codec,
34    de::{Decode, Decoder},
35    enc::{Encode, Encoder},
36    types::AsnType,
37};
38
39#[doc(inline)]
40#[cfg(feature = "compiler")]
41#[cfg_attr(docsrs, doc(cfg(feature = "compiler")))]
42/// Compiler for ASN.1 Notation to Rust code.
43pub use rasn_compiler as compiler;
44
45/// A prelude containing the codec traits and all types defined in the [`types`]
46/// module.
47pub mod prelude {
48    pub use crate::{
49        de::{Decode, Decoder},
50        enc::{Encode, Encoder},
51        macros,
52        types::*,
53    };
54}
55
56#[cfg(test)]
57mod tests {
58    use super::prelude::*;
59
60    #[track_caller]
61    fn round_trip<T: Decode + Encode + PartialEq + core::fmt::Debug>(value: &T) {
62        macro_rules! codecs {
63            ($($codec:ident),+ $(,)?) => {
64                $(
65                    pretty_assertions::assert_eq!(
66                        value,
67                        &match crate::$codec::decode::<T>(
68                            &match crate::$codec::encode(value).map_err(|error| error.to_string()) {
69                                Ok(value) => value,
70                                Err(error) => panic!("error encoding: {}", error),
71                            }
72                        ) {
73                            Ok(value) => value,
74                            Err(error) => panic!("error decoding: {}", error),
75                        }
76                    );
77                )+
78            }
79        }
80
81        codecs!(uper, aper, oer, coer, ber);
82    }
83
84    #[test]
85    fn null() {
86        round_trip(&());
87    }
88
89    #[test]
90    fn bool() {
91        round_trip(&true);
92        round_trip(&false);
93    }
94
95    macro_rules! integer_tests {
96        ($($integer:ident),*) => {
97            $(
98                #[test]
99                fn $integer() {
100                    let min = <$integer>::MIN;
101                    let max = <$integer>::MAX;
102                    let half_max = <$integer>::MAX / 2;
103                    let half_min = <$integer>::MIN / 2;
104
105                    round_trip(&min);
106                    round_trip(&half_min);
107                    round_trip(&half_max);
108                    round_trip(&max);
109                }
110            )*
111        }
112    }
113
114    integer_tests! {
115        i8,
116        i16,
117        i32,
118        i64,
119        // i128, TODO i128 does not work for UPER/APER
120        isize,
121        u8,
122        u16,
123        u32,
124        u64,
125        // TODO cannot support u128 as it is constrained type by default and current constraints uses i128 for bounds
126        // u128,
127        usize
128    }
129
130    #[test]
131    fn integer() {
132        round_trip(&89);
133        round_trip(&256);
134        round_trip(&u64::MAX);
135        round_trip(&i64::MIN);
136    }
137
138    #[test]
139    fn semi_constrained_integer() {
140        #[derive(PartialEq, Debug)]
141        struct CustomInt(i32);
142
143        impl crate::AsnType for CustomInt {
144            const TAG: Tag = Tag::INTEGER;
145            const CONSTRAINTS: Constraints =
146                macros::constraints!(macros::value_constraint!(start: 127));
147        }
148
149        impl crate::Encode for CustomInt {
150            fn encode_with_tag_and_constraints<'b, E: crate::Encoder<'b>>(
151                &self,
152                encoder: &mut E,
153                tag: Tag,
154                constraints: Constraints,
155                _: Identifier,
156            ) -> Result<(), E::Error> {
157                encoder
158                    .encode_integer::<i128>(tag, constraints, &self.0.into(), Identifier::EMPTY)
159                    .map(drop)
160            }
161        }
162
163        impl crate::Decode for CustomInt {
164            fn decode_with_tag_and_constraints<D: crate::Decoder>(
165                decoder: &mut D,
166                tag: Tag,
167                constraints: Constraints,
168            ) -> Result<Self, D::Error> {
169                Ok(Self(decoder.decode_integer::<i32>(tag, constraints)?))
170            }
171        }
172
173        round_trip(&CustomInt(256));
174        round_trip(&CustomInt(i32::MAX));
175    }
176
177    #[test]
178    fn bit_string() {
179        round_trip(&BitString::from_slice(&[1u8, 2, 3, 4, 5]));
180        round_trip(&BitString::from_slice(&[5u8, 4, 3, 2, 1]));
181    }
182
183    #[test]
184    fn octet_string() {
185        round_trip(&OctetString::from(vec![1u8, 2, 3, 4, 5]));
186        round_trip(&OctetString::from(vec![5u8, 4, 3, 2, 1]));
187    }
188
189    #[test]
190    fn utf8_string() {
191        round_trip(&crate::types::Utf8String::from("Jones"));
192    }
193
194    #[test]
195    fn visible_string() {
196        round_trip(&crate::types::Utf8String::from("Jones"));
197    }
198
199    #[test]
200    fn long_sequence_of() {
201        round_trip(&vec![5u8; 0xffff]);
202    }
203
204    #[test]
205    fn object_identifier() {
206        round_trip(&ObjectIdentifier::new(vec![1, 2]).unwrap());
207        round_trip(&ObjectIdentifier::new(vec![1, 2, 840]).unwrap());
208        round_trip(&ObjectIdentifier::new(vec![1, 2, 840, 113549]).unwrap());
209        round_trip(&ObjectIdentifier::new(vec![1, 2, 840, 113549, 1]).unwrap());
210        round_trip(&ObjectIdentifier::new(vec![0, 3, 0, 3]).unwrap());
211    }
212
213    #[test]
214    fn enumerated() {
215        #[derive(AsnType, Clone, Copy, Debug, Decode, Encode, PartialEq)]
216        #[rasn(enumerated, crate_root = "crate")]
217        enum Day {
218            Mon,
219            Tues,
220            Weds,
221            Thurs,
222            Fri,
223            Sat,
224            Sun,
225        }
226
227        round_trip(&Day::Mon);
228        round_trip(&Day::Tues);
229        round_trip(&Day::Sat);
230    }
231    // Test iterator-based decoding
232    #[test]
233    fn decode_with_iterator() {
234        use crate::types::Integer;
235
236        macro_rules! test_codec_iter {
237            ($codec:ident, $codec_enum:expr) => {
238                let mut data = vec![];
239                let integer_before1 = Integer::from(i64::from(i32::MIN) - 1);
240                let integer_before2 = Integer::from(i64::from(i32::MAX) - 1);
241                let integer_before3 = Integer::from(i64::from(i32::MIN) - i64::from(i16::MIN));
242                data.extend(crate::$codec::encode(&integer_before1).unwrap());
243                data.extend(crate::$codec::encode(&integer_before2).unwrap());
244                let mut iter = crate::de::iter(&data, $codec_enum);
245                let decoded: Integer = iter.next().unwrap().unwrap();
246                assert_eq!(integer_before1, decoded);
247                let int3_bytes = crate::$codec::encode(&integer_before3).unwrap();
248                iter.append_bytes(&int3_bytes);
249                let decoded: Integer = iter.next().unwrap().unwrap();
250                assert_eq!(integer_before2, decoded);
251                let decoded: Integer = iter.next().unwrap().unwrap();
252                assert_eq!(integer_before3, decoded);
253            };
254        }
255
256        test_codec_iter!(oer, crate::Codec::Oer);
257        test_codec_iter!(coer, crate::Codec::Coer);
258        test_codec_iter!(uper, crate::Codec::Uper);
259        test_codec_iter!(aper, crate::Codec::Aper);
260        test_codec_iter!(ber, crate::Codec::Ber);
261        test_codec_iter!(cer, crate::Codec::Cer);
262        test_codec_iter!(der, crate::Codec::Der);
263    }
264}