rasn/
coer.rs

1//! COER is a binary encoding rule that is a subset of OER.
2//! Encodes and decodes as COER in this stricter variant.
3pub use super::oer::*;
4use crate::error::{DecodeError, EncodeError};
5use crate::types::Constraints;
6
7/// Attempts to decode `T` from `input` using OER.
8///
9/// # Errors
10/// Returns `DecodeError` if `input` is not valid COER encoding specific to the expected type.
11pub fn decode<T: crate::Decode>(input: &[u8]) -> Result<T, DecodeError> {
12    T::decode(&mut Decoder::new(
13        crate::types::BitStr::from_slice(input),
14        de::DecoderOptions::coer(),
15    ))
16}
17/// Attempts to encode `value` of type `T` to COER.
18///
19/// # Errors
20/// Returns `EncodeError` if `value` cannot be encoded as COER, usually meaning that constraints
21/// are not met.
22pub fn encode<T: crate::Encode>(value: &T) -> Result<alloc::vec::Vec<u8>, EncodeError> {
23    let mut enc = Encoder::new(enc::EncoderOptions::coer());
24    value.encode(&mut enc)?;
25    Ok(enc.output())
26}
27/// Attempts to decode `T` from `input` using OER with constraints.
28///
29/// # Errors
30/// Returns `DecodeError` if `input` is not valid COER, while passing setting constraints.
31pub fn decode_with_constraints<T: crate::Decode>(
32    constraints: Constraints,
33    input: &[u8],
34) -> Result<T, DecodeError> {
35    T::decode_with_constraints(
36        &mut Decoder::new(
37            crate::types::BitStr::from_slice(input),
38            de::DecoderOptions::coer(),
39        ),
40        constraints,
41    )
42}
43/// Attempts to encode `value` of type `T` into COER with constraints.
44///
45/// # Errors
46/// Returns `EncodeError` if `value` cannot be encoded as COER, while setting specific constraints.
47pub fn encode_with_constraints<T: crate::Encode>(
48    constraints: Constraints,
49    value: &T,
50) -> Result<alloc::vec::Vec<u8>, EncodeError> {
51    let mut enc = Encoder::new(enc::EncoderOptions::coer());
52    value.encode_with_constraints(&mut enc, constraints)?;
53    Ok(enc.output())
54}
55
56#[cfg(test)]
57#[allow(clippy::items_after_statements)]
58mod tests {
59    use crate as rasn;
60    use crate::prelude::*;
61    use crate::types::constraints::{Bounded, Size, Value};
62    use bitvec::prelude::*;
63    #[test]
64    fn bool() {
65        round_trip!(coer, bool, true, &[0xff]);
66        round_trip!(coer, bool, false, &[0]);
67    }
68    #[test]
69    #[allow(clippy::too_many_lines)]
70    fn integer_no_constraints() {
71        // Without constraints, all integers should be encoded as signed, with length determinant,
72        // and without padding.
73        round_trip!(coer, Integer, 0.into(), &[0x01u8, 0x00]);
74        round_trip!(coer, Integer, 1.into(), &[0x01u8, 0x01]);
75        round_trip!(coer, Integer, (-1).into(), &[0x01u8, 0xff]);
76        round_trip!(coer, Integer, 255.into(), &[0x02u8, 0x00, 0xff]);
77        round_trip!(coer, Integer, (-255).into(), &[0x02u8, 0xff, 0x01]);
78        round_trip!(coer, Integer, i16::MAX.into(), &[0x02u8, 0x7f, 0xff]);
79        round_trip!(coer, Integer, i16::MIN.into(), &[0x02u8, 0x80, 0x00]);
80        round_trip!(
81            coer,
82            Integer,
83            (i32::from(i16::MAX) + 1).into(),
84            &[0x03u8, 0x00u8, 0x80, 0x00]
85        );
86        round_trip!(
87            coer,
88            Integer,
89            (i32::from(i16::MIN) - 1).into(),
90            &[0x03u8, 0xff, 0x7f, 0xff]
91        );
92        round_trip!(
93            coer,
94            Integer,
95            i32::MAX.into(),
96            &[0x04u8, 0x7f, 0xff, 0xff, 0xff]
97        );
98        round_trip!(
99            coer,
100            Integer,
101            i32::MIN.into(),
102            &[0x04u8, 0x80, 0x00, 0x00, 0x00]
103        );
104        round_trip!(
105            coer,
106            Integer,
107            (i64::from(i32::MAX) + 1).into(),
108            &[0x05u8, 0x00, 0x80, 0x00, 0x00, 0x00]
109        );
110        round_trip!(
111            coer,
112            Integer,
113            (i64::from(i32::MIN) - 1).into(),
114            &[0x05u8, 0xff, 0x7f, 0xff, 0xff, 0xff]
115        );
116        round_trip!(
117            coer,
118            Integer,
119            i64::MAX.into(),
120            &[0x08u8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
121        );
122        round_trip!(
123            coer,
124            Integer,
125            i64::MIN.into(),
126            &[0x08u8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
127        );
128        round_trip!(
129            coer,
130            Integer,
131            (i128::from(i64::MAX) + 1).into(),
132            &[0x09u8, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
133        );
134        round_trip!(
135            coer,
136            Integer,
137            (i128::from(i64::MIN) - 1).into(),
138            &[0x09u8, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
139        );
140        round_trip!(
141            coer,
142            Integer,
143            i128::MAX.into(),
144            &[
145                0x10u8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
146                0xff, 0xff, 0xff, 0xff
147            ]
148        );
149        round_trip!(
150            coer,
151            Integer,
152            i128::MIN.into(),
153            &[
154                0x10u8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155                0x00, 0x00, 0x00, 0x00
156            ]
157        );
158        round_trip!(
159            coer,
160            Integer,
161            Integer::from(i128::MAX) + 1,
162            &[
163                0x11u8, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164                0x00, 0x00, 0x00, 0x00, 0x00
165            ]
166        );
167        round_trip!(
168            coer,
169            Integer,
170            Integer::from(i128::MIN) - 1,
171            &[
172                0x11u8, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
173                0xff, 0xff, 0xff, 0xff, 0xff
174            ]
175        );
176    }
177    #[test]
178    fn test_integer_with_unsigned_constraints() {
179        type A = ConstrainedInteger<0, { u8::MAX as i128 }>;
180        type B = ConstrainedInteger<0, { u16::MAX as i128 }>;
181        type C = ConstrainedInteger<0, { u32::MAX as i128 }>;
182        type D = ConstrainedInteger<0, { u64::MAX as i128 }>;
183        type E = ConstrainedInteger<0, { i128::MAX }>;
184        type F = ConstrainedInteger<2, { u16::MAX as i128 }>;
185
186        round_trip!(coer, A, 0.into(), &[0x00]);
187        round_trip!(coer, A, 5.into(), &[0x05]);
188        round_trip!(coer, A, 255.into(), &[0xff]);
189        // Paddings are expected
190        round_trip!(coer, B, 0.into(), &[0x00, 0x00]);
191        round_trip!(coer, B, 255.into(), &[0x00, 0xff]);
192        round_trip!(coer, C, 0.into(), &[0x00, 0x00, 0x00, 0x00]);
193        round_trip!(coer, C, u16::MAX.into(), &[0x00, 0x00, 0xff, 0xff]);
194        round_trip!(
195            coer,
196            D,
197            0.into(),
198            &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
199        );
200        round_trip!(
201            coer,
202            D,
203            u32::MAX.into(),
204            &[0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]
205        );
206        // Use length determinant when upper range above u64 max
207        round_trip!(
208            coer,
209            E,
210            (i128::from(u64::MAX) + 1).into(),
211            &[0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
212        );
213        round_trip!(coer, F, 2.into(), &[0x00, 0x02]);
214        // Error expected, outside of range constraints
215        encode_error!(coer, A, (-1).into());
216        encode_error!(coer, B, (-1).into());
217        encode_error!(coer, C, (-1).into());
218        encode_error!(coer, D, (-1).into());
219        encode_error!(coer, E, (-1).into());
220        encode_error!(coer, F, (1).into());
221        encode_error!(coer, A, (u16::from(u8::MAX) + 1).into());
222        encode_error!(coer, B, (u32::from(u16::MAX) + 1).into());
223        encode_error!(coer, C, (u64::from(u32::MAX) + 1).into());
224        encode_error!(coer, D, (u128::from(u64::MAX) + 1).into());
225    }
226    #[test]
227    fn test_integer_with_signed_constraints() {
228        type A = ConstrainedInteger<{ i8::MIN as i128 }, { i8::MAX as i128 }>;
229        type B = ConstrainedInteger<{ i16::MIN as i128 }, { i16::MAX as i128 }>;
230        type C = ConstrainedInteger<{ i32::MIN as i128 }, { i32::MAX as i128 }>;
231        type D = ConstrainedInteger<{ i64::MIN as i128 }, { i64::MAX as i128 }>;
232        type E = ConstrainedInteger<-5, 5>;
233
234        round_trip!(coer, A, 0.into(), &[0x00]);
235        round_trip!(coer, A, (-1).into(), &[0xff]);
236        round_trip!(coer, A, i8::MIN.into(), &[0x80]);
237        round_trip!(coer, A, i8::MAX.into(), &[0x7f]);
238        // Paddings (0xff as 2's complement) are sometimes expected
239        round_trip!(coer, B, 0.into(), &[0x00, 0x00]);
240        round_trip!(coer, B, (-1).into(), &[0xff, 0xff]);
241        round_trip!(coer, B, i8::MIN.into(), &[0xff, 0x80]);
242        round_trip!(coer, B, i8::MAX.into(), &[0x00, 0x7f]);
243        round_trip!(coer, B, i16::MIN.into(), &[0x80, 0x00]);
244        round_trip!(coer, B, i16::MAX.into(), &[0x7f, 0xff]);
245
246        round_trip!(coer, C, 0.into(), &[0x00, 0x00, 0x00, 0x00]);
247        round_trip!(coer, C, (-1).into(), &[0xff, 0xff, 0xff, 0xff]);
248        round_trip!(coer, C, i16::MIN.into(), &[0xff, 0xff, 0x80, 0x00]);
249        round_trip!(coer, C, i16::MAX.into(), &[0x00, 0x00, 0x7f, 0xff]);
250        round_trip!(coer, C, i32::MIN.into(), &[0x80, 0x00, 0x00, 0x00]);
251        round_trip!(coer, C, i32::MAX.into(), &[0x7f, 0xff, 0xff, 0xff]);
252
253        round_trip!(
254            coer,
255            D,
256            0.into(),
257            &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
258        );
259        round_trip!(
260            coer,
261            D,
262            (-1).into(),
263            &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
264        );
265        round_trip!(
266            coer,
267            D,
268            i32::MIN.into(),
269            &[0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00]
270        );
271        round_trip!(
272            coer,
273            D,
274            i32::MAX.into(),
275            &[0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff]
276        );
277        round_trip!(
278            coer,
279            D,
280            i64::MIN.into(),
281            &[0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
282        );
283        round_trip!(
284            coer,
285            D,
286            i64::MAX.into(),
287            &[0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
288        );
289        round_trip!(coer, E, 4.into(), &[0x04]);
290        round_trip!(coer, E, (-4).into(), &[0xfc]);
291
292        // Error expected, outside of range constraints
293        encode_error!(coer, A, (i16::from(i8::MIN) - 1).into());
294        encode_error!(coer, B, (i32::from(i16::MIN) - 1).into());
295        encode_error!(coer, C, (i64::from(i32::MIN) - 1).into());
296        encode_error!(coer, D, (i128::from(i64::MIN) - 1).into());
297
298        encode_error!(coer, A, (i16::from(i8::MAX) + 1).into());
299        encode_error!(coer, B, (i32::from(i16::MAX) + 1).into());
300        encode_error!(coer, C, (i64::from(i32::MAX) + 1).into());
301        encode_error!(coer, D, (i128::from(i64::MAX) + 1).into());
302    }
303    #[test]
304    fn test_integer_single_constraint() {
305        round_trip_with_constraints!(
306            coer,
307            Integer,
308            Constraints::new(&[Constraint::Value(Value::new(Bounded::Single(5)).into())]),
309            5.into(),
310            &[0x05]
311        );
312    }
313    #[test]
314    fn test_enumerated() {
315        #[derive(AsnType, Clone, Copy, Debug, Decode, Encode, PartialEq)]
316        #[rasn(enumerated, crate_root = "crate")]
317        enum Enum1 {
318            Green,
319            Red,
320            Blue,
321        }
322        round_trip!(coer, Enum1, Enum1::Green, &[0x00]);
323        round_trip!(coer, Enum1, Enum1::Red, &[0x01]);
324        round_trip!(coer, Enum1, Enum1::Blue, &[0x02]);
325        // TODO, check correctness https://github.com/XAMPPRocky/rasn/discussions/124#discussioncomment-6724973
326        #[derive(AsnType, Clone, Copy, Debug, Decode, Encode, PartialEq)]
327        #[rasn(enumerated, crate_root = "crate")]
328        #[allow(clippy::items_after_statements)]
329        enum Enum2 {
330            Red,
331            Blue,
332            Green,
333            #[rasn(extension_addition_group)]
334            Yellow,
335            Purple,
336        }
337        round_trip!(coer, Enum2, Enum2::Red, &[0x00]);
338        round_trip!(coer, Enum2, Enum2::Yellow, &[0x03]);
339        round_trip!(coer, Enum2, Enum2::Purple, &[0x04]);
340        #[derive(AsnType, Clone, Copy, Debug, Decode, Encode, PartialEq)]
341        #[rasn(enumerated, crate_root = "crate")]
342        #[allow(clippy::items_after_statements)]
343        enum Enum3 {
344            Red = 5,
345            Blue = 6,
346            Green = 7,
347        }
348        round_trip!(coer, Enum3, Enum3::Red, &[0x05]);
349        round_trip!(coer, Enum3, Enum3::Blue, &[0x06]);
350        round_trip!(coer, Enum3, Enum3::Green, &[0x07]);
351
352        #[derive(AsnType, Clone, Copy, Debug, Decode, Encode, PartialEq)]
353        #[rasn(enumerated, crate_root = "crate")]
354        #[allow(clippy::items_after_statements)]
355        enum Enum4 {
356            Yes = 1000,
357            No = -1000,
358        }
359        round_trip!(coer, Enum4, Enum4::Yes, &[0x82, 0x03, 0xe8]);
360        round_trip!(coer, Enum4, Enum4::No, &[0x82, 0xfc, 0x18]);
361    }
362    #[test]
363    fn test_bit_string() {
364        round_trip!(
365            coer,
366            BitString,
367            BitString::from_slice(&[0x01]),
368            &[0x02, 0x00, 0x01]
369        );
370        round_trip!(coer, BitString, BitString::from_slice(&[]), &[0x01, 0x00]);
371        let mut bv = bitvec![u8, Msb0;];
372        bv.extend_from_raw_slice(&[0xff]);
373        bv.push(false);
374        bv.push(true);
375        bv.extend([false; 4].iter());
376        // bv should be 14 bits now
377        round_trip_with_constraints!(
378            coer,
379            BitString,
380            Constraints::new(&[Constraint::Size(Size::new(Bounded::Single(14)).into())]),
381            BitString::from_bitslice(&bv),
382            &[0b1111_1111, 0b0100_0000]
383        );
384        round_trip!(
385            coer,
386            BitString,
387            BitString::from_bitslice(&bv),
388            &[0x03u8, 0x02, 0b1111_1111, 0b0100_0000]
389        );
390        encode_error_with_constraints!(
391            coer,
392            BitString,
393            Constraints::new(&[Constraint::Size(Size::new(Bounded::Single(15)).into())]),
394            BitString::from_bitslice(&bv)
395        );
396    }
397    #[test]
398    fn test_octet_string() {
399        round_trip!(
400            coer,
401            OctetString,
402            OctetString::from_static(&[0x01]),
403            &[0x01, 0x01]
404        );
405        round_trip_with_constraints!(
406            coer,
407            OctetString,
408            Constraints::new(&[Constraint::Size(Size::new(Bounded::Single(5)).into())]),
409            OctetString::from_static(&[0x01u8, 0x02, 0x03, 0x04, 0x05]),
410            &[0x01u8, 0x02, 0x03, 0x04, 0x05]
411        );
412        round_trip_with_constraints!(
413            coer,
414            OctetString,
415            Constraints::new(&[Constraint::Size(
416                Size::new(Bounded::Range {
417                    start: Some(3),
418                    end: Some(6)
419                })
420                .into()
421            )]),
422            OctetString::from_static(&[0x01u8, 0x02, 0x03, 0x04, 0x05]),
423            &[0x05u8, 0x01, 0x02, 0x03, 0x04, 0x05]
424        );
425        encode_error_with_constraints!(
426            coer,
427            OctetString,
428            Constraints::new(&[Constraint::Size(Size::new(Bounded::Single(5)).into())]),
429            OctetString::from_static(&[0x01u8, 0x02, 0x03, 0x04])
430        );
431        encode_error_with_constraints!(
432            coer,
433            OctetString,
434            Constraints::new(&[Constraint::Size(
435                Size::new(Bounded::Range {
436                    start: Some(3),
437                    end: Some(6)
438                })
439                .into()
440            )]),
441            OctetString::from_static(&[0x01u8, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07])
442        );
443        encode_error_with_constraints!(
444            coer,
445            OctetString,
446            Constraints::new(&[Constraint::Size(
447                Size::new(Bounded::Range {
448                    start: Some(3),
449                    end: Some(6)
450                })
451                .into()
452            )]),
453            OctetString::from_static(&[0x01u8, 0x02])
454        );
455    }
456    #[test]
457    fn test_object_identifier() {
458        // ('A',                   '1.2', b'\x01\x2a'),
459        // ('A',              '1.2.3321', b'\x03\x2a\x99\x79')
460        round_trip!(
461            coer,
462            ObjectIdentifier,
463            ObjectIdentifier::new(vec![1u32, 2]).unwrap(),
464            &[0x01u8, 0x2a]
465        );
466        round_trip!(
467            coer,
468            ObjectIdentifier,
469            ObjectIdentifier::new(vec![1, 2, 3321]).unwrap(),
470            &[0x03u8, 0x2a, 0x99, 0x79]
471        );
472    }
473    #[test]
474    fn test_choice() {
475        // use crate as rasn;
476        #[derive(AsnType, Decode, Debug, Encode, PartialEq)]
477        #[rasn(crate_root = "crate")]
478        #[rasn(choice, automatic_tags)]
479        #[non_exhaustive]
480        enum Choice {
481            Normal(Integer),
482            High(Integer),
483            #[rasn(extension_addition)]
484            Medium(Integer),
485        }
486        round_trip!(
487            coer,
488            Choice,
489            Choice::Normal(333.into()),
490            &[0x80, 0x02, 0x01, 0x4d]
491        );
492        round_trip!(
493            coer,
494            Choice,
495            Choice::High(333.into()),
496            &[0x81, 0x02, 0x01, 0x4d]
497        );
498        round_trip!(
499            coer,
500            Choice,
501            Choice::Medium(333.into()),
502            &[0x82, 0x03, 0x02, 0x01, 0x4d]
503        );
504
505        #[derive(AsnType, Decode, Debug, Encode, PartialEq)]
506        #[rasn(crate_root = "crate")]
507        #[rasn(choice, automatic_tags)]
508        #[non_exhaustive]
509        enum BoolChoice {
510            A(bool),
511            #[rasn(extension_addition)]
512            B(bool),
513            C(Choice),
514        }
515        round_trip!(coer, BoolChoice, BoolChoice::A(true), &[0x80, 0xff]);
516        round_trip!(coer, BoolChoice, BoolChoice::B(true), &[0x81, 0x01, 0xff]);
517        round_trip!(
518            coer,
519            BoolChoice,
520            BoolChoice::C(Choice::Normal(333.into())),
521            &[0x82, 0x80, 0x02, 0x01, 0x4d]
522        );
523        #[derive(AsnType, Decode, Debug, Encode, PartialEq)]
524        #[rasn(choice, automatic_tags)]
525        #[non_exhaustive]
526        enum TripleChoice {
527            A(bool),
528            B(BoolChoice),
529        }
530        round_trip!(coer, TripleChoice, TripleChoice::A(true), &[0x80, 0xff]);
531        round_trip!(
532            coer,
533            TripleChoice,
534            TripleChoice::B(BoolChoice::C(Choice::Normal(333.into()))),
535            &[0x81, 0x82, 0x80, 0x02, 0x01, 0x4d]
536        );
537        #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq)]
538        #[rasn(crate_root = "crate")]
539        #[rasn(choice, automatic_tags)]
540        #[non_exhaustive]
541        enum TestChoice {
542            Number1(()),
543            Number2(bool),
544            Number3(Box<TopLevel>),
545        }
546
547        #[derive(AsnType, Debug, Clone, Decode, Encode, PartialEq)]
548        #[rasn(crate_root = "crate")]
549        #[rasn(automatic_tags)]
550        struct TopLevel {
551            #[rasn(value("1..=8"))]
552            pub test: u8,
553            pub choice: TestChoice,
554        }
555
556        impl TopLevel {
557            pub fn new(test: u8, choice: TestChoice) -> Self {
558                Self { test, choice }
559            }
560        }
561
562        let test_value = TopLevel::new(
563            1,
564            TestChoice::Number3(Box::new(TopLevel {
565                test: 2,
566                choice: TestChoice::Number1(()),
567            })),
568        );
569        round_trip!(coer, TopLevel, test_value, &[1, 130, 2, 128]);
570    }
571    #[test]
572    fn test_numeric_string() {
573        round_trip!(
574            coer,
575            NumericString,
576            "123".try_into().unwrap(),
577            &[0x03, 0x31, 0x32, 0x33]
578        );
579        round_trip_with_constraints!(
580            coer,
581            NumericString,
582            Constraints::new(&[Constraint::Size(Size::new(Bounded::Single(3)).into())]),
583            "123".try_into().unwrap(),
584            &[0x31, 0x32, 0x33]
585        );
586        round_trip_with_constraints!(
587            coer,
588            NumericString,
589            Constraints::new(&[Constraint::Size(
590                Size::new(Bounded::Range {
591                    start: Some(3),
592                    end: Some(7)
593                })
594                .into()
595            )]),
596            "123".try_into().unwrap(),
597            &[0x03, 0x31, 0x32, 0x33]
598        );
599    }
600    #[test]
601    fn test_printable_string() {
602        round_trip!(
603            coer,
604            PrintableString,
605            "foo".try_into().unwrap(),
606            &[0x03, 0x66, 0x6f, 0x6f]
607        );
608        round_trip!(
609            coer,
610            PrintableString,
611            " '()+,-./:=?".try_into().unwrap(),
612            &[0x0c, 0x20, 0x27, 0x28, 0x29, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x3a, 0x3d, 0x3f]
613        );
614        round_trip_with_constraints!(
615            coer,
616            PrintableString,
617            Constraints::new(&[Constraint::Size(Size::new(Bounded::Single(3)).into())]),
618            "foo".try_into().unwrap(),
619            &[0x66, 0x6f, 0x6f]
620        );
621        round_trip_with_constraints!(
622            coer,
623            PrintableString,
624            Constraints::new(&[Constraint::Size(
625                Size::new(Bounded::Range {
626                    start: Some(3),
627                    end: Some(7)
628                })
629                .into()
630            )]),
631            "foo".try_into().unwrap(),
632            &[0x03, 0x66, 0x6f, 0x6f]
633        );
634    }
635    #[test]
636    fn test_visible_string() {
637        round_trip!(
638            coer,
639            VisibleString,
640            "foo".try_into().unwrap(),
641            &[0x03, 0x66, 0x6f, 0x6f]
642        );
643        round_trip_with_constraints!(
644            coer,
645            VisibleString,
646            Constraints::new(&[Constraint::Size(Size::new(Bounded::Single(3)).into())]),
647            "foo".try_into().unwrap(),
648            &[0x66, 0x6f, 0x6f]
649        );
650        round_trip_with_constraints!(
651            coer,
652            VisibleString,
653            Constraints::new(&[Constraint::Size(
654                Size::new(Bounded::Range {
655                    start: Some(3),
656                    end: Some(7)
657                })
658                .into()
659            )]),
660            "foo".try_into().unwrap(),
661            &[0x03, 0x66, 0x6f, 0x6f]
662        );
663    }
664    #[test]
665    fn test_ia5_string() {
666        round_trip!(
667            coer,
668            Ia5String,
669            "foo".try_into().unwrap(),
670            &[0x03, 0x66, 0x6f, 0x6f]
671        );
672        round_trip_with_constraints!(
673            coer,
674            Ia5String,
675            Constraints::new(&[Constraint::Size(Size::new(Bounded::Single(3)).into())]),
676            "foo".try_into().unwrap(),
677            &[0x66, 0x6f, 0x6f]
678        );
679        round_trip_with_constraints!(
680            coer,
681            Ia5String,
682            Constraints::new(&[Constraint::Size(
683                Size::new(Bounded::Range {
684                    start: Some(3),
685                    end: Some(7)
686                })
687                .into()
688            )]),
689            "foo".try_into().unwrap(),
690            &[0x03, 0x66, 0x6f, 0x6f]
691        );
692    }
693    #[test]
694    fn test_general_string() {
695        round_trip!(
696            coer,
697            GeneralString,
698            GeneralString::from_bytes("".as_bytes()).unwrap(),
699            &[0x00]
700        );
701        round_trip!(
702            coer,
703            GeneralString,
704            GeneralString::from_bytes("2".as_bytes()).unwrap(),
705            &[0x01, 0x32]
706        );
707    }
708    #[test]
709    fn test_utf8_string() {
710        round_trip!(coer, Utf8String, "".into(), &[0x00]);
711        round_trip!(coer, Utf8String, "2".into(), &[0x01, 0x32]);
712        round_trip!(
713            coer,
714            Utf8String,
715            "2".repeat(128),
716            &[0x81, 0x80]
717                .iter()
718                .chain("2".repeat(128).as_bytes().iter())
719                .copied()
720                .collect::<Vec<_>>()
721        );
722        round_trip!(
723            coer,
724            Utf8String,
725            "ÄÖÄÖÄÖÄÖ12e4Ä".into(),
726            &[
727                0x16, 0xc3, 0x84, 0xc3, 0x96, 0xc3, 0x84, 0xc3, 0x96, 0xc3, 0x84, 0xc3, 0x96, 0xc3,
728                0x84, 0xc3, 0x96, 0x31, 0x32, 0x65, 0x34, 0xc3, 0x84
729            ]
730        );
731        round_trip_with_constraints!(
732            coer,
733            Utf8String,
734            Constraints::new(&[Constraint::Size(Size::new(Bounded::Single(3)).into())]),
735            "foo".into(),
736            &[0x66, 0x6f, 0x6f]
737        );
738    }
739    #[test]
740    fn test_teletext_string() {
741        round_trip!(
742            coer,
743            TeletexString,
744            TeletexString::from("123".as_bytes().to_vec()),
745            &[0x03, 0x31, 0x32, 0x33]
746        );
747    }
748    #[test]
749    fn test_generalized_time() {
750        use chrono::NaiveDate;
751        let offset = chrono::FixedOffset::east_opt(0).unwrap();
752        let dt = NaiveDate::from_ymd_opt(2080, 10, 9)
753            .unwrap()
754            .and_hms_micro_opt(13, 0, 5, 342_000)
755            .unwrap()
756            .and_local_timezone(offset);
757        round_trip!(
758            coer,
759            GeneralizedTime,
760            GeneralizedTime::from(dt.unwrap(),),
761            &[
762                0x13, 0x32, 0x30, 0x38, 0x30, 0x31, 0x30, 0x30, 0x39, 0x31, 0x33, 0x30, 0x30, 0x30,
763                0x35, 0x2e, 0x33, 0x34, 0x32, 0x5a
764            ]
765        );
766
767        let data = [
768            24, 19, 43, 53, 49, 54, 49, 53, 32, 32, 48, 53, 50, 52, 48, 57, 52, 48, 50, 48, 90,
769        ];
770
771        assert!(crate::der::decode::<crate::types::Open>(&data).is_err());
772    }
773    #[test]
774    fn test_utc_time() {
775        // 2019-10-09 13:00:05 UTC
776        // 191009130005Z
777        round_trip!(
778            coer,
779            UtcTime,
780            UtcTime::from(
781                chrono::NaiveDate::from_ymd_opt(2019, 10, 9)
782                    .unwrap()
783                    .and_hms_opt(13, 0, 5)
784                    .unwrap()
785                    .and_utc()
786            ),
787            &[0x0d, 0x31, 0x39, 0x31, 0x30, 0x30, 0x39, 0x31, 0x33, 0x30, 0x30, 0x30, 0x35, 0x5a]
788        );
789    }
790    #[test]
791    /// No extension addition presence bitmap in any test case or preamble
792    /// Or option or defaults
793    fn test_sequence_no_extensions() {
794        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
795        // #[rasn(automatic_tags)]
796        #[rasn(crate_root = "crate")]
797        struct Sequence1 {
798            a: Integer,
799            b: Integer,
800        }
801        round_trip!(
802            coer,
803            Sequence1,
804            Sequence1 {
805                a: 1.into(),
806                b: 2.into()
807            },
808            &[0x01, 0x01, 0x01, 0x02]
809        );
810
811        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
812        #[rasn(automatic_tags)]
813        struct Sequence2 {
814            a: bool,
815        }
816        round_trip!(coer, Sequence2, Sequence2 { a: true }, &[0xff]);
817
818        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
819        #[rasn(automatic_tags)]
820        struct Sequence3 {
821            a: bool,
822            b: Sequence1,
823        }
824        round_trip!(
825            coer,
826            Sequence3,
827            Sequence3 {
828                a: true,
829                b: Sequence1 {
830                    a: 1.into(),
831                    b: 2.into()
832                }
833            },
834            &[0xff, 0x01, 0x01, 0x01, 0x02]
835        );
836        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
837        #[rasn(crate_root = "crate", choice, automatic_tags)]
838        enum Choice1 {
839            A(bool),
840            B(Sequence1),
841        }
842        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
843        #[rasn(crate_root = "crate")]
844        struct Sequence4 {
845            a: Integer,
846            b: Choice1,
847        }
848        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
849        #[rasn(crate_root = "crate")]
850        struct Sequence5 {
851            a: bool,
852            b: Sequence4,
853        }
854        round_trip!(
855            coer,
856            Sequence5,
857            Sequence5 {
858                a: true,
859                b: Sequence4 {
860                    a: 1.into(),
861                    b: Choice1::B(Sequence1 {
862                        a: 1.into(),
863                        b: 2.into()
864                    })
865                }
866            },
867            &[0xff, 0x01, 0x01, 0x81, 0x01, 0x01, 0x01, 0x02]
868        );
869    }
870    #[test]
871    fn test_sequence_default_option() {
872        fn default_a() -> Integer {
873            0.into()
874        }
875        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
876        #[rasn(automatic_tags)]
877        struct Sequence1 {
878            #[rasn(default = "default_a")]
879            a: Integer,
880        }
881        round_trip!(coer, Sequence1, Sequence1 { a: 0.into() }, &[0x00]);
882        round_trip!(
883            coer,
884            Sequence1,
885            Sequence1 { a: 1.into() },
886            &[0b1000_0000, 0x01, 0x01]
887        );
888        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
889        #[rasn(automatic_tags)]
890        struct Sequence2 {
891            a: Integer,
892            b: Option<Integer>,
893        }
894        round_trip!(
895            coer,
896            Sequence2,
897            Sequence2 {
898                a: 1.into(),
899                b: Some(2.into())
900            },
901            &[0b1000_0000, 0x01, 0x01, 0x01, 0x02]
902        );
903        round_trip!(
904            coer,
905            Sequence2,
906            Sequence2 {
907                a: 1.into(),
908                b: None
909            },
910            &[0x00, 0x01, 0x01]
911        );
912        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
913        #[rasn(automatic_tags)]
914        struct Sequence4 {
915            #[rasn(default = "default_a")]
916            a: Integer, // default is 0
917            b: Option<Integer>,
918        }
919        round_trip!(
920            coer,
921            Sequence4,
922            Sequence4 {
923                a: 0.into(),
924                b: None
925            },
926            &[0x00]
927        );
928        round_trip!(
929            coer,
930            Sequence4,
931            Sequence4 {
932                a: 1.into(),
933                b: Some(3.into())
934            },
935            &[0b1100_0000, 0x01, 0x01, 0x01, 0x03]
936        );
937    }
938    #[test]
939    fn test_sequence_with_extensions() {
940        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
941        #[rasn(automatic_tags)]
942        #[non_exhaustive]
943        struct Sequence1 {
944            a: bool,
945        }
946        round_trip!(coer, Sequence1, Sequence1 { a: true }, &[0x00, 0xff]);
947        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
948        #[rasn(automatic_tags)]
949        #[non_exhaustive]
950        struct Sequence2 {
951            a: bool,
952            #[rasn(extension_addition)]
953            b: Option<bool>,
954            #[rasn(extension_addition)]
955            c: Option<bool>,
956        }
957        round_trip!(
958            coer,
959            Sequence2,
960            Sequence2 {
961                a: true,
962                b: Some(true),
963                c: Some(true)
964            },
965            &[0x80, 0xff, 0x02, 0x06, 0xc0, 0x01, 0xff, 0x01, 0xff]
966        );
967        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
968        #[rasn(automatic_tags)]
969        #[non_exhaustive]
970        struct Sequence3 {
971            a: bool,
972            #[rasn(extension_addition_group)]
973            b: Option<Sequence4>,
974        }
975        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
976        #[rasn(automatic_tags)]
977        struct Sequence4 {
978            a: bool,
979        }
980        round_trip!(
981            coer,
982            Sequence3,
983            Sequence3 { a: true, b: None },
984            &[0x00, 0xff]
985        );
986        round_trip!(
987            coer,
988            Sequence3,
989            Sequence3 {
990                a: true,
991                b: Some(Sequence4 { a: true })
992            },
993            &[0x80, 0xff, 0x02, 0x07, 0x80, 0x01, 0xff]
994        );
995        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
996        #[rasn(automatic_tags)]
997        #[non_exhaustive]
998        struct Sequence5 {
999            a: bool,
1000            #[rasn(extension_addition)]
1001            b: Option<bool>,
1002        }
1003        round_trip!(
1004            coer,
1005            Sequence5,
1006            Sequence5 { a: true, b: None },
1007            &[0x00, 0xff]
1008        );
1009        round_trip!(
1010            coer,
1011            Sequence5,
1012            Sequence5 {
1013                a: true,
1014                b: Some(true)
1015            },
1016            &[0x80, 0xff, 0x02, 0x07, 0x80, 0x01, 0xff]
1017        );
1018    }
1019    #[test]
1020    fn test_sequence_of() {
1021        round_trip!(
1022            coer,
1023            SequenceOf::<Integer>,
1024            SequenceOf::<Integer>::from(vec![]),
1025            &[0x01, 0x00]
1026        );
1027        round_trip!(
1028            coer,
1029            SequenceOf::<Integer>,
1030            SequenceOf::<Integer>::from(vec![1.into(), 2.into()]),
1031            &[0x01, 0x02, 0x01, 0x01, 0x01, 0x02]
1032        );
1033    }
1034    #[test]
1035    fn test_set() {
1036        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
1037        #[rasn(set, tag(application, 0))]
1038        struct Foo {
1039            #[rasn(tag(explicit(444)))]
1040            a: Integer,
1041            #[rasn(tag(explicit(5)))]
1042            b: Integer,
1043            #[rasn(tag(application, 9))]
1044            c: Integer,
1045        }
1046        round_trip!(
1047            coer,
1048            Foo,
1049            Foo {
1050                a: 5.into(),
1051                b: 6.into(),
1052                c: 7.into(),
1053            },
1054            &[0x01, 0x07, 0x01, 0x06, 0x01, 0x05]
1055        );
1056    }
1057    #[test]
1058    fn test_sequence_with_nested_opt() {
1059        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
1060        #[rasn(automatic_tags)]
1061        struct Sequence1 {
1062            a: Integer,
1063            b: Option<Integer>,
1064        }
1065        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
1066        #[rasn(automatic_tags)]
1067        struct Sequence2 {
1068            a: Integer,
1069            b: Option<Sequence1>,
1070        }
1071        round_trip!(
1072            coer,
1073            Sequence2,
1074            Sequence2 {
1075                a: 1.into(),
1076                b: Some(Sequence1 {
1077                    a: 2.into(),
1078                    b: Some(3.into())
1079                })
1080            },
1081            &[0x80, 0x01, 0x01, 0x80, 0x01, 0x02, 0x01, 0x03]
1082        );
1083        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
1084        #[rasn(automatic_tags)]
1085        struct Sequence3 {
1086            a: Integer,
1087            b: Sequence2,
1088        }
1089        round_trip!(
1090            coer,
1091            Sequence3,
1092            Sequence3 {
1093                a: 1.into(),
1094                b: Sequence2 {
1095                    a: 2.into(),
1096                    b: Some(Sequence1 {
1097                        a: 3.into(),
1098                        b: Some(4.into())
1099                    })
1100                }
1101            },
1102            &[0x01, 0x01, 0x80, 0x01, 0x02, 0x80, 0x01, 0x03, 0x01, 0x04]
1103        );
1104    }
1105    #[test]
1106    fn test_boxed_sequence() {
1107        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
1108        #[rasn(automatic_tags)]
1109        struct Sequence1 {
1110            a: Integer,
1111            b: Option<Integer>,
1112        }
1113        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
1114        #[rasn(automatic_tags)]
1115        struct Sequence2 {
1116            a: Integer,
1117            b: Box<Sequence1>,
1118        }
1119        round_trip!(
1120            coer,
1121            Sequence2,
1122            Sequence2 {
1123                a: 1.into(),
1124                b: Box::new(Sequence1 {
1125                    a: 2.into(),
1126                    b: Some(3.into())
1127                })
1128            },
1129            &[0x01, 0x01, 0x80, 0x01, 0x02, 0x01, 0x03]
1130        );
1131    }
1132    #[test]
1133    fn test_nested_boxed_sequence() {
1134        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
1135        #[rasn(choice, automatic_tags)]
1136        enum Choice1 {
1137            A(bool),
1138            B(Box<Sequence1>),
1139        }
1140        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
1141        #[rasn(automatic_tags)]
1142        struct Sequence1 {
1143            a: Option<Integer>,
1144            b: Choice1,
1145        }
1146        round_trip!(
1147            coer,
1148            Sequence1,
1149            Sequence1 {
1150                a: Some(1.into()),
1151                b: Choice1::B(Box::new(Sequence1 {
1152                    a: Some(2.into()),
1153                    b: Choice1::A(true)
1154                }))
1155            },
1156            &[0x80, 0x01, 0x01, 0x81, 0x80, 0x01, 0x02, 0x80, 0xff]
1157        );
1158    }
1159    #[test]
1160    fn test_empty_sequence() {
1161        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
1162        #[rasn(automatic_tags)]
1163        struct Sequence1 {}
1164        round_trip!(coer, Sequence1, Sequence1 {}, &[]);
1165
1166        // Only optional fields, all empty
1167        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
1168        #[rasn(automatic_tags)]
1169        struct Sequence2 {
1170            a: Option<Integer>,
1171            b: Option<Integer>,
1172        }
1173        round_trip!(coer, Sequence2, Sequence2 { a: None, b: None }, &[0x00]);
1174        // Only default values
1175        #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
1176        #[rasn(automatic_tags)]
1177        struct Sequence3 {
1178            #[rasn(default = "default_a")]
1179            a: Integer,
1180            #[rasn(default = "default_b")]
1181            b: Integer,
1182        }
1183        fn default_a() -> Integer {
1184            0.into()
1185        }
1186        fn default_b() -> Integer {
1187            1.into()
1188        }
1189        round_trip!(
1190            coer,
1191            Sequence3,
1192            Sequence3 {
1193                a: 0.into(),
1194                b: 1.into()
1195            },
1196            &[0x00]
1197        );
1198    }
1199}