serde_utils/
num.rs

1use cfx_types::{U256, U64};
2use core::str::FromStr;
3use serde::{de, Deserialize, Deserializer};
4use std::fmt;
5
6/// An enum that represents either a [serde_json::Number] integer, or a hex
7/// [U256].
8#[derive(Debug, Deserialize)]
9#[serde(untagged)]
10pub enum NumberOrHexU256 {
11    /// An integer
12    Int(serde_json::Number),
13    /// A hex U256
14    Hex(U256),
15}
16
17impl NumberOrHexU256 {
18    /// Tries to convert this into a [U256]].
19    pub fn try_into_u256<E: de::Error>(self) -> Result<U256, E> {
20        match self {
21            NumberOrHexU256::Int(num) => {
22                U256::from_str(num.to_string().as_str()).map_err(E::custom)
23            }
24            NumberOrHexU256::Hex(val) => Ok(val),
25        }
26    }
27}
28
29/// Deserializes the input into a U256, accepting both 0x-prefixed hex and
30/// decimal strings with arbitrary precision, defined by serde_json's
31/// [`Number`](serde_json::Number).
32pub fn from_int_or_hex_to_u256<'de, D>(
33    deserializer: D,
34) -> Result<U256, D::Error>
35where D: Deserializer<'de> {
36    NumberOrHexU256::deserialize(deserializer)?.try_into_u256()
37}
38
39/// Deserializes the input into an `Option<U256>`, using [`from_int_or_hex`] to
40/// deserialize the inner value.
41pub fn from_int_or_hex_to_u256_opt<'de, D>(
42    deserializer: D,
43) -> Result<Option<U256>, D::Error>
44where D: Deserializer<'de> {
45    match Option::<NumberOrHexU256>::deserialize(deserializer)? {
46        Some(val) => val.try_into_u256().map(Some),
47        None => Ok(None),
48    }
49}
50
51/// An enum that represents either a [serde_json::Number] integer, or a hex
52/// [U64].
53#[derive(Debug, Deserialize)]
54#[serde(untagged)]
55pub enum NumberOrHexU64 {
56    /// An integer
57    Int(serde_json::Number),
58    /// A hex U64
59    Hex(U64),
60}
61
62impl NumberOrHexU64 {
63    /// Tries to convert this into a [U64]].
64    pub fn try_into_u64<E: de::Error>(self) -> Result<U64, E> {
65        match self {
66            NumberOrHexU64::Int(num) => {
67                U64::from_str(num.to_string().as_str()).map_err(E::custom)
68            }
69            NumberOrHexU64::Hex(val) => Ok(val),
70        }
71    }
72}
73
74/// Deserializes the input into a U64, accepting both 0x-prefixed hex and
75/// decimal strings with arbitrary precision, defined by serde_json's
76/// [`Number`](serde_json::Number).
77pub fn from_int_or_hex_to_u64<'de, D>(
78    deserializer: D,
79) -> Result<U64, D::Error>
80where D: Deserializer<'de> {
81    NumberOrHexU64::deserialize(deserializer)?.try_into_u64()
82}
83
84/// Deserializes the input into an `Option<U64>`, using
85/// [`from_int_or_hex_to_u64`] to deserialize the inner value.
86pub fn from_int_or_hex_to_u64_opt<'de, D>(
87    deserializer: D,
88) -> Result<Option<U64>, D::Error>
89where D: Deserializer<'de> {
90    match Option::<NumberOrHexU64>::deserialize(deserializer)? {
91        Some(val) => val.try_into_u64().map(Some),
92        None => Ok(None),
93    }
94}
95
96pub fn deserialize_u64_from_num_or_hex<'de, D>(
97    deserializer: D,
98) -> Result<u64, D::Error>
99where D: Deserializer<'de> {
100    struct U64OrHexVisitor;
101
102    impl<'de> serde::de::Visitor<'de> for U64OrHexVisitor {
103        type Value = u64;
104
105        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
106            formatter
107                .write_str("a u64 integer or a hex string representing a u64")
108        }
109
110        fn visit_u64<E>(self, value: u64) -> Result<u64, E> { Ok(value) }
111
112        fn visit_str<E>(self, value: &str) -> Result<u64, E>
113        where E: serde::de::Error {
114            if let Some(stripped) = value.strip_prefix("0x") {
115                u64::from_str_radix(stripped, 16).map_err(E::custom)
116            } else {
117                Err(E::custom("expected hex string to start with '0x'"))
118            }
119        }
120    }
121
122    deserializer.deserialize_any(U64OrHexVisitor)
123}