1use std::{
2 fmt::Display,
3 str::FromStr,
4};
5
6use serde::{
7 Deserializer,
8 Serializer,
9};
10
11pub struct HexDisplayFromStr;
12
13impl<T> serde_with::SerializeAs<T> for HexDisplayFromStr
14where
15 T: Display,
16{
17 fn serialize_as<S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
18 where
19 S: Serializer,
20 {
21 let s = format!("0x{value}");
22 serializer.serialize_str(&s)
23 }
24}
25
26impl<'de, T> serde_with::DeserializeAs<'de, T> for HexDisplayFromStr
27where
28 T: FromStr,
29 T::Err: Display,
30{
31 fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
32 where
33 D: Deserializer<'de>,
34 {
35 use serde::Deserialize;
36 let s = String::deserialize(deserializer)?;
37 let trimmed = s.strip_prefix("0x").unwrap_or(&s);
38 T::from_str(trimmed).map_err(serde::de::Error::custom)
39 }
40}
41
42pub fn serialize_hex<S, A>(value: A, serializer: S) -> Result<S::Ok, S::Error>
43where
44 S: Serializer,
45 A: Display,
46{
47 serializer.serialize_str(&format!("0x{value}"))
48}
49
50pub struct HexVecFromStr;
51
52impl serde_with::SerializeAs<Vec<u8>> for HexVecFromStr {
53 fn serialize_as<S>(value: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error>
54 where
55 S: Serializer,
56 {
57 let hex_str = value.iter().map(|b| format!("{b:02x}")).collect::<String>();
58 let hex_str = format!("0x{hex_str}");
59 serializer.serialize_str(&hex_str)
60 }
61}
62
63impl<'de> serde_with::DeserializeAs<'de, Vec<u8>> for HexVecFromStr {
64 fn deserialize_as<D>(deserializer: D) -> Result<Vec<u8>, D::Error>
65 where
66 D: Deserializer<'de>,
67 {
68 use serde::{
69 Deserialize,
70 de,
71 };
72 use serde_json::Value;
73
74 let value = Value::deserialize(deserializer)?;
75
76 match value {
77 Value::String(hex_str) => {
78 let trimmed = hex_str.strip_prefix("0x").unwrap_or(&hex_str);
79
80 (0..trimmed.len())
81 .step_by(2)
82 .map(|i| u8::from_str_radix(&trimmed[i..i + 2], 16))
83 .collect::<Result<Vec<u8>, _>>()
84 .map_err(de::Error::custom)
85 }
86 Value::Array(arr) => arr
87 .into_iter()
88 .map(|v| match v {
89 Value::Number(n) => {
90 if let Some(u) = n.as_u64() {
91 if u <= 255 {
92 Ok(u as u8)
93 } else {
94 Err(de::Error::custom(format!(
95 "Number {u} is out of range for u8"
96 )))
97 }
98 } else {
99 Err(de::Error::custom("Invalid number in array"))
100 }
101 }
102 _ => Err(de::Error::custom("Array must contain only numbers")),
103 })
104 .collect::<Result<Vec<u8>, _>>(),
105 _ => Err(de::Error::custom("Expected hex string or array of numbers")),
106 }
107 }
108}