1use alloy_primitives::{U64, U256};
4use serde::{Deserialize, Deserializer, de};
5use std::str::FromStr;
6
7#[derive(Copy, Clone, Deserialize)]
9#[serde(untagged)]
10pub enum Numeric {
11 U256(U256),
13 Num(u64),
15}
16
17impl From<Numeric> for U256 {
18 fn from(n: Numeric) -> Self {
19 match n {
20 Numeric::U256(n) => n,
21 Numeric::Num(n) => Self::from(n),
22 }
23 }
24}
25
26impl FromStr for Numeric {
27 type Err = String;
28
29 fn from_str(s: &str) -> Result<Self, Self::Err> {
30 if let Ok(val) = s.parse::<u128>() {
31 Ok(Self::U256(U256::from(val)))
32 } else if s.starts_with("0x") {
33 U256::from_str_radix(s, 16).map(Numeric::U256).map_err(|err| err.to_string())
34 } else {
35 U256::from_str(s).map(Numeric::U256).map_err(|err| err.to_string())
36 }
37 }
38}
39
40#[derive(Copy, Clone, Deserialize)]
42#[serde(untagged)]
43pub enum Numeric64 {
44 Num(u64),
46 U64(U64),
48}
49
50impl From<Numeric64> for u64 {
51 fn from(n: Numeric64) -> Self {
52 match n {
53 Numeric64::Num(n) => n,
54 Numeric64::U64(n) => n.to::<Self>(),
55 }
56 }
57}
58
59#[derive(Debug, Deserialize)]
61#[serde(untagged)]
62pub enum NumberOrHexU256 {
63 Int(serde_json::Number),
65 Hex(U256),
67}
68
69impl NumberOrHexU256 {
70 pub fn try_into_u256<E: de::Error>(self) -> Result<U256, E> {
72 match self {
73 Self::Int(num) => U256::from_str(&num.to_string()).map_err(E::custom),
74 Self::Hex(val) => Ok(val),
75 }
76 }
77}
78
79pub fn from_int_or_hex<'de, D>(deserializer: D) -> Result<U256, D::Error>
82where
83 D: Deserializer<'de>,
84{
85 NumberOrHexU256::deserialize(deserializer)?.try_into_u256()
86}
87
88#[derive(Deserialize)]
90#[serde(untagged)]
91pub enum NumericSeq {
92 Seq([Numeric; 1]),
94 U256(U256),
96 Num(u64),
98}
99
100#[derive(Deserialize)]
102#[serde(untagged)]
103pub enum Numeric64ValueOrSeq {
104 Seq([Numeric64; 1]),
106 Value(Numeric64),
108}
109
110pub fn deserialize_number<'de, D>(deserializer: D) -> Result<U256, D::Error>
112where
113 D: Deserializer<'de>,
114{
115 Numeric::deserialize(deserializer).map(Into::into)
116}
117
118pub fn deserialize_number_opt<'de, D>(deserializer: D) -> Result<Option<U256>, D::Error>
120where
121 D: Deserializer<'de>,
122{
123 let num = match Option::<Numeric>::deserialize(deserializer)? {
124 Some(Numeric::U256(n)) => Some(n),
125 Some(Numeric::Num(n)) => Some(U256::from(n)),
126 _ => None,
127 };
128
129 Ok(num)
130}
131
132pub fn deserialize_number_seq<'de, D>(deserializer: D) -> Result<U256, D::Error>
134where
135 D: Deserializer<'de>,
136{
137 let num = match NumericSeq::deserialize(deserializer)? {
138 NumericSeq::Seq(seq) => seq[0].into(),
139 NumericSeq::U256(n) => n,
140 NumericSeq::Num(n) => U256::from(n),
141 };
142
143 Ok(num)
144}
145
146pub fn deserialize_u64_seq<'de, D>(deserializer: D) -> Result<u64, D::Error>
148where
149 D: Deserializer<'de>,
150{
151 let num = match Numeric64ValueOrSeq::deserialize(deserializer)? {
152 Numeric64ValueOrSeq::Seq(seq) => seq[0].into(),
153 Numeric64ValueOrSeq::Value(num) => num.into(),
154 };
155
156 Ok(num)
157}
158
159pub fn deserialize_u64_seq_opt<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
162where
163 D: Deserializer<'de>,
164{
165 let seq = Vec::<Option<Numeric64>>::deserialize(deserializer)?;
166 if seq.len() > 1 {
167 return Err(de::Error::custom(format!(
168 "expected params sequence with length 0 or 1 but got {}",
169 seq.len()
170 )));
171 }
172 Ok(seq.into_iter().next().flatten().map(Into::into))
173}
174
175pub mod duration {
176 use serde::{Deserialize, Deserializer};
177 use std::time::Duration;
178
179 pub fn serialize<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>
180 where
181 S: serde::Serializer,
182 {
183 let d = jiff::SignedDuration::try_from(*duration).map_err(serde::ser::Error::custom)?;
184 serializer.serialize_str(&format!("{d:#}"))
185 }
186
187 pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
188 where
189 D: Deserializer<'de>,
190 {
191 let s = String::deserialize(deserializer)?;
192 let d = s.parse::<jiff::SignedDuration>().map_err(serde::de::Error::custom)?;
193 d.try_into().map_err(serde::de::Error::custom)
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200 use serde::de::IntoDeserializer;
201 use serde_json::json;
202
203 fn parse_u64_param(value: serde_json::Value) -> Result<u64, serde_json::Error> {
204 deserialize_u64_seq(value.into_deserializer())
205 }
206
207 fn parse_optional_u64_param(
208 value: serde_json::Value,
209 ) -> Result<Option<u64>, serde_json::Error> {
210 deserialize_u64_seq_opt(value.into_deserializer())
211 }
212
213 #[test]
214 fn deserialize_u64_seq_accepts_single_param_sequence_and_direct_value() {
215 let valid_values = [
216 json!([100]),
217 json!(100),
218 json!(["0x64"]),
219 json!("0x64"),
220 json!(["100"]),
221 json!("100"),
222 ];
223 for value in valid_values {
224 assert_eq!(parse_u64_param(value).unwrap(), 100);
225 }
226
227 for value in [json!([u64::MAX]), json!(u64::MAX)] {
228 assert_eq!(parse_u64_param(value).unwrap(), u64::MAX);
229 }
230 }
231
232 #[test]
233 fn deserialize_u64_seq_rejects_invalid_shape_and_overflow() {
234 for value in [
235 json!([]),
236 json!([1, 2]),
237 json!([null]),
238 json!(null),
239 json!(["0x10000000000000000"]),
240 json!("0x10000000000000000"),
241 json!(["18446744073709551616"]),
242 json!("18446744073709551616"),
243 ] {
244 assert!(parse_u64_param(value).is_err());
245 }
246 }
247
248 #[test]
249 fn deserialize_u64_seq_opt_accepts_empty_null_and_single_param_sequence() {
250 for value in [json!([]), json!([null])] {
251 assert_eq!(parse_optional_u64_param(value).unwrap(), None);
252 }
253
254 for value in [json!([100]), json!(["0x64"]), json!(["100"])] {
255 assert_eq!(parse_optional_u64_param(value).unwrap(), Some(100));
256 }
257
258 assert_eq!(parse_optional_u64_param(json!([u64::MAX])).unwrap(), Some(u64::MAX));
259 }
260
261 #[test]
262 fn deserialize_u64_seq_opt_rejects_invalid_shape_and_overflow() {
263 for value in [
264 json!([1, 2]),
265 json!(100),
266 json!("0x64"),
267 json!([["0x64"]]),
268 json!(["0x10000000000000000"]),
269 json!(["18446744073709551616"]),
270 ] {
271 assert!(parse_optional_u64_param(value).is_err());
272 }
273 }
274}