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 }
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 }
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 }
100 }
101 }};
102}
103
104pub mod codec;
105pub mod de;
106pub mod enc;
107pub mod types;
108
109mod 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
133pub 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}