rasn/
jer.rs

1pub mod de;
2pub mod enc;
3
4/// Attempts to decode `T` from `input` using JER.
5/// # Errors
6/// Returns error specific to JER decoder if decoding is not possible.
7pub fn decode<T: crate::Decode>(input: &str) -> Result<T, crate::error::DecodeError> {
8    T::decode(&mut de::Decoder::new(input)?)
9}
10
11/// Attempts to encode `value` to JER.
12/// # Errors
13/// Returns error specific to JER encoder if encoding is not possible.
14pub fn encode<T: crate::Encode>(
15    value: &T,
16) -> Result<alloc::string::String, crate::error::EncodeError> {
17    let mut encoder = enc::Encoder::new();
18    value.encode(&mut encoder)?;
19    Ok(encoder.to_json())
20}
21
22#[cfg(test)]
23mod tests {
24    macro_rules! round_trip_jer {
25        ($typ:ty, $value:expr, $expected:expr) => {{
26            let value: $typ = $value;
27            let expected: &'static str = $expected;
28            let actual_encoding = crate::jer::encode(&value).unwrap();
29
30            pretty_assertions::assert_eq!(expected, &*actual_encoding);
31
32            let decoded_value: $typ = crate::jer::decode(&actual_encoding).unwrap();
33
34            pretty_assertions::assert_eq!(value, decoded_value);
35        }};
36    }
37
38    macro_rules! round_trip_string_type {
39        ($typ:ty) => {{
40            let string = String::from(" 1234567890");
41            let expected: &'static str = "\" 1234567890\"";
42            let value: $typ = string.try_into().unwrap();
43            let actual_encoding = crate::jer::encode(&value).unwrap();
44
45            pretty_assertions::assert_eq!(expected, &actual_encoding);
46
47            let decoded_value: $typ = crate::jer::decode(&actual_encoding).unwrap();
48
49            pretty_assertions::assert_eq!(value, decoded_value);
50        }};
51    }
52
53    use crate::prelude::*;
54
55    #[derive(AsnType, Decode, Encode, Debug, PartialEq)]
56    #[rasn(automatic_tags)]
57    #[rasn(crate_root = "crate")]
58    #[non_exhaustive]
59    struct TestTypeA {
60        #[rasn(value("0..3", extensible))]
61        juice: Integer,
62        wine: Inner,
63        #[rasn(extension_addition)]
64        grappa: BitString,
65    }
66
67    #[derive(AsnType, Decode, Encode, Debug, PartialEq)]
68    #[rasn(choice, automatic_tags)]
69    #[rasn(crate_root = "crate")]
70    enum Inner {
71        #[rasn(value("0..3"))]
72        Wine(u8),
73    }
74
75    #[derive(AsnType, Decode, Encode, Debug, Clone, Copy, PartialEq)]
76    #[rasn(automatic_tags, enumerated)]
77    #[rasn(crate_root = "crate")]
78    enum SimpleEnum {
79        Test1 = 5,
80        Test2 = 2,
81    }
82
83    #[derive(AsnType, Decode, Encode, Debug, Clone, Copy, PartialEq)]
84    #[rasn(automatic_tags, enumerated)]
85    #[rasn(crate_root = "crate")]
86    #[non_exhaustive]
87    enum ExtEnum {
88        Test1 = 5,
89        Test2 = 2,
90        #[rasn(extension_addition)]
91        Test3 = -1,
92    }
93
94    #[derive(AsnType, Decode, Encode, Debug, Clone, PartialEq, Ord, Eq, PartialOrd)]
95    #[rasn(automatic_tags, choice)]
96    #[rasn(crate_root = "crate")]
97    enum SimpleChoice {
98        Test1(u8),
99        #[rasn(size("0..3"))]
100        Test2(Utf8String),
101    }
102
103    #[derive(AsnType, Decode, Encode, Debug, Clone, PartialEq)]
104    #[rasn(automatic_tags, choice)]
105    #[rasn(crate_root = "crate")]
106    #[non_exhaustive]
107    enum ExtChoice {
108        Test1(u8),
109        #[rasn(size("0..3"))]
110        Test2(Utf8String),
111        #[rasn(extension_addition)]
112        Test3(bool),
113    }
114
115    #[derive(AsnType, Decode, Encode, Debug, PartialEq)]
116    #[rasn(automatic_tags)]
117    #[rasn(crate_root = "crate")]
118    #[non_exhaustive]
119    struct Very {
120        #[rasn(extension_addition)]
121        a: Option<Nested>,
122    }
123
124    #[derive(AsnType, Decode, Encode, Debug, PartialEq)]
125    #[rasn(automatic_tags)]
126    #[rasn(crate_root = "crate")]
127    struct Nested {
128        very: Option<Struct>,
129        nested: Option<bool>,
130    }
131
132    #[derive(AsnType, Decode, Encode, Debug, PartialEq)]
133    #[rasn(automatic_tags)]
134    #[rasn(crate_root = "crate")]
135    struct Struct {
136        strct: Option<u8>,
137    }
138
139    #[derive(AsnType, Decode, Encode, Debug, PartialEq)]
140    #[rasn(crate_root = "crate", delegate, size("3", extensible))]
141    struct ConstrainedOctetString(pub OctetString);
142
143    #[derive(AsnType, Decode, Encode, Debug, PartialEq)]
144    #[rasn(crate_root = "crate", delegate, value("-5..=5", extensible))]
145    struct ConstrainedInt(pub Integer);
146
147    #[derive(AsnType, Decode, Encode, Debug, PartialEq)]
148    #[rasn(crate_root = "crate", delegate, size("3"))]
149    struct ConstrainedBitString(pub BitString);
150
151    #[derive(AsnType, Decode, Encode, Debug, PartialEq)]
152    #[rasn(automatic_tags)]
153    #[rasn(crate_root = "crate")]
154    struct Renamed {
155        #[rasn(identifier = "so-very")]
156        very: Integer,
157        #[rasn(identifier = "re_named")]
158        renamed: Option<bool>,
159    }
160
161    #[derive(AsnType, Decode, Encode, Debug, Clone, PartialEq)]
162    #[rasn(automatic_tags, choice)]
163    #[rasn(crate_root = "crate")]
164    enum Renumed {
165        #[rasn(identifier = "test-1")]
166        #[rasn(size("0..3"))]
167        Test1(Utf8String),
168    }
169
170    #[test]
171    fn bool() {
172        round_trip_jer!(bool, true, "true");
173        round_trip_jer!(bool, false, "false");
174    }
175
176    #[test]
177    fn integer() {
178        round_trip_jer!(u8, 1, "1");
179        round_trip_jer!(i8, -1, "-1");
180        round_trip_jer!(u16, 0, "0");
181        round_trip_jer!(i16, -14321, "-14321");
182        round_trip_jer!(i64, -1213428598524996264, "-1213428598524996264");
183        round_trip_jer!(Integer, 1.into(), "1");
184        round_trip_jer!(Integer, (-1235352).into(), "-1235352");
185        round_trip_jer!(ConstrainedInt, ConstrainedInt(1.into()), "1");
186    }
187
188    #[test]
189    fn bit_string() {
190        round_trip_jer!(
191            BitString,
192            BitString::from_iter([true, false].into_iter()),
193            r#"{"value":"80","length":2}"#
194        );
195        round_trip_jer!(
196            ConstrainedBitString,
197            ConstrainedBitString(BitString::from_iter([true, false, true].into_iter())),
198            "\"A0\""
199        );
200    }
201
202    #[test]
203    fn octet_string() {
204        round_trip_jer!(OctetString, OctetString::from_static(&[1, 255]), "\"01FF\"");
205        round_trip_jer!(
206            ConstrainedOctetString,
207            ConstrainedOctetString(OctetString::from_static(&[1, 255, 0, 254])),
208            "\"01FF00FE\""
209        );
210    }
211
212    #[test]
213    fn object_identifier() {
214        round_trip_jer!(
215            ObjectIdentifier,
216            ObjectIdentifier::from(Oid::JOINT_ISO_ITU_T_DS_NAME_FORM),
217            "\"2.5.15\""
218        );
219    }
220
221    #[test]
222    fn string_types() {
223        round_trip_string_type!(NumericString);
224        round_trip_string_type!(GeneralString);
225        round_trip_string_type!(VisibleString);
226        round_trip_string_type!(UniversalString);
227        round_trip_string_type!(PrintableString);
228        round_trip_string_type!(Ia5String);
229        round_trip_string_type!(Utf8String);
230    }
231
232    #[test]
233    fn enumerated() {
234        round_trip_jer!(SimpleEnum, SimpleEnum::Test1, "\"Test1\"");
235        round_trip_jer!(SimpleEnum, SimpleEnum::Test2, "\"Test2\"");
236        round_trip_jer!(ExtEnum, ExtEnum::Test1, "\"Test1\"");
237        round_trip_jer!(ExtEnum, ExtEnum::Test2, "\"Test2\"");
238        round_trip_jer!(ExtEnum, ExtEnum::Test3, "\"Test3\"");
239    }
240
241    #[test]
242    fn choice() {
243        round_trip_jer!(SimpleChoice, SimpleChoice::Test1(3), "{\"Test1\":3}");
244        round_trip_jer!(
245            SimpleChoice,
246            SimpleChoice::Test2("foo".into()),
247            "{\"Test2\":\"foo\"}"
248        );
249        round_trip_jer!(ExtChoice, ExtChoice::Test1(255), "{\"Test1\":255}");
250        round_trip_jer!(
251            ExtChoice,
252            ExtChoice::Test2("bar".into()),
253            "{\"Test2\":\"bar\"}"
254        );
255        round_trip_jer!(ExtChoice, ExtChoice::Test3(true), "{\"Test3\":true}");
256    }
257
258    #[test]
259    fn sequence_of() {
260        round_trip_jer!(
261            SequenceOf<SimpleChoice>,
262            alloc::vec![SimpleChoice::Test1(3)],
263            "[{\"Test1\":3}]"
264        );
265        round_trip_jer!(
266            SequenceOf<u8>,
267            alloc::vec![1, 2, 3, 4, 5, 5, 3],
268            "[1,2,3,4,5,5,3]"
269        );
270        round_trip_jer!(SequenceOf<bool>, alloc::vec![], "[]");
271    }
272
273    #[test]
274    fn set_of() {
275        round_trip_jer!(
276            SetOf<SimpleChoice>,
277            alloc::vec![SimpleChoice::Test1(3)].into_iter().collect(),
278            "[{\"Test1\":3}]"
279        );
280        round_trip_jer!(
281            SetOf<u8>,
282            alloc::vec![1, 2, 3, 4, 5].into_iter().collect(),
283            "[1,2,3,4,5]"
284        );
285        round_trip_jer!(SetOf<bool>, alloc::vec![].into_iter().collect(), "[]");
286    }
287
288    #[test]
289    fn seqence() {
290        round_trip_jer!(
291            TestTypeA,
292            TestTypeA {
293                juice: 0.into(),
294                wine: Inner::Wine(4),
295                grappa: BitString::from_iter([true, false].iter())
296            },
297            r#"{"juice":0,"wine":{"Wine":4},"grappa":{"value":"80","length":2}}"#
298        );
299        round_trip_jer!(
300            Very,
301            Very {
302                a: Some(Nested {
303                    very: Some(Struct { strct: None }),
304                    nested: Some(false)
305                })
306            },
307            "{\"a\":{\"very\":{},\"nested\":false}}"
308        );
309    }
310
311    #[test]
312    fn with_identifier_annotation() {
313        round_trip_jer!(
314            Renamed,
315            Renamed {
316                very: 1.into(),
317                renamed: Some(true),
318            },
319            r#"{"so-very":1,"re_named":true}"#
320        );
321
322        round_trip_jer!(Renumed, Renumed::Test1("hel".into()), r#"{"test-1":"hel"}"#);
323    }
324}