1pub mod de;
4pub mod enc;
5
6pub fn decode<T: crate::Decode>(input: &str) -> Result<T, crate::error::DecodeError> {
10 T::decode(&mut de::Decoder::new(input)?)
11}
12
13pub 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 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 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}