faster_hex/
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::{de::Error, Deserializer, Serializer};
14
15    pub(crate) fn serialize<S, T>(
16        data: T,
17        serializer: S,
18        with_prefix: bool,
19        case: CheckCase,
20    ) -> Result<S::Ok, S::Error>
21    where
22        S: Serializer,
23        T: AsRef<[u8]>,
24    {
25        let src: &[u8] = data.as_ref();
26
27        let mut dst_length = data.as_ref().len() << 1;
28        if with_prefix {
29            dst_length += 2;
30        }
31
32        let mut dst = vec![0u8; dst_length];
33        let mut dst_start = 0;
34        if with_prefix {
35            dst[0] = b'0';
36            dst[1] = b'x';
37
38            dst_start = 2;
39        }
40
41        hex_encode_custom(src, &mut dst[dst_start..], matches!(case, CheckCase::Upper))
42            .map_err(serde::ser::Error::custom)?;
43        serializer.serialize_str(unsafe { ::core::str::from_utf8_unchecked(&dst) })
44    }
45
46    pub(crate) fn deserialize<'de, D, T>(
47        deserializer: D,
48        with_prefix: bool,
49        check_case: CheckCase,
50    ) -> Result<T, D::Error>
51    where
52        D: Deserializer<'de>,
53        T: FromIterator<u8>,
54    {
55        let raw_src: Cow<str> = serde::Deserialize::deserialize(deserializer)?;
56        if with_prefix && !raw_src.starts_with("0x") {
57            return Err(D::Error::custom("invalid prefix".to_string()));
58        }
59
60        let src: &[u8] = {
61            if with_prefix {
62                raw_src[2..].as_bytes()
63            } else {
64                raw_src.as_bytes()
65            }
66        };
67
68        if src.len() & 1 != 0 {
69            return Err(D::Error::custom("invalid length".to_string()));
70        }
71
72        // we have already checked src's length, so src's length is a even integer
73        let mut dst = vec![0; src.len() >> 1];
74        hex_decode_with_case(src, &mut dst, check_case)
75            .map_err(|e| Error::custom(format!("{:?}", e)))?;
76        Ok(dst.into_iter().collect())
77    }
78}
79
80/// Serde: Serialize with 0x-prefix and ignore case
81pub fn serialize<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
82where
83    S: serde::Serializer,
84    T: AsRef<[u8]>,
85{
86    withpfx_ignorecase::serialize(data, serializer)
87}
88
89/// Serde: Deserialize with 0x-prefix and ignore case
90pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
91where
92    D: serde::Deserializer<'de>,
93    T: FromIterator<u8>,
94{
95    withpfx_ignorecase::deserialize(deserializer)
96}
97
98/// Generate module with serde methods
99macro_rules! faster_hex_serde_macros {
100    ($mod_name:ident, $with_pfx:expr, $check_case:expr) => {
101        /// Serialize and deserialize with or without 0x-prefix,
102        /// and lowercase or uppercase or ignorecase
103        pub mod $mod_name {
104            use crate::decode::CheckCase;
105            use crate::serde::internal;
106            use core::iter::FromIterator;
107
108            /// Serializes `data` as hex string
109            pub fn serialize<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
110            where
111                S: serde::Serializer,
112                T: AsRef<[u8]>,
113            {
114                internal::serialize(data, serializer, $with_pfx, $check_case)
115            }
116
117            /// Deserializes a hex string into raw bytes.
118            pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
119            where
120                D: serde::Deserializer<'de>,
121                T: FromIterator<u8>,
122            {
123                internal::deserialize(deserializer, $with_pfx, $check_case)
124            }
125        }
126    };
127}
128
129// /// Serialize with 0x-prefix and lowercase
130// /// When deserialize, expect 0x-prefix and don't care case
131faster_hex_serde_macros!(withpfx_ignorecase, true, CheckCase::None);
132// /// Serialize without 0x-prefix and lowercase
133// /// When deserialize, expect without 0x-prefix and don't care case
134faster_hex_serde_macros!(nopfx_ignorecase, false, CheckCase::None);
135// /// Serialize with 0x-prefix and lowercase
136// /// When deserialize, expect with 0x-prefix and lower case
137faster_hex_serde_macros!(withpfx_lowercase, true, CheckCase::Lower);
138// /// Serialize without 0x-prefix and lowercase
139// /// When deserialize, expect without 0x-prefix and lower case
140faster_hex_serde_macros!(nopfx_lowercase, false, CheckCase::Lower);
141
142// /// Serialize with 0x-prefix and upper case
143// /// When deserialize, expect with 0x-prefix and upper case
144faster_hex_serde_macros!(withpfx_uppercase, true, CheckCase::Upper);
145// /// Serialize without 0x-prefix and upper case
146// /// When deserialize, expect without 0x-prefix and upper case
147faster_hex_serde_macros!(nopfx_uppercase, false, CheckCase::Upper);
148
149#[cfg(test)]
150mod tests {
151    use super::{
152        nopfx_ignorecase, nopfx_lowercase, nopfx_uppercase, withpfx_ignorecase, withpfx_lowercase,
153        withpfx_uppercase,
154    };
155    use crate as faster_hex;
156    use bytes::Bytes;
157    use proptest::proptest;
158    use serde::{Deserialize, Serialize};
159
160    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
161    struct Simple {
162        #[serde(with = "faster_hex")]
163        bar: Vec<u8>,
164    }
165
166    #[test]
167    fn test_deserialize_escaped() {
168        // 0x03 but escaped.
169        let x: Simple = serde_json::from_str(
170            r#"{
171            "bar": "\u0030x\u00303"
172        }"#,
173        )
174        .unwrap();
175        assert_eq!(x.bar, b"\x03");
176    }
177
178    fn _test_simple(src: &str) {
179        let simple = Simple { bar: src.into() };
180        let result = serde_json::to_string(&simple);
181        assert!(result.is_ok());
182        let result = result.unwrap();
183
184        // #[serde(with = "faster_hex")] should result with 0x prefix
185        assert!(result.starts_with(r#"{"bar":"0x"#));
186
187        // #[serde(with = "faster_hex")] shouldn't contains uppercase
188        assert!(result[7..].chars().all(|c| !c.is_uppercase()));
189
190        let decode_simple = serde_json::from_str::<Simple>(&result);
191        assert!(decode_simple.is_ok());
192        assert_eq!(decode_simple.unwrap(), simple);
193    }
194
195    proptest! {
196        #[test]
197        fn test_simple(ref s in ".*") {
198            _test_simple(s);
199        }
200    }
201
202    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
203    struct Foo {
204        #[serde(with = "nopfx_lowercase")]
205        bar_nopfx_lowercase_vec: Vec<u8>,
206        #[serde(with = "nopfx_lowercase")]
207        bar_nopfx_lowercase_bytes: Bytes,
208
209        #[serde(with = "withpfx_lowercase")]
210        bar_withpfx_lowercase_vec: Vec<u8>,
211        #[serde(with = "withpfx_lowercase")]
212        bar_withpfx_lowercase_bytes: Bytes,
213
214        #[serde(with = "nopfx_uppercase")]
215        bar_nopfx_uppercase_vec: Vec<u8>,
216        #[serde(with = "nopfx_uppercase")]
217        bar_nopfx_uppercase_bytes: Bytes,
218
219        #[serde(with = "withpfx_uppercase")]
220        bar_withpfx_uppercase_vec: Vec<u8>,
221        #[serde(with = "withpfx_uppercase")]
222        bar_withpfx_uppercase_bytes: Bytes,
223
224        #[serde(with = "withpfx_ignorecase")]
225        bar_withpfx_ignorecase_vec: Vec<u8>,
226        #[serde(with = "withpfx_ignorecase")]
227        bar_withpfx_ignorecase_bytes: Bytes,
228
229        #[serde(with = "nopfx_ignorecase")]
230        bar_nopfx_ignorecase_vec: Vec<u8>,
231        #[serde(with = "nopfx_ignorecase")]
232        bar_nopfx_ignorecase_bytes: Bytes,
233    }
234
235    #[test]
236    fn test_serde_default() {
237        {
238            let foo_defuault = Foo {
239                bar_nopfx_lowercase_vec: vec![],
240                bar_nopfx_lowercase_bytes: Default::default(),
241                bar_withpfx_lowercase_vec: vec![],
242                bar_withpfx_lowercase_bytes: Default::default(),
243                bar_nopfx_uppercase_vec: vec![],
244                bar_nopfx_uppercase_bytes: Default::default(),
245                bar_withpfx_uppercase_vec: vec![],
246                bar_withpfx_uppercase_bytes: Default::default(),
247                bar_withpfx_ignorecase_vec: vec![],
248                bar_withpfx_ignorecase_bytes: Default::default(),
249                bar_nopfx_ignorecase_vec: vec![],
250                bar_nopfx_ignorecase_bytes: Default::default(),
251            };
252            let serde_result = serde_json::to_string(&foo_defuault).unwrap();
253            let  expect = "{\"bar_nopfx_lowercase_vec\":\"\",\"bar_nopfx_lowercase_bytes\":\"\",\"bar_withpfx_lowercase_vec\":\"0x\",\"bar_withpfx_lowercase_bytes\":\"0x\",\"bar_nopfx_uppercase_vec\":\"\",\"bar_nopfx_uppercase_bytes\":\"\",\"bar_withpfx_uppercase_vec\":\"0x\",\"bar_withpfx_uppercase_bytes\":\"0x\",\"bar_withpfx_ignorecase_vec\":\"0x\",\"bar_withpfx_ignorecase_bytes\":\"0x\",\"bar_nopfx_ignorecase_vec\":\"\",\"bar_nopfx_ignorecase_bytes\":\"\"}";
254            assert_eq!(serde_result, expect);
255
256            let foo_src: Foo = serde_json::from_str(&serde_result).unwrap();
257            assert_eq!(foo_defuault, foo_src);
258        }
259    }
260
261    fn _test_serde(src: &str) {
262        let foo = Foo {
263            bar_nopfx_lowercase_vec: Vec::from(src),
264            bar_nopfx_lowercase_bytes: Bytes::from(Vec::from(src)),
265            bar_withpfx_lowercase_vec: Vec::from(src),
266            bar_withpfx_lowercase_bytes: Bytes::from(Vec::from(src)),
267            bar_nopfx_uppercase_vec: Vec::from(src),
268            bar_nopfx_uppercase_bytes: Bytes::from(Vec::from(src)),
269            bar_withpfx_uppercase_vec: Vec::from(src),
270            bar_withpfx_uppercase_bytes: Bytes::from(Vec::from(src)),
271
272            bar_withpfx_ignorecase_vec: Vec::from(src),
273            bar_withpfx_ignorecase_bytes: Bytes::from(Vec::from(src)),
274            bar_nopfx_ignorecase_vec: Vec::from(src),
275            bar_nopfx_ignorecase_bytes: Bytes::from(Vec::from(src)),
276        };
277        let hex_str = hex::encode(src);
278        let hex_str_upper = hex::encode_upper(src);
279        let serde_result = serde_json::to_string(&foo).unwrap();
280
281        let  expect = format!("{{\"bar_nopfx_lowercase_vec\":\"{}\",\"bar_nopfx_lowercase_bytes\":\"{}\",\"bar_withpfx_lowercase_vec\":\"0x{}\",\"bar_withpfx_lowercase_bytes\":\"0x{}\",\"bar_nopfx_uppercase_vec\":\"{}\",\"bar_nopfx_uppercase_bytes\":\"{}\",\"bar_withpfx_uppercase_vec\":\"0x{}\",\"bar_withpfx_uppercase_bytes\":\"0x{}\",\"bar_withpfx_ignorecase_vec\":\"0x{}\",\"bar_withpfx_ignorecase_bytes\":\"0x{}\",\"bar_nopfx_ignorecase_vec\":\"{}\",\"bar_nopfx_ignorecase_bytes\":\"{}\"}}",
282                              hex_str,
283                              hex_str,
284                              hex_str,
285                              hex_str,
286                              hex_str_upper,
287                              hex_str_upper,
288                              hex_str_upper,
289                              hex_str_upper,
290                              hex_str,
291                              hex_str,
292                              hex_str,
293                              hex_str,
294
295        );
296        assert_eq!(serde_result, expect);
297
298        let foo_src: Foo = serde_json::from_str(&serde_result).unwrap();
299        assert_eq!(foo, foo_src);
300    }
301
302    proptest! {
303        #[test]
304        fn test_serde(ref s in ".*") {
305            _test_serde(s);
306        }
307    }
308
309    fn _test_serde_deserialize(src: &str) {
310        #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
311        struct FooNoPfxLower {
312            #[serde(with = "nopfx_lowercase")]
313            bar: Vec<u8>,
314        }
315
316        #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
317        struct FooWithPfxLower {
318            #[serde(with = "withpfx_lowercase")]
319            bar: Vec<u8>,
320        }
321
322        #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
323        struct FooNoPfxUpper {
324            #[serde(with = "nopfx_uppercase")]
325            bar: Vec<u8>,
326        }
327        #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
328        struct FooWithPfxUpper {
329            #[serde(with = "withpfx_uppercase")]
330            bar: Vec<u8>,
331        }
332
333        #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
334        struct FooNoPfxIgnoreCase {
335            #[serde(with = "nopfx_ignorecase")]
336            bar: Vec<u8>,
337        }
338        #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
339        struct FooWithPfxIgnoreCase {
340            #[serde(with = "withpfx_ignorecase")]
341            bar: Vec<u8>,
342        }
343
344        {
345            let hex_foo = serde_json::to_string(&FooNoPfxLower { bar: src.into() }).unwrap();
346            let foo_pfx: serde_json::Result<FooWithPfxLower> = serde_json::from_str(&hex_foo);
347            // assert foo_pfx is Error, and contains "invalid prefix"
348            assert!(foo_pfx.is_err());
349            assert!(foo_pfx.unwrap_err().to_string().contains("invalid prefix"));
350        }
351
352        {
353            let foo_lower = serde_json::to_string(&FooNoPfxLower { bar: src.into() }).unwrap();
354            let foo_upper_result: serde_json::Result<FooNoPfxUpper> =
355                serde_json::from_str(&foo_lower);
356            if hex::encode(src).contains(char::is_lowercase) {
357                // FooNoPfxLower's foo field is lowercase, so we can't deserialize it to FooNoPfxUpper
358                assert!(foo_upper_result.is_err());
359                assert!(foo_upper_result
360                    .unwrap_err()
361                    .to_string()
362                    .contains("Invalid character"));
363            }
364        }
365    }
366
367    proptest! {
368        #[test]
369        fn test_serde_deserialize(ref s in ".*") {
370            _test_serde_deserialize(s);
371        }
372    }
373}