Skip to main content

rasn/
jer.rs

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