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 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
80pub 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
89pub 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
98macro_rules! faster_hex_serde_macros {
100 ($mod_name:ident, $with_pfx:expr, $check_case:expr) => {
101 pub mod $mod_name {
104 use crate::decode::CheckCase;
105 use crate::serde::internal;
106 use core::iter::FromIterator;
107
108 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 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
129faster_hex_serde_macros!(withpfx_ignorecase, true, CheckCase::None);
132faster_hex_serde_macros!(nopfx_ignorecase, false, CheckCase::None);
135faster_hex_serde_macros!(withpfx_lowercase, true, CheckCase::Lower);
138faster_hex_serde_macros!(nopfx_lowercase, false, CheckCase::Lower);
141
142faster_hex_serde_macros!(withpfx_uppercase, true, CheckCase::Upper);
145faster_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 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 assert!(result.starts_with(r#"{"bar":"0x"#));
186
187 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_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 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}