foundry_common/
serde_helpers.rs

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