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