foundry_block_explorers/
serde_helpers.rs1use crate::block_number::BlockNumber;
2use alloy_primitives::{U256, U64};
3use serde::{Deserialize, Deserializer};
4use std::str::FromStr;
5
6#[derive(Deserialize, Debug, Clone)]
8#[serde(untagged)]
9pub enum StringifiedNumeric {
10 String(String),
11 U256(U256),
12 Num(serde_json::Number),
13}
14
15impl TryFrom<StringifiedNumeric> for U256 {
16 type Error = String;
17
18 fn try_from(value: StringifiedNumeric) -> Result<Self, Self::Error> {
19 match value {
20 StringifiedNumeric::U256(n) => Ok(n),
21 StringifiedNumeric::Num(n) => {
22 Ok(U256::from_str(&n.to_string()).map_err(|err| err.to_string())?)
23 }
24 StringifiedNumeric::String(s) => {
25 if let Ok(val) = s.parse::<u128>() {
26 Ok(U256::from(val))
27 } else if s.starts_with("0x") {
28 U256::from_str_radix(&s, 16).map_err(|err| err.to_string())
29 } else {
30 U256::from_str(&s).map_err(|err| err.to_string())
31 }
32 }
33 }
34 }
35}
36
37impl TryFrom<StringifiedNumeric> for U64 {
38 type Error = String;
39
40 fn try_from(value: StringifiedNumeric) -> Result<Self, Self::Error> {
41 let value = U256::try_from(value)?;
42 Ok(value.wrapping_to::<U64>())
43 }
44}
45
46#[derive(Deserialize)]
47#[serde(untagged)]
48enum BoolOrU64 {
49 #[serde(deserialize_with = "deserialize_stringified_u64")]
50 U64(u64),
51 Bool(String),
52}
53
54pub fn deserialize_stringified_bool_or_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>
59where
60 D: Deserializer<'de>,
61{
62 let num = BoolOrU64::deserialize(deserializer)?;
63 match num {
64 BoolOrU64::Bool(b) => {
65 let b = b.parse::<bool>().map_err(serde::de::Error::custom)?;
66 let u = if b { 1 } else { 0 };
67 Ok(u)
68 }
69 BoolOrU64::U64(u) => Ok(u),
70 }
71}
72
73pub fn deserialize_stringified_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>
77where
78 D: Deserializer<'de>,
79{
80 let num = StringifiedNumeric::deserialize(deserializer)?;
81 let num: U256 = num.try_into().map_err(serde::de::Error::custom)?;
82 num.try_into().map_err(serde::de::Error::custom)
83}
84
85pub fn deserialize_stringified_numeric<'de, D>(deserializer: D) -> Result<U256, D::Error>
89where
90 D: Deserializer<'de>,
91{
92 let num = StringifiedNumeric::deserialize(deserializer)?;
93 num.try_into().map_err(serde::de::Error::custom)
94}
95
96pub fn deserialize_stringified_numeric_opt<'de, D>(
100 deserializer: D,
101) -> Result<Option<U256>, D::Error>
102where
103 D: Deserializer<'de>,
104{
105 if let Some(num) = Option::<StringifiedNumeric>::deserialize(deserializer)? {
106 num.try_into().map(Some).map_err(serde::de::Error::custom)
107 } else {
108 Ok(None)
109 }
110}
111
112pub fn deserialize_stringified_u64_opt<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
116where
117 D: Deserializer<'de>,
118{
119 if let Some(num) = Option::<StringifiedNumeric>::deserialize(deserializer)? {
120 let num: U256 = num.try_into().map_err(serde::de::Error::custom)?;
121 let num: u64 = num.try_into().map_err(serde::de::Error::custom)?;
122 Ok(Some(num))
123 } else {
124 Ok(None)
125 }
126}
127
128#[derive(Deserialize, Debug, Clone)]
130#[serde(untagged)]
131pub enum StringifiedBlockNumber {
132 Numeric(StringifiedNumeric),
133 BlockNumber(BlockNumber),
134}
135
136impl TryFrom<StringifiedBlockNumber> for BlockNumber {
137 type Error = String;
138
139 fn try_from(value: StringifiedBlockNumber) -> Result<Self, Self::Error> {
140 match value {
141 StringifiedBlockNumber::Numeric(num) => {
142 let num = U256::try_from(num)
143 .and_then(|num| u64::try_from(num).map_err(|e| e.to_string()))?;
144 Ok(BlockNumber::Number(U64::from(num)))
145 }
146 StringifiedBlockNumber::BlockNumber(b) => Ok(b),
147 }
148 }
149}
150
151pub fn deserialize_stringified_block_number<'de, D>(
155 deserializer: D,
156) -> Result<BlockNumber, D::Error>
157where
158 D: Deserializer<'de>,
159{
160 let num = StringifiedBlockNumber::deserialize(deserializer)?;
161 num.try_into().map_err(serde::de::Error::custom)
162}