Skip to main content

faster_hex_thiserror/
serde.rs

1#![warn(missing_docs)]
2
3use core::iter::FromIterator;
4
5mod internal {
6    use crate::{
7        decode::{hex_decode_with_case, CheckCase},
8        encode::hex_encode_custom,
9    };
10    #[cfg(feature = "alloc")]
11    use alloc::{borrow::Cow, format, string::ToString, vec};
12    use core::iter::FromIterator;
13    use serde::{
14        de::{Error, IntoDeserializer},
15        Deserializer, Serializer,
16    };
17
18    pub(crate) fn serialize<S, T>(
19        data: T,
20        serializer: S,
21        with_prefix: bool,
22        case: CheckCase,
23    ) -> Result<S::Ok, S::Error>
24    where
25        S: Serializer,
26        T: AsRef<[u8]>,
27    {
28        let src: &[u8] = data.as_ref();
29
30        let mut dst_length = data.as_ref().len() << 1;
31        if with_prefix {
32            dst_length += 2;
33        }
34
35        let mut dst = vec![0u8; dst_length];
36        let mut dst_start = 0;
37        if with_prefix {
38            dst[0] = b'0';
39            dst[1] = b'x';
40
41            dst_start = 2;
42        }
43
44        hex_encode_custom(src, &mut dst[dst_start..], matches!(case, CheckCase::Upper))
45            .map_err(serde::ser::Error::custom)?;
46        serializer.serialize_str(unsafe { ::core::str::from_utf8_unchecked(&dst) })
47    }
48
49    pub(crate) fn deserialize<'de, D, T>(
50        deserializer: D,
51        with_prefix: bool,
52        check_case: CheckCase,
53    ) -> Result<T, D::Error>
54    where
55        D: Deserializer<'de>,
56        T: FromIterator<u8>,
57    {
58        let raw_src: Cow<str> = serde::Deserialize::deserialize(deserializer)?;
59        if with_prefix && !raw_src.starts_with("0x") {
60            return Err(D::Error::custom("invalid prefix".to_string()));
61        }
62
63        let src: &[u8] = {
64            if with_prefix {
65                raw_src[2..].as_bytes()
66            } else {
67                raw_src.as_bytes()
68            }
69        };
70
71        if src.len() & 1 != 0 {
72            return Err(D::Error::custom("invalid length".to_string()));
73        }
74
75        // we have already checked src's length, so src's length is a even integer
76        let mut dst = vec![0; src.len() >> 1];
77        hex_decode_with_case(src, &mut dst, check_case)
78            .map_err(|e| Error::custom(format!("{:?}", e)))?;
79        Ok(dst.into_iter().collect())
80    }
81
82    pub(crate) fn serialize_option<S, T>(
83        option_data: &Option<T>,
84        serializer: S,
85        with_prefix: bool,
86        case: CheckCase,
87    ) -> Result<S::Ok, S::Error>
88    where
89        S: Serializer,
90        T: AsRef<[u8]>,
91    {
92        match option_data {
93            Some(data) => serialize(data, serializer, with_prefix, case),
94            None => serializer.serialize_none(),
95        }
96    }
97
98    pub(crate) fn deserialize_option<'de, D, T>(
99        deserializer: D,
100        with_prefix: bool,
101        check_case: CheckCase,
102    ) -> Result<Option<T>, D::Error>
103    where
104        D: Deserializer<'de>,
105        T: FromIterator<u8>,
106    {
107        let option_str: Option<Cow<str>> = serde::Deserialize::deserialize(deserializer)?;
108        match option_str {
109            Some(raw_src) => {
110                let des: Vec<u8> =
111                    deserialize(raw_src.into_deserializer(), with_prefix, check_case)?;
112                Ok(Some(des.into_iter().collect()))
113            }
114            None => Ok(None),
115        }
116    }
117}
118
119/// Serde: Serialize with 0x-prefix and ignore case
120pub fn serialize<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
121where
122    S: serde::Serializer,
123    T: AsRef<[u8]>,
124{
125    withpfx_ignorecase::serialize(data, serializer)
126}
127
128/// Serde: Deserialize with 0x-prefix and ignore case
129pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
130where
131    D: serde::Deserializer<'de>,
132    T: FromIterator<u8>,
133{
134    withpfx_ignorecase::deserialize(deserializer)
135}
136
137/// Generate module with serde methods
138macro_rules! faster_hex_serde_macros {
139    ($mod_name:ident, $with_pfx:expr, $check_case:expr) => {
140        /// Serialize and deserialize with or without 0x-prefix,
141        /// and lowercase or uppercase or ignorecase
142        pub mod $mod_name {
143            use crate::decode::CheckCase;
144            use crate::serde::internal;
145            use core::iter::FromIterator;
146
147            /// Serializes `data` as hex string
148            pub fn serialize<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
149            where
150                S: serde::Serializer,
151                T: AsRef<[u8]>,
152            {
153                internal::serialize(data, serializer, $with_pfx, $check_case)
154            }
155
156            /// Deserializes a hex string into raw bytes.
157            pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
158            where
159                D: serde::Deserializer<'de>,
160                T: FromIterator<u8>,
161            {
162                internal::deserialize(deserializer, $with_pfx, $check_case)
163            }
164        }
165    };
166}
167
168// /// Serialize with 0x-prefix and lowercase
169// /// When deserialize, expect 0x-prefix and don't care case
170faster_hex_serde_macros!(withpfx_ignorecase, true, CheckCase::None);
171// /// Serialize without 0x-prefix and lowercase
172// /// When deserialize, expect without 0x-prefix and don't care case
173faster_hex_serde_macros!(nopfx_ignorecase, false, CheckCase::None);
174// /// Serialize with 0x-prefix and lowercase
175// /// When deserialize, expect with 0x-prefix and lower case
176faster_hex_serde_macros!(withpfx_lowercase, true, CheckCase::Lower);
177// /// Serialize without 0x-prefix and lowercase
178// /// When deserialize, expect without 0x-prefix and lower case
179faster_hex_serde_macros!(nopfx_lowercase, false, CheckCase::Lower);
180
181// /// Serialize with 0x-prefix and upper case
182// /// When deserialize, expect with 0x-prefix and upper case
183faster_hex_serde_macros!(withpfx_uppercase, true, CheckCase::Upper);
184// /// Serialize without 0x-prefix and upper case
185// /// When deserialize, expect without 0x-prefix and upper case
186faster_hex_serde_macros!(nopfx_uppercase, false, CheckCase::Upper);
187
188/// Generate module with serde option methods
189macro_rules! faster_hex_serde_option_macros {
190    ($mod_name:ident, $with_pfx:expr, $check_case:expr) => {
191        /// Serialize and deserialize with or without 0x-prefix,
192        /// and lowercase or uppercase or ignorecase for Option<Vec<u8>>
193        pub mod $mod_name {
194            use crate::decode::CheckCase;
195            use crate::serde::internal;
196            use core::iter::FromIterator;
197
198            /// Serializes `Option<data>` as hex string or null
199            pub fn serialize<S, T>(data: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
200            where
201                S: serde::Serializer,
202                T: AsRef<[u8]>,
203            {
204                internal::serialize_option(data, serializer, $with_pfx, $check_case)
205            }
206
207            /// Deserializes a hex string or null into `Option<Vec<u8>>`.
208            pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
209            where
210                D: serde::Deserializer<'de>,
211                T: FromIterator<u8>,
212            {
213                internal::deserialize_option(deserializer, $with_pfx, $check_case)
214            }
215        }
216    };
217}
218
219// /// Serialize Option with 0x-prefix and ignorecase
220faster_hex_serde_option_macros!(option_withpfx_ignorecase, true, CheckCase::None);
221// /// Serialize Option without 0x-prefix and ignorecase
222faster_hex_serde_option_macros!(option_nopfx_ignorecase, false, CheckCase::None);
223// /// Serialize Option with 0x-prefix and lowercase
224faster_hex_serde_option_macros!(option_withpfx_lowercase, true, CheckCase::Lower);
225// /// Serialize Option without 0x-prefix and lowercase
226faster_hex_serde_option_macros!(option_nopfx_lowercase, false, CheckCase::Lower);
227// /// Serialize Option with 0x-prefix and uppercase
228faster_hex_serde_option_macros!(option_withpfx_uppercase, true, CheckCase::Upper);
229// /// Serialize Option without 0x-prefix and uppercase
230faster_hex_serde_option_macros!(option_nopfx_uppercase, false, CheckCase::Upper);
231
232#[cfg(test)]
233mod tests {
234    use super::{
235        nopfx_ignorecase, nopfx_lowercase, nopfx_uppercase, option_nopfx_ignorecase,
236        option_nopfx_lowercase, option_nopfx_uppercase, option_withpfx_ignorecase,
237        option_withpfx_lowercase, option_withpfx_uppercase, withpfx_ignorecase, withpfx_lowercase,
238        withpfx_uppercase,
239    };
240    use crate as faster_hex;
241    use bytes::Bytes;
242    use proptest::proptest;
243    use serde::{Deserialize, Serialize};
244
245    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
246    struct Simple {
247        #[serde(with = "faster_hex")]
248        bar: Vec<u8>,
249    }
250
251    #[test]
252    fn test_deserialize_escaped() {
253        // 0x03 but escaped.
254        let x: Simple = serde_json::from_str(
255            r#"{
256            "bar": "\u0030x\u00303"
257        }"#,
258        )
259        .unwrap();
260        assert_eq!(x.bar, b"\x03");
261    }
262
263    fn _test_simple(src: &str) {
264        let simple = Simple { bar: src.into() };
265        let result = serde_json::to_string(&simple);
266        assert!(result.is_ok());
267        let result = result.unwrap();
268
269        // #[serde(with = "faster_hex")] should result with 0x prefix
270        assert!(result.starts_with(r#"{"bar":"0x"#));
271
272        // #[serde(with = "faster_hex")] shouldn't contains uppercase
273        assert!(result[7..].chars().all(|c| !c.is_uppercase()));
274
275        let decode_simple = serde_json::from_str::<Simple>(&result);
276        assert!(decode_simple.is_ok());
277        assert_eq!(decode_simple.unwrap(), simple);
278    }
279
280    proptest! {
281        #[test]
282        fn test_simple(ref s in ".*") {
283            _test_simple(s);
284        }
285    }
286
287    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
288    struct Foo {
289        #[serde(with = "nopfx_lowercase")]
290        bar_nopfx_lowercase_vec: Vec<u8>,
291        #[serde(with = "nopfx_lowercase")]
292        bar_nopfx_lowercase_bytes: Bytes,
293
294        #[serde(with = "withpfx_lowercase")]
295        bar_withpfx_lowercase_vec: Vec<u8>,
296        #[serde(with = "withpfx_lowercase")]
297        bar_withpfx_lowercase_bytes: Bytes,
298
299        #[serde(with = "nopfx_uppercase")]
300        bar_nopfx_uppercase_vec: Vec<u8>,
301        #[serde(with = "nopfx_uppercase")]
302        bar_nopfx_uppercase_bytes: Bytes,
303
304        #[serde(with = "withpfx_uppercase")]
305        bar_withpfx_uppercase_vec: Vec<u8>,
306        #[serde(with = "withpfx_uppercase")]
307        bar_withpfx_uppercase_bytes: Bytes,
308
309        #[serde(with = "withpfx_ignorecase")]
310        bar_withpfx_ignorecase_vec: Vec<u8>,
311        #[serde(with = "withpfx_ignorecase")]
312        bar_withpfx_ignorecase_bytes: Bytes,
313
314        #[serde(with = "nopfx_ignorecase")]
315        bar_nopfx_ignorecase_vec: Vec<u8>,
316        #[serde(with = "nopfx_ignorecase")]
317        bar_nopfx_ignorecase_bytes: Bytes,
318
319        #[serde(with = "option_nopfx_ignorecase")]
320        bar_nopfx_ignorecase_vec_option: Option<Vec<u8>>,
321        #[serde(with = "option_nopfx_ignorecase")]
322        bar_nopfx_ignorecase_bytes_option: Option<Bytes>,
323
324        #[serde(with = "option_withpfx_ignorecase")]
325        bar_withpfx_ignorecase_vec_option: Option<Vec<u8>>,
326        #[serde(with = "option_withpfx_ignorecase")]
327        bar_withpfx_ignorecase_bytes_option: Option<Bytes>,
328
329        #[serde(with = "option_nopfx_lowercase")]
330        bar_nopfx_lowercase_vec_option: Option<Vec<u8>>,
331        #[serde(with = "option_nopfx_lowercase")]
332        bar_nopfx_lowercase_bytes_option: Option<Bytes>,
333
334        #[serde(with = "option_withpfx_lowercase")]
335        bar_withpfx_lowercase_vec_option: Option<Vec<u8>>,
336        #[serde(with = "option_withpfx_lowercase")]
337        bar_withpfx_lowercase_bytes_option: Option<Bytes>,
338
339        #[serde(with = "option_nopfx_uppercase")]
340        bar_nopfx_uppercase_vec_option: Option<Vec<u8>>,
341        #[serde(with = "option_nopfx_uppercase")]
342        bar_nopfx_uppercase_bytes_option: Option<Bytes>,
343
344        #[serde(with = "option_withpfx_uppercase")]
345        bar_withpfx_uppercase_vec_option: Option<Vec<u8>>,
346        #[serde(with = "option_withpfx_uppercase")]
347        bar_withpfx_uppercase_bytes_option: Option<Bytes>,
348    }
349
350    #[test]
351    fn test_serde_default() {
352        {
353            let foo_defuault = Foo {
354                bar_nopfx_lowercase_vec: vec![],
355                bar_nopfx_lowercase_bytes: Default::default(),
356                bar_withpfx_lowercase_vec: vec![],
357                bar_withpfx_lowercase_bytes: Default::default(),
358                bar_nopfx_uppercase_vec: vec![],
359                bar_nopfx_uppercase_bytes: Default::default(),
360                bar_withpfx_uppercase_vec: vec![],
361                bar_withpfx_uppercase_bytes: Default::default(),
362                bar_withpfx_ignorecase_vec: vec![],
363                bar_withpfx_ignorecase_bytes: Default::default(),
364                bar_nopfx_ignorecase_vec: vec![],
365                bar_nopfx_ignorecase_bytes: Default::default(),
366                bar_nopfx_ignorecase_vec_option: Default::default(),
367                bar_nopfx_ignorecase_bytes_option: Default::default(),
368                bar_withpfx_ignorecase_vec_option: Default::default(),
369                bar_withpfx_ignorecase_bytes_option: Default::default(),
370                bar_nopfx_lowercase_vec_option: Default::default(),
371                bar_nopfx_lowercase_bytes_option: Default::default(),
372                bar_withpfx_lowercase_vec_option: Default::default(),
373                bar_withpfx_lowercase_bytes_option: Default::default(),
374                bar_nopfx_uppercase_vec_option: Default::default(),
375                bar_nopfx_uppercase_bytes_option: Default::default(),
376                bar_withpfx_uppercase_vec_option: Default::default(),
377                bar_withpfx_uppercase_bytes_option: Default::default(),
378            };
379            let serde_result = serde_json::to_string(&foo_defuault).unwrap();
380            let expect = r#"
381{"bar_nopfx_lowercase_vec":"",
382"bar_nopfx_lowercase_bytes":"",
383"bar_withpfx_lowercase_vec":"0x",
384"bar_withpfx_lowercase_bytes":"0x",
385"bar_nopfx_uppercase_vec":"",
386"bar_nopfx_uppercase_bytes":"",
387"bar_withpfx_uppercase_vec":"0x",
388"bar_withpfx_uppercase_bytes":"0x",
389"bar_withpfx_ignorecase_vec":"0x",
390"bar_withpfx_ignorecase_bytes":"0x",
391"bar_nopfx_ignorecase_vec":"",
392"bar_nopfx_ignorecase_bytes":"",
393"bar_nopfx_ignorecase_vec_option":null,
394"bar_nopfx_ignorecase_bytes_option":null,
395"bar_withpfx_ignorecase_vec_option":null,
396"bar_withpfx_ignorecase_bytes_option":null,
397"bar_nopfx_lowercase_vec_option":null,
398"bar_nopfx_lowercase_bytes_option":null,
399"bar_withpfx_lowercase_vec_option":null,
400"bar_withpfx_lowercase_bytes_option":null,
401"bar_nopfx_uppercase_vec_option":null,
402"bar_nopfx_uppercase_bytes_option":null,
403"bar_withpfx_uppercase_vec_option":null,
404"bar_withpfx_uppercase_bytes_option":null}"#;
405
406            let expect = expect.replace('\n', "");
407            assert_eq!(serde_result, expect);
408
409            let foo_src: Foo = serde_json::from_str(&serde_result).unwrap();
410            assert_eq!(foo_defuault, foo_src);
411        }
412    }
413
414    fn _test_serde(src: &str) {
415        let foo = Foo {
416            bar_nopfx_lowercase_vec: Vec::from(src),
417            bar_nopfx_lowercase_bytes: Bytes::from(Vec::from(src)),
418            bar_withpfx_lowercase_vec: Vec::from(src),
419            bar_withpfx_lowercase_bytes: Bytes::from(Vec::from(src)),
420            bar_nopfx_uppercase_vec: Vec::from(src),
421            bar_nopfx_uppercase_bytes: Bytes::from(Vec::from(src)),
422            bar_withpfx_uppercase_vec: Vec::from(src),
423            bar_withpfx_uppercase_bytes: Bytes::from(Vec::from(src)),
424
425            bar_withpfx_ignorecase_vec: Vec::from(src),
426            bar_withpfx_ignorecase_bytes: Bytes::from(Vec::from(src)),
427            bar_nopfx_ignorecase_vec: Vec::from(src),
428            bar_nopfx_ignorecase_bytes: Bytes::from(Vec::from(src)),
429            bar_withpfx_ignorecase_vec_option: Some(Vec::from(src)),
430            bar_nopfx_ignorecase_bytes_option: Some(Bytes::from(Vec::from(src))),
431            bar_nopfx_ignorecase_vec_option: Some(Vec::from(src)),
432            bar_withpfx_ignorecase_bytes_option: Some(Bytes::from(Vec::from(src))),
433            bar_nopfx_lowercase_vec_option: Some(Vec::from(src)),
434            bar_nopfx_lowercase_bytes_option: Some(Bytes::from(Vec::from(src))),
435            bar_withpfx_lowercase_vec_option: Some(Vec::from(src)),
436            bar_withpfx_lowercase_bytes_option: Some(Bytes::from(Vec::from(src))),
437            bar_nopfx_uppercase_vec_option: Some(Vec::from(src)),
438            bar_nopfx_uppercase_bytes_option: Some(Bytes::from(Vec::from(src))),
439            bar_withpfx_uppercase_vec_option: Some(Vec::from(src)),
440            bar_withpfx_uppercase_bytes_option: Some(Bytes::from(Vec::from(src))),
441        };
442        let hex_str = hex::encode(src);
443        let hex_str_upper = hex::encode_upper(src);
444        let serde_result = serde_json::to_string(&foo).unwrap();
445
446        let expect = format!(
447            r#"{{"bar_nopfx_lowercase_vec":"{}",
448"bar_nopfx_lowercase_bytes":"{}",
449"bar_withpfx_lowercase_vec":"0x{}",
450"bar_withpfx_lowercase_bytes":"0x{}",
451"bar_nopfx_uppercase_vec":"{}",
452"bar_nopfx_uppercase_bytes":"{}",
453"bar_withpfx_uppercase_vec":"0x{}",
454"bar_withpfx_uppercase_bytes":"0x{}",
455"bar_withpfx_ignorecase_vec":"0x{}",
456"bar_withpfx_ignorecase_bytes":"0x{}",
457"bar_nopfx_ignorecase_vec":"{}",
458"bar_nopfx_ignorecase_bytes":"{}",
459"bar_nopfx_ignorecase_vec_option":"{}",
460"bar_nopfx_ignorecase_bytes_option":"{}",
461"bar_withpfx_ignorecase_vec_option":"0x{}",
462"bar_withpfx_ignorecase_bytes_option":"0x{}",
463"bar_nopfx_lowercase_vec_option":"{}",
464"bar_nopfx_lowercase_bytes_option":"{}",
465"bar_withpfx_lowercase_vec_option":"0x{}",
466"bar_withpfx_lowercase_bytes_option":"0x{}",
467"bar_nopfx_uppercase_vec_option":"{}",
468"bar_nopfx_uppercase_bytes_option":"{}",
469"bar_withpfx_uppercase_vec_option":"0x{}",
470"bar_withpfx_uppercase_bytes_option":"0x{}"}}"#,
471            hex_str,
472            hex_str,
473            hex_str,
474            hex_str,
475            hex_str_upper,
476            hex_str_upper,
477            hex_str_upper,
478            hex_str_upper,
479            hex_str,
480            hex_str,
481            hex_str,
482            hex_str,
483            hex_str,
484            hex_str,
485            hex_str,
486            hex_str,
487            hex_str,
488            hex_str,
489            hex_str,
490            hex_str,
491            hex_str_upper,
492            hex_str_upper,
493            hex_str_upper,
494            hex_str_upper,
495        );
496        let expect = expect.replace('\n', "");
497        assert_eq!(serde_result, expect);
498
499        let foo_src: Foo = serde_json::from_str(&serde_result).unwrap();
500        assert_eq!(foo, foo_src);
501    }
502
503    proptest! {
504        #[test]
505        fn test_serde(ref s in ".*") {
506            _test_serde(s);
507        }
508    }
509
510    fn _test_serde_deserialize(src: &str) {
511        #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
512        struct FooNoPfxLower {
513            #[serde(with = "nopfx_lowercase")]
514            bar: Vec<u8>,
515        }
516
517        #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
518        struct FooWithPfxLower {
519            #[serde(with = "withpfx_lowercase")]
520            bar: Vec<u8>,
521        }
522
523        #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
524        struct FooNoPfxUpper {
525            #[serde(with = "nopfx_uppercase")]
526            bar: Vec<u8>,
527        }
528        #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
529        struct FooWithPfxUpper {
530            #[serde(with = "withpfx_uppercase")]
531            bar: Vec<u8>,
532        }
533
534        #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
535        struct FooNoPfxIgnoreCase {
536            #[serde(with = "nopfx_ignorecase")]
537            bar: Vec<u8>,
538        }
539        #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
540        struct FooWithPfxIgnoreCase {
541            #[serde(with = "withpfx_ignorecase")]
542            bar: Vec<u8>,
543        }
544
545        {
546            let hex_foo = serde_json::to_string(&FooNoPfxLower { bar: src.into() }).unwrap();
547            let foo_pfx: serde_json::Result<FooWithPfxLower> = serde_json::from_str(&hex_foo);
548            // assert foo_pfx is Error, and contains "invalid prefix"
549            assert!(foo_pfx.is_err());
550            assert!(foo_pfx.unwrap_err().to_string().contains("invalid prefix"));
551        }
552
553        {
554            let foo_lower = serde_json::to_string(&FooNoPfxLower { bar: src.into() }).unwrap();
555            let foo_upper_result: serde_json::Result<FooNoPfxUpper> =
556                serde_json::from_str(&foo_lower);
557            if hex::encode(src).contains(char::is_lowercase) {
558                // FooNoPfxLower's foo field is lowercase, so we can't deserialize it to FooNoPfxUpper
559                assert!(foo_upper_result.is_err());
560                assert!(foo_upper_result
561                    .unwrap_err()
562                    .to_string()
563                    .contains("Invalid character"));
564            }
565        }
566    }
567
568    proptest! {
569        #[test]
570        fn test_serde_deserialize(ref s in ".*") {
571            _test_serde_deserialize(s);
572        }
573    }
574}