Skip to main content

rasn/jer/
de.rs

1//! Decoding JSON Encoding Rules data into Rust structures.
2
3use 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
26/// Decodes JSON Encoding Rules data into Rust structures.
27pub struct Decoder {
28    stack: alloc::vec::Vec<Value>,
29}
30
31impl Decoder {
32    /// Creates new default decoder from the given input.
33    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
492// -------------------------------------------------------------------
493//
494//                        HELPER METHODS
495//
496// -------------------------------------------------------------------
497
498impl 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        // For performance reasons, sometimes it is better to use lazy one
578        #[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
729/// Parses a hex string into bytes.
730fn 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
746/// Parses a hexdigit character into a nibble (four bits).
747fn 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}