openzeppelin_relayer/utils/serde/
u64_deserializer.rs1use std::fmt;
9
10use serde::{de, Deserializer, Serializer};
11
12use super::safe_float::f64_to_safe_integer;
13
14#[derive(Debug)]
15struct U64Visitor;
16
17impl de::Visitor<'_> for U64Visitor {
18 type Value = u64;
19
20 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
21 formatter.write_str("a string containing a u64 number or a u64 integer")
22 }
23
24 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
26 where
27 E: de::Error,
28 {
29 value.parse::<u64>().map_err(de::Error::custom)
30 }
31
32 #[allow(clippy::unnecessary_cast)]
34 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
35 where
36 E: de::Error,
37 {
38 Ok(value)
39 }
40
41 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
43 where
44 E: de::Error,
45 {
46 if value < 0 {
47 Err(de::Error::custom(
48 "negative value cannot be converted to u64",
49 ))
50 } else {
51 Ok(value as u64)
52 }
53 }
54
55 fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
58 where
59 E: de::Error,
60 {
61 let n = f64_to_safe_integer::<E>(value)?;
62 u64::try_from(n).map_err(de::Error::custom)
63 }
64}
65
66pub fn deserialize_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>
67where
68 D: Deserializer<'de>,
69{
70 deserializer.deserialize_any(U64Visitor)
71}
72
73pub fn serialize_u64<S>(value: &u64, serializer: S) -> Result<S::Ok, S::Error>
76where
77 S: Serializer,
78{
79 serializer.serialize_str(&value.to_string())
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use serde::de::value::{
86 Error as ValueError, I64Deserializer, StringDeserializer, U64Deserializer,
87 };
88
89 #[test]
90 fn test_deserialize_from_string() {
91 let input = "12345";
92 let deserializer = StringDeserializer::<ValueError>::new(input.to_string());
93 let result = deserialize_u64(deserializer);
94 assert!(result.is_ok());
95 assert_eq!(result.unwrap(), 12345);
96 }
97
98 #[test]
99 fn test_deserialize_from_string_max_u64() {
100 let input = "18446744073709551615"; let deserializer = StringDeserializer::<ValueError>::new(input.to_string());
102 let result = deserialize_u64(deserializer);
103 assert!(result.is_ok());
104 assert_eq!(result.unwrap(), u64::MAX);
105 }
106
107 #[test]
108 fn test_deserialize_from_invalid_string() {
109 let input = "not a number";
110 let deserializer = StringDeserializer::<ValueError>::new(input.to_string());
111 let result = deserialize_u64(deserializer);
112 assert!(result.is_err());
113 }
114
115 #[test]
116 fn test_deserialize_from_u64() {
117 let input: u64 = 54321;
118 let deserializer = U64Deserializer::<ValueError>::new(input);
119 let result = deserialize_u64(deserializer);
120 assert!(result.is_ok());
121 assert_eq!(result.unwrap(), 54321);
122 }
123
124 #[test]
125 fn test_deserialize_from_i64_positive() {
126 let input: i64 = 9876;
127 let deserializer = I64Deserializer::<ValueError>::new(input);
128 let result = deserialize_u64(deserializer);
129 assert!(result.is_ok());
130 assert_eq!(result.unwrap(), 9876);
131 }
132
133 #[test]
134 fn test_deserialize_from_i64_negative() {
135 let input: i64 = -123;
136 let deserializer = I64Deserializer::<ValueError>::new(input);
137 let result = deserialize_u64(deserializer);
138 assert!(result.is_err());
139 }
140
141 #[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug)]
142 struct Wrapper {
143 #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
144 id: u64,
145 }
146
147 #[test]
148 fn serializes_as_string() {
149 let json = serde_json::to_string(&Wrapper {
150 id: 18446744073709551615,
151 })
152 .unwrap();
153 assert_eq!(json, r#"{"id":"18446744073709551615"}"#);
154 }
155
156 #[test]
157 fn deserializes_from_string_integer_and_corrupted_float() {
158 let from_str: Wrapper = serde_json::from_str(r#"{"id":"1099511627776"}"#).unwrap();
159 assert_eq!(from_str.id, 1099511627776);
160 let from_int: Wrapper = serde_json::from_str(r#"{"id":1099511627776}"#).unwrap();
161 assert_eq!(from_int.id, 1099511627776);
162 let from_float: Wrapper = serde_json::from_str(r#"{"id":1099511627776.0}"#).unwrap();
163 assert_eq!(from_float.id, 1099511627776);
164 }
165
166 #[test]
167 fn rejects_corrupted_float_beyond_safe_range() {
168 assert!(serde_json::from_str::<Wrapper>(r#"{"id":9007199254740993.0}"#).is_err());
169 }
170}