foundry_common/
serde_helpers.rs

1//! Misc Serde helpers for foundry crates.
2
3use alloy_primitives::U256;
4use serde::{Deserialize, Deserializer, de};
5use std::str::FromStr;
6
7/// Helper type to parse both `u64` and `U256`
8#[derive(Copy, Clone, Deserialize)]
9#[serde(untagged)]
10pub enum Numeric {
11    /// A [U256] value.
12    U256(U256),
13    /// A `u64` value.
14    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/// An enum that represents either a [serde_json::Number] integer, or a hex [U256].
41#[derive(Debug, Deserialize)]
42#[serde(untagged)]
43pub enum NumberOrHexU256 {
44    /// An integer
45    Int(serde_json::Number),
46    /// A hex U256
47    Hex(U256),
48}
49
50impl NumberOrHexU256 {
51    /// Tries to convert this into a [U256]].
52    pub fn try_into_u256<E: de::Error>(self) -> Result<U256, E> {
53        match self {
54            Self::Int(num) => U256::from_str(&num.to_string()).map_err(E::custom),
55            Self::Hex(val) => Ok(val),
56        }
57    }
58}
59
60/// Deserializes the input into a U256, accepting both 0x-prefixed hex and decimal strings with
61/// arbitrary precision, defined by serde_json's [`Number`](serde_json::Number).
62pub fn from_int_or_hex<'de, D>(deserializer: D) -> Result<U256, D::Error>
63where
64    D: Deserializer<'de>,
65{
66    NumberOrHexU256::deserialize(deserializer)?.try_into_u256()
67}
68
69/// Helper type to deserialize sequence of numbers
70#[derive(Deserialize)]
71#[serde(untagged)]
72pub enum NumericSeq {
73    /// Single parameter sequence (e.g `[1]`).
74    Seq([Numeric; 1]),
75    /// `U256`.
76    U256(U256),
77    /// Native `u64`.
78    Num(u64),
79}
80
81/// Deserializes a number from hex or int
82pub fn deserialize_number<'de, D>(deserializer: D) -> Result<U256, D::Error>
83where
84    D: Deserializer<'de>,
85{
86    Numeric::deserialize(deserializer).map(Into::into)
87}
88
89/// Deserializes a number from hex or int, but optionally
90pub fn deserialize_number_opt<'de, D>(deserializer: D) -> Result<Option<U256>, D::Error>
91where
92    D: Deserializer<'de>,
93{
94    let num = match Option::<Numeric>::deserialize(deserializer)? {
95        Some(Numeric::U256(n)) => Some(n),
96        Some(Numeric::Num(n)) => Some(U256::from(n)),
97        _ => None,
98    };
99
100    Ok(num)
101}
102
103/// Deserializes single integer params: `1, [1], ["0x01"]`
104pub fn deserialize_number_seq<'de, D>(deserializer: D) -> Result<U256, D::Error>
105where
106    D: Deserializer<'de>,
107{
108    let num = match NumericSeq::deserialize(deserializer)? {
109        NumericSeq::Seq(seq) => seq[0].into(),
110        NumericSeq::U256(n) => n,
111        NumericSeq::Num(n) => U256::from(n),
112    };
113
114    Ok(num)
115}
116
117pub mod duration {
118    use serde::{Deserialize, Deserializer};
119    use std::time::Duration;
120
121    pub fn serialize<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>
122    where
123        S: serde::Serializer,
124    {
125        let d = jiff::SignedDuration::try_from(*duration).map_err(serde::ser::Error::custom)?;
126        serializer.serialize_str(&format!("{d:#}"))
127    }
128
129    pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
130    where
131        D: Deserializer<'de>,
132    {
133        let s = String::deserialize(deserializer)?;
134        let d = s.parse::<jiff::SignedDuration>().map_err(serde::de::Error::custom)?;
135        d.try_into().map_err(serde::de::Error::custom)
136    }
137}