1use serde_json::Value;
4
5use crate::{
6 Decode,
7 de::Error,
8 error::{DecodeError, JerDecodeErrorKind},
9 types::{
10 Any, BitString, BmpString, Constraints, Constructed, Date, DecodeChoice, Enumerated,
11 GeneralString, GeneralizedTime, GraphicString, Ia5String, NumericString, ObjectIdentifier,
12 Oid, PrintableString, SequenceOf, SetOf, Tag, TeletexString, UtcTime, Utf8String,
13 VisibleString, variants,
14 },
15};
16
17macro_rules! decode_jer_value {
18 ($decoder_fn:expr, $input:expr) => {
19 $input
20 .pop()
21 .ok_or_else(|| DecodeError::from(JerDecodeErrorKind::eoi()))
22 .and_then($decoder_fn)
23 };
24}
25
26pub struct Decoder {
28 stack: alloc::vec::Vec<Value>,
29}
30
31impl Decoder {
32 pub fn new(input: &str) -> Result<Self, <Decoder as crate::de::Decoder>::Error> {
34 let root = serde_json::from_str(input).map_err(|e| {
35 DecodeError::parser_fail(
36 alloc::format!("Error parsing JER JSON {e:?}"),
37 crate::Codec::Jer,
38 )
39 })?;
40 Ok(Self {
41 stack: alloc::vec![root],
42 })
43 }
44}
45
46impl From<Value> for Decoder {
47 fn from(value: Value) -> Self {
48 Self {
49 stack: alloc::vec![value],
50 }
51 }
52}
53
54impl crate::Decoder for Decoder {
55 type Ok = ();
56 type Error = DecodeError;
57 type AnyDecoder<const R: usize, const E: usize> = Self;
58
59 fn decode_any(&mut self, _tag: Tag) -> Result<Any, Self::Error> {
60 decode_jer_value!(Self::any_from_value, self.stack)
61 }
62
63 fn decode_bit_string(
64 &mut self,
65 _t: Tag,
66 constraints: Constraints,
67 ) -> Result<BitString, Self::Error> {
68 let (mut padded, bitstring_length) = if let Some(size) = constraints
69 .size()
70 .and_then(|s| s.constraint.is_fixed().then_some(s.constraint.as_start()))
71 .flatten()
72 {
73 let value = BitString::try_from_vec(decode_jer_value!(
74 Self::octet_string_from_value,
75 self.stack
76 )?)
77 .map_err(|e| {
78 DecodeError::custom(
79 alloc::format!("Failed to create BitString from bytes: {e:02x?}"),
80 self.codec(),
81 )
82 })?;
83 (value, *size)
84 } else {
85 let last = self.stack.pop().ok_or_else(JerDecodeErrorKind::eoi)?;
86 let value_map = last
87 .as_object()
88 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
89 needed: "object",
90 found: "unknown".into(),
91 })?;
92 let (value, length) = value_map
93 .get("value")
94 .and_then(|v| v.as_str())
95 .zip(
96 value_map
97 .get("length")
98 .and_then(|l| l.as_number())
99 .and_then(|i| i.as_u64())
100 .map(|i| i as usize),
101 )
102 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
103 needed: "JSON object containing 'value' and 'length' properties.",
104 found: alloc::format!("{value_map:#?}"),
105 })?;
106
107 let value = bytes_from_hexstring(value).ok_or(DecodeError::custom(
108 alloc::format!("Failed to create BitString from bytes: {value:02x?}"),
109 self.codec(),
110 ))?;
111 let value = BitString::try_from_vec(value).map_err(|e| {
112 DecodeError::custom(
113 alloc::format!("Failed to create BitString from bytes: {e:02x?}"),
114 self.codec(),
115 )
116 })?;
117
118 (value, length)
119 };
120 let padding_length = if bitstring_length % 8 == 0 {
121 0
122 } else {
123 8 - (bitstring_length % 8)
124 };
125 for _ in 0..padding_length {
126 padded.pop();
127 }
128
129 if bitstring_length == padded.len() {
130 Ok(padded)
131 } else {
132 Err(DecodeError::custom(
133 alloc::format!(
134 "Failed to create BitString from bytes: invalid value length (was: {}, expected: {})",
135 padded.len(),
136 bitstring_length
137 ),
138 self.codec(),
139 ))
140 }
141 }
142
143 fn decode_bool(&mut self, _t: Tag) -> Result<bool, Self::Error> {
144 decode_jer_value!(Self::boolean_from_value, self.stack)
145 }
146
147 fn decode_enumerated<E: Enumerated>(&mut self, _t: Tag) -> Result<E, Self::Error> {
148 decode_jer_value!(Self::enumerated_from_value, self.stack)
149 }
150
151 fn decode_integer<I: crate::types::IntegerType>(
152 &mut self,
153 _t: Tag,
154 _c: Constraints,
155 ) -> Result<I, Self::Error> {
156 decode_jer_value!(Self::integer_from_value::<I>, self.stack)
157 }
158
159 fn decode_real<R: crate::types::RealType>(
160 &mut self,
161 _t: Tag,
162 _c: Constraints,
163 ) -> Result<R, Self::Error> {
164 decode_jer_value!(Self::real_from_value::<R>, self.stack)
165 }
166
167 fn decode_null(&mut self, _t: Tag) -> Result<(), Self::Error> {
168 decode_jer_value!(Self::null_from_value, self.stack)
169 }
170
171 fn decode_object_identifier(&mut self, _t: Tag) -> Result<ObjectIdentifier, Self::Error> {
172 decode_jer_value!(Self::object_identifier_from_value, self.stack)
173 }
174
175 fn decode_sequence<const RC: usize, const EC: usize, D, DF, F>(
176 &mut self,
177 _: Tag,
178 _: Option<DF>,
179 decode_fn: F,
180 ) -> Result<D, Self::Error>
181 where
182 D: Constructed<RC, EC>,
183 F: FnOnce(&mut Self) -> Result<D, Self::Error>,
184 {
185 let mut last = self.stack.pop().ok_or_else(JerDecodeErrorKind::eoi)?;
186 let value_map = last
187 .as_object_mut()
188 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
189 needed: "object",
190 found: "unknown".into(),
191 })?;
192 let mut field_names = D::FIELDS
193 .iter()
194 .map(|f| f.name)
195 .collect::<alloc::vec::Vec<&str>>();
196 if let Some(extended_fields) = D::EXTENDED_FIELDS {
197 field_names.extend(extended_fields.iter().map(|f| f.name));
198 }
199 field_names.reverse();
200 for name in field_names {
201 self.stack
202 .push(value_map.remove(name).unwrap_or(Value::Null));
203 }
204
205 (decode_fn)(self)
206 }
207
208 fn decode_sequence_of<D: crate::Decode>(
209 &mut self,
210 _t: Tag,
211 _c: Constraints,
212 ) -> Result<SequenceOf<D>, Self::Error> {
213 decode_jer_value!(|v| self.sequence_of_from_value(v), self.stack)
214 }
215
216 fn decode_set_of<D: crate::Decode + Eq + core::hash::Hash>(
217 &mut self,
218 _t: Tag,
219 _c: Constraints,
220 ) -> Result<SetOf<D>, Self::Error> {
221 decode_jer_value!(|v| self.set_of_from_value(v), self.stack)
222 }
223
224 fn decode_octet_string<'b, T: From<alloc::vec::Vec<u8>> + From<&'b [u8]>>(
225 &'b mut self,
226 _: Tag,
227 _c: Constraints,
228 ) -> Result<T, Self::Error> {
229 decode_jer_value!(Self::octet_string_from_value, self.stack).map(T::from)
230 }
231
232 fn decode_utf8_string(&mut self, _t: Tag, _c: Constraints) -> Result<Utf8String, Self::Error> {
233 decode_jer_value!(Self::string_from_value, self.stack)
234 }
235
236 fn decode_visible_string(
237 &mut self,
238 _t: Tag,
239 _c: Constraints,
240 ) -> Result<VisibleString, Self::Error> {
241 decode_jer_value!(Self::string_from_value, self.stack)?
242 .try_into()
243 .map_err(|e| {
244 DecodeError::string_conversion_failed(
245 Tag::VISIBLE_STRING,
246 alloc::format!("Error transforming VisibleString: {e:?}"),
247 crate::Codec::Jer,
248 )
249 })
250 }
251
252 fn decode_general_string(
253 &mut self,
254 _t: Tag,
255 _c: Constraints,
256 ) -> Result<GeneralString, Self::Error> {
257 decode_jer_value!(Self::string_from_value, self.stack)?
258 .try_into()
259 .map_err(|e| {
260 DecodeError::string_conversion_failed(
261 Tag::GENERAL_STRING,
262 alloc::format!("Error transforming GeneralString: {e:?}"),
263 crate::Codec::Jer,
264 )
265 })
266 }
267
268 fn decode_graphic_string(
269 &mut self,
270 _t: Tag,
271 _c: Constraints,
272 ) -> Result<GraphicString, Self::Error> {
273 decode_jer_value!(Self::string_from_value, self.stack)?
274 .try_into()
275 .map_err(|e| {
276 DecodeError::string_conversion_failed(
277 Tag::GRAPHIC_STRING,
278 alloc::format!("Error transforming GeneralString: {e:?}"),
279 crate::Codec::Jer,
280 )
281 })
282 }
283
284 fn decode_ia5_string(&mut self, _t: Tag, _c: Constraints) -> Result<Ia5String, Self::Error> {
285 decode_jer_value!(Self::string_from_value, self.stack)?
286 .try_into()
287 .map_err(|e| {
288 DecodeError::string_conversion_failed(
289 Tag::IA5_STRING,
290 alloc::format!("Error transforming IA5String: {e:?}"),
291 crate::Codec::Jer,
292 )
293 })
294 }
295
296 fn decode_printable_string(
297 &mut self,
298 _t: Tag,
299 _c: Constraints,
300 ) -> Result<PrintableString, Self::Error> {
301 decode_jer_value!(Self::string_from_value, self.stack)?
302 .try_into()
303 .map_err(|e| {
304 DecodeError::string_conversion_failed(
305 Tag::PRINTABLE_STRING,
306 alloc::format!("Error transforming PrintableString: {e:?}"),
307 crate::Codec::Jer,
308 )
309 })
310 }
311
312 fn decode_numeric_string(
313 &mut self,
314 _t: Tag,
315 _c: Constraints,
316 ) -> Result<NumericString, Self::Error> {
317 decode_jer_value!(Self::string_from_value, self.stack)?
318 .try_into()
319 .map_err(|e| {
320 DecodeError::string_conversion_failed(
321 Tag::NUMERIC_STRING,
322 alloc::format!("Error transforming NumericString: {e:?}"),
323 crate::Codec::Jer,
324 )
325 })
326 }
327
328 fn decode_teletex_string(
329 &mut self,
330 _t: Tag,
331 _c: Constraints,
332 ) -> Result<TeletexString, Self::Error> {
333 todo!()
334 }
335
336 fn decode_bmp_string(&mut self, _t: Tag, _c: Constraints) -> Result<BmpString, Self::Error> {
337 decode_jer_value!(Self::string_from_value, self.stack)?
338 .try_into()
339 .map_err(|e| {
340 DecodeError::string_conversion_failed(
341 Tag::BMP_STRING,
342 alloc::format!("Error transforming BMPString: {e:?}"),
343 crate::Codec::Jer,
344 )
345 })
346 }
347 fn decode_optional_with_explicit_prefix<D: Decode>(
348 &mut self,
349 _: Tag,
350 ) -> Result<Option<D>, Self::Error> {
351 self.decode_optional()
352 }
353
354 fn decode_explicit_prefix<D: crate::Decode>(&mut self, _t: Tag) -> Result<D, Self::Error> {
355 D::decode(self)
356 }
357
358 fn decode_utc_time(&mut self, _t: Tag) -> Result<UtcTime, Self::Error> {
359 decode_jer_value!(Self::utc_time_from_value, self.stack)
360 }
361
362 fn decode_generalized_time(&mut self, _t: Tag) -> Result<GeneralizedTime, Self::Error> {
363 decode_jer_value!(Self::general_time_from_value, self.stack)
364 }
365
366 fn decode_date(&mut self, _t: Tag) -> Result<Date, Self::Error> {
367 decode_jer_value!(Self::date_from_value, self.stack)
368 }
369
370 fn decode_set<const RC: usize, const EC: usize, FIELDS, SET, D, F>(
371 &mut self,
372 _t: Tag,
373 decode_fn: D,
374 field_fn: F,
375 ) -> Result<SET, Self::Error>
376 where
377 SET: crate::Decode + Constructed<RC, EC>,
378 FIELDS: crate::Decode,
379 D: Fn(&mut Self::AnyDecoder<RC, EC>, usize, Tag) -> Result<FIELDS, Self::Error>,
380 F: FnOnce(alloc::vec::Vec<FIELDS>) -> Result<SET, Self::Error>,
381 {
382 let mut last = self.stack.pop().ok_or_else(JerDecodeErrorKind::eoi)?;
383 let value_map = last
384 .as_object_mut()
385 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
386 needed: "object",
387 found: "unknown".into(),
388 })?;
389 let mut field_indices = SET::FIELDS
390 .iter()
391 .enumerate()
392 .collect::<alloc::vec::Vec<_>>();
393 let mut fields = alloc::vec![];
394 field_indices
395 .sort_by(|(_, a), (_, b)| a.tag_tree.smallest_tag().cmp(&b.tag_tree.smallest_tag()));
396 for (index, field) in field_indices.into_iter() {
397 self.stack
398 .push(value_map.remove(field.name).unwrap_or(Value::Null));
399 fields.push((decode_fn)(self, index, field.tag)?);
400 }
401
402 for (index, field) in SET::EXTENDED_FIELDS
403 .iter()
404 .flat_map(|fields| fields.iter())
405 .enumerate()
406 {
407 self.stack
408 .push(value_map.remove(field.name).unwrap_or(Value::Null));
409 fields.push((decode_fn)(self, index + SET::FIELDS.len(), field.tag)?);
410 }
411
412 (field_fn)(fields)
413 }
414
415 fn decode_choice<D>(&mut self, _c: Constraints) -> Result<D, Self::Error>
416 where
417 D: DecodeChoice,
418 {
419 decode_jer_value!(|v| self.choice_from_value::<D>(v), self.stack)
420 }
421
422 fn decode_optional<D: crate::Decode>(&mut self) -> Result<Option<D>, Self::Error> {
423 let last = self.stack.pop().ok_or_else(JerDecodeErrorKind::eoi)?;
424 match last {
425 Value::Null => Ok(None),
426 v => {
427 self.stack.push(v);
428 Some(D::decode(self)).transpose()
429 }
430 }
431 }
432
433 fn decode_optional_with_tag<D: crate::Decode>(
434 &mut self,
435 _: Tag,
436 ) -> Result<Option<D>, Self::Error> {
437 self.decode_optional()
438 }
439
440 fn decode_optional_with_constraints<D: crate::Decode>(
441 &mut self,
442 _: Constraints,
443 ) -> Result<Option<D>, Self::Error> {
444 self.decode_optional()
445 }
446
447 fn decode_optional_with_tag_and_constraints<D: crate::Decode>(
448 &mut self,
449 _t: Tag,
450 _c: Constraints,
451 ) -> Result<Option<D>, Self::Error> {
452 self.decode_optional()
453 }
454
455 fn decode_extension_addition_with_explicit_tag_and_constraints<D>(
456 &mut self,
457 tag: Tag,
458 constraints: Constraints,
459 ) -> core::result::Result<Option<D>, Self::Error>
460 where
461 D: Decode,
462 {
463 self.decode_extension_addition_with_tag_and_constraints::<D>(tag, constraints)
464 }
465
466 fn decode_extension_addition_with_tag_and_constraints<D>(
467 &mut self,
468 _: Tag,
469 _: Constraints,
470 ) -> Result<Option<D>, Self::Error>
471 where
472 D: crate::Decode,
473 {
474 self.decode_optional()
475 }
476
477 fn decode_extension_addition_group<
478 const RC: usize,
479 const EC: usize,
480 D: crate::Decode + Constructed<RC, EC>,
481 >(
482 &mut self,
483 ) -> Result<Option<D>, Self::Error> {
484 self.decode_optional()
485 }
486
487 fn codec(&self) -> crate::Codec {
488 crate::Codec::Jer
489 }
490}
491
492impl Decoder {
499 fn any_from_value(value: Value) -> Result<Any, <Self as crate::de::Decoder>::Error> {
500 Ok(Any::new(alloc::format!("{value}").as_bytes().to_vec()))
501 }
502
503 fn boolean_from_value(value: Value) -> Result<bool, DecodeError> {
504 Ok(value
505 .as_bool()
506 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
507 needed: "boolean",
508 found: alloc::format!("{value}"),
509 })?)
510 }
511
512 fn enumerated_from_value<E: Enumerated>(value: Value) -> Result<E, DecodeError> {
513 let identifier = value
514 .as_str()
515 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
516 needed: "enumerated item as string",
517 found: alloc::format!("{value}"),
518 })?;
519 Ok(E::from_identifier(identifier).ok_or_else(|| {
520 JerDecodeErrorKind::InvalidEnumDiscriminant {
521 discriminant: alloc::string::String::from(identifier),
522 }
523 })?)
524 }
525
526 fn integer_from_value<I: crate::types::IntegerType>(value: Value) -> Result<I, DecodeError> {
527 value
528 .as_i64()
529 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
530 needed: "number (supported range -2^63..2^63)",
531 found: alloc::format!("{value}"),
532 })?
533 .try_into()
534 .map_err(|_| DecodeError::integer_overflow(I::WIDTH, crate::Codec::Jer))
535 }
536
537 fn real_from_value<R: crate::types::RealType>(value: Value) -> Result<R, DecodeError> {
538 if let Some(as_f64) = value.as_f64() {
539 return R::try_from_float(as_f64).ok_or_else(|| {
540 JerDecodeErrorKind::TypeMismatch {
541 needed: "number (double precision floating point)",
542 found: alloc::format!("{value}"),
543 }
544 .into()
545 });
546 }
547
548 value
549 .as_str()
550 .and_then(|s| match s {
551 "-0" => R::try_from_float(-0.0),
552 "INF" => R::try_from_float(f64::INFINITY),
553 "-INF" => R::try_from_float(f64::NEG_INFINITY),
554 "NAN" => R::try_from_float(f64::NAN),
555 _ => None,
556 })
557 .ok_or_else(|| {
558 JerDecodeErrorKind::TypeMismatch {
559 needed: "number (double precision floating point)",
560 found: alloc::format!("{value}"),
561 }
562 .into()
563 })
564 }
565
566 fn null_from_value(value: Value) -> Result<(), DecodeError> {
567 Ok(value
568 .is_null()
569 .then_some(())
570 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
571 needed: "null",
572 found: alloc::format!("{value}"),
573 })?)
574 }
575
576 fn object_identifier_from_value(value: Value) -> Result<ObjectIdentifier, DecodeError> {
577 #[allow(clippy::unnecessary_lazy_evaluations)]
579 Ok(value
580 .as_str()
581 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
582 needed: "number array",
583 found: alloc::format!("{value}"),
584 })?
585 .split('.')
586 .map(|arc| {
587 arc.parse::<u32>()
588 .map_err(|_| JerDecodeErrorKind::TypeMismatch {
589 needed: "OID arc number",
590 found: arc.into(),
591 })
592 })
593 .collect::<Result<alloc::vec::Vec<u32>, _>>()
594 .ok()
595 .and_then(|arcs| Oid::new(&arcs).map(ObjectIdentifier::from))
596 .ok_or_else(|| JerDecodeErrorKind::InvalidOIDString { value })?)
597 }
598
599 fn sequence_of_from_value<D: Decode>(
600 &mut self,
601 value: Value,
602 ) -> Result<SequenceOf<D>, DecodeError> {
603 value
604 .as_array()
605 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
606 needed: "array",
607 found: alloc::format!("{value}"),
608 })?
609 .clone()
610 .into_iter()
611 .map(|v| {
612 self.stack.push(v);
613 D::decode(self)
614 })
615 .collect()
616 }
617
618 fn set_of_from_value<D: Decode + Eq + core::hash::Hash>(
619 &mut self,
620 value: Value,
621 ) -> Result<SetOf<D>, DecodeError> {
622 value
623 .as_array()
624 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
625 needed: "array",
626 found: alloc::format!("{value}"),
627 })?
628 .clone()
629 .into_iter()
630 .try_fold(SetOf::new(), |mut acc, v| {
631 self.stack.push(v);
632 acc.insert(D::decode(self)?);
633 Ok(acc)
634 })
635 }
636
637 fn string_from_value(value: Value) -> Result<alloc::string::String, DecodeError> {
638 Ok(value
639 .as_str()
640 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
641 needed: "string",
642 found: alloc::format!("{value}"),
643 })
644 .map(|n| n.into())?)
645 }
646
647 fn choice_from_value<D>(&mut self, value: Value) -> Result<D, DecodeError>
648 where
649 D: DecodeChoice,
650 {
651 let tag = value
652 .as_object()
653 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
654 needed: "object",
655 found: alloc::format!("{value}"),
656 })?
657 .iter()
658 .next()
659 .and_then(|(k, v)| {
660 D::IDENTIFIERS
661 .iter()
662 .enumerate()
663 .find(|id| id.1.eq_ignore_ascii_case(k))
664 .map(|(i, _)| (i, v))
665 })
666 .map_or(Tag::EOC, |(i, v)| {
667 match variants::Variants::from_slice(
668 &[D::VARIANTS, D::EXTENDED_VARIANTS.unwrap_or(&[])].concat(),
669 )
670 .get(i)
671 {
672 Some(t) => {
673 self.stack.push(v.clone());
674 *t
675 }
676 None => Tag::EOC,
677 }
678 });
679 D::from_tag(self, tag)
680 }
681
682 fn octet_string_from_value(value: Value) -> Result<alloc::vec::Vec<u8>, DecodeError> {
683 let octet_string = value
684 .as_str()
685 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
686 needed: "hex string",
687 found: alloc::format!("{value}"),
688 })?;
689 bytes_from_hexstring(octet_string)
690 .ok_or(JerDecodeErrorKind::InvalidJerOctetString {}.into())
691 }
692
693 fn utc_time_from_value(value: Value) -> Result<chrono::DateTime<chrono::Utc>, DecodeError> {
694 crate::ber::de::Decoder::parse_any_utc_time_string(
695 value
696 .as_str()
697 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
698 needed: "time string",
699 found: alloc::format!("{value}"),
700 })?
701 .into(),
702 )
703 }
704
705 fn general_time_from_value(
706 value: Value,
707 ) -> Result<chrono::DateTime<chrono::FixedOffset>, DecodeError> {
708 crate::ber::de::Decoder::parse_any_generalized_time_string(
709 value
710 .as_str()
711 .ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
712 needed: "time string",
713 found: alloc::format!("{value}"),
714 })?
715 .into(),
716 )
717 }
718
719 fn date_from_value(value: Value) -> Result<chrono::NaiveDate, DecodeError> {
720 crate::ber::de::Decoder::parse_date_string(value.as_str().ok_or_else(|| {
721 JerDecodeErrorKind::TypeMismatch {
722 needed: "date string",
723 found: alloc::format!("{value}"),
724 }
725 })?)
726 }
727}
728
729fn bytes_from_hexstring(hex_string: &str) -> Option<alloc::vec::Vec<u8>> {
731 if !hex_string.len().is_multiple_of(2) {
732 return None;
733 }
734 let mut bytes = alloc::vec::Vec::<u8>::with_capacity(hex_string.len() / 2);
735 for (i, c) in hex_string.char_indices() {
736 let n = nibble_from_hexdigit(c)?;
737 if i % 2 == 0 {
738 bytes.push(n << 4);
739 } else {
740 bytes[i / 2] |= n;
741 }
742 }
743 Some(bytes)
744}
745
746fn nibble_from_hexdigit(c: char) -> Option<u8> {
748 match c {
749 '0'..='9' => Some(c as u8 - b'0'),
750 'a'..='f' => Some(c as u8 - b'a' + 0xA),
751 'A'..='F' => Some(c as u8 - b'A' + 0xA),
752 _ => None,
753 }
754}
755
756#[cfg(test)]
757mod tests {
758 use super::*;
759
760 #[test]
761 fn test_bytes_from_hexstring() {
762 assert_eq!(bytes_from_hexstring(""), Some(vec![]));
763 assert_eq!(bytes_from_hexstring("00"), Some(vec![0]));
764 assert_eq!(bytes_from_hexstring("FF"), Some(vec![0xFF]));
765 assert_eq!(bytes_from_hexstring("0000"), Some(vec![0, 0]));
766 assert_eq!(bytes_from_hexstring("FFFF"), Some(vec![0xFF, 0xFF]));
767
768 assert_eq!(bytes_from_hexstring(" "), None);
769 assert_eq!(bytes_from_hexstring("!"), None);
770 assert_eq!(bytes_from_hexstring("0"), None);
771 assert_eq!(bytes_from_hexstring(" 0"), None);
772 assert_eq!(bytes_from_hexstring("0 "), None);
773 assert_eq!(bytes_from_hexstring("0!"), None);
774 assert_eq!(bytes_from_hexstring(" "), None);
775 assert_eq!(bytes_from_hexstring("00 "), None);
776 assert_eq!(bytes_from_hexstring(" 00"), None);
777 assert_eq!(bytes_from_hexstring("000"), None);
778 assert_eq!(bytes_from_hexstring("Œ"), None);
779 assert_eq!(bytes_from_hexstring("ŒŒ"), None);
780 assert_eq!(bytes_from_hexstring("ŒŒŒ"), None);
781 assert_eq!(bytes_from_hexstring("ABCDEFG"), None);
782 assert_eq!(bytes_from_hexstring(" ABCDEF"), None);
783 assert_eq!(bytes_from_hexstring("\u{0000}"), None);
784 assert_eq!(bytes_from_hexstring("\u{FFFF}"), None);
785 assert_eq!(bytes_from_hexstring("\u{0123}"), None);
786 assert_eq!(bytes_from_hexstring("\u{30}"), None);
787 assert_eq!(bytes_from_hexstring("\\u0030"), None);
788 assert_eq!(bytes_from_hexstring("\\u202E\\u0030\\u0030"), None);
789 assert_eq!(bytes_from_hexstring("⣐⡄"), None);
790 assert_eq!(bytes_from_hexstring("😎"), None);
791 assert_eq!(bytes_from_hexstring("🙈🙉🙊"), None);
792 }
793
794 #[test]
795 fn test_nibble_from_hexdigit() {
796 for c in '\u{0}'..'\u{1024}' {
797 match c {
798 '0' => assert_eq!(Some(0x00), nibble_from_hexdigit(c)),
799 '1' => assert_eq!(Some(0x01), nibble_from_hexdigit(c)),
800 '2' => assert_eq!(Some(0x02), nibble_from_hexdigit(c)),
801 '3' => assert_eq!(Some(0x03), nibble_from_hexdigit(c)),
802 '4' => assert_eq!(Some(0x04), nibble_from_hexdigit(c)),
803 '5' => assert_eq!(Some(0x05), nibble_from_hexdigit(c)),
804 '6' => assert_eq!(Some(0x06), nibble_from_hexdigit(c)),
805 '7' => assert_eq!(Some(0x07), nibble_from_hexdigit(c)),
806 '8' => assert_eq!(Some(0x08), nibble_from_hexdigit(c)),
807 '9' => assert_eq!(Some(0x09), nibble_from_hexdigit(c)),
808 'A' => assert_eq!(Some(0x0A), nibble_from_hexdigit(c)),
809 'B' => assert_eq!(Some(0x0B), nibble_from_hexdigit(c)),
810 'C' => assert_eq!(Some(0x0C), nibble_from_hexdigit(c)),
811 'D' => assert_eq!(Some(0x0D), nibble_from_hexdigit(c)),
812 'E' => assert_eq!(Some(0x0E), nibble_from_hexdigit(c)),
813 'F' => assert_eq!(Some(0x0F), nibble_from_hexdigit(c)),
814 'a' => assert_eq!(Some(0x0A), nibble_from_hexdigit(c)),
815 'b' => assert_eq!(Some(0x0B), nibble_from_hexdigit(c)),
816 'c' => assert_eq!(Some(0x0C), nibble_from_hexdigit(c)),
817 'd' => assert_eq!(Some(0x0D), nibble_from_hexdigit(c)),
818 'e' => assert_eq!(Some(0x0E), nibble_from_hexdigit(c)),
819 'f' => assert_eq!(Some(0x0F), nibble_from_hexdigit(c)),
820 _ => assert_eq!(None, nibble_from_hexdigit(c)),
821 }
822 }
823 }
824}