openzeppelin_relayer/utils/serde/
i64_serializer.rs1use std::fmt;
18
19use serde::{de, Deserialize, Deserializer, Serializer};
20
21use super::safe_float::f64_to_safe_integer;
22
23#[derive(Debug)]
24struct I64Visitor;
25
26impl de::Visitor<'_> for I64Visitor {
27 type Value = i64;
28
29 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
30 formatter.write_str("a string, integer, or float representing an i64")
31 }
32
33 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
35 where
36 E: de::Error,
37 {
38 value.parse::<i64>().map_err(de::Error::custom)
39 }
40
41 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
43 where
44 E: de::Error,
45 {
46 Ok(value)
47 }
48
49 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
50 where
51 E: de::Error,
52 {
53 i64::try_from(value).map_err(de::Error::custom)
54 }
55
56 fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
60 where
61 E: de::Error,
62 {
63 let n = f64_to_safe_integer::<E>(value)?;
64 i64::try_from(n).map_err(de::Error::custom)
65 }
66}
67
68pub fn deserialize_i64<'de, D>(deserializer: D) -> Result<i64, D::Error>
71where
72 D: Deserializer<'de>,
73{
74 deserializer.deserialize_any(I64Visitor)
75}
76
77pub fn serialize_i64<S>(value: &i64, serializer: S) -> Result<S::Ok, S::Error>
80where
81 S: Serializer,
82{
83 serializer.serialize_str(&value.to_string())
84}
85
86pub fn deserialize_optional_i64<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error>
90where
91 D: Deserializer<'de>,
92{
93 #[derive(Deserialize)]
94 struct Helper(#[serde(deserialize_with = "deserialize_i64")] i64);
95
96 let helper = Option::<Helper>::deserialize(deserializer)?;
97 Ok(helper.map(|Helper(value)| value))
98}
99
100pub fn serialize_optional_i64<S>(value: &Option<i64>, serializer: S) -> Result<S::Ok, S::Error>
103where
104 S: Serializer,
105{
106 match value {
107 Some(v) => serializer.serialize_some(&v.to_string()),
108 None => serializer.serialize_none(),
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug)]
117 struct Wrapper {
118 #[serde(
119 serialize_with = "serialize_optional_i64",
120 deserialize_with = "deserialize_optional_i64",
121 default
122 )]
123 seq: Option<i64>,
124 }
125
126 #[test]
127 fn serializes_as_string() {
128 let json = serde_json::to_string(&Wrapper {
129 seq: Some(643918676885760),
130 })
131 .unwrap();
132 assert_eq!(json, r#"{"seq":"643918676885760"}"#);
133 }
134
135 #[test]
136 fn serializes_none_as_null() {
137 let json = serde_json::to_string(&Wrapper { seq: None }).unwrap();
138 assert_eq!(json, r#"{"seq":null}"#);
139 }
140
141 #[test]
142 fn deserializes_from_string() {
143 let w: Wrapper = serde_json::from_str(r#"{"seq":"643918676885760"}"#).unwrap();
144 assert_eq!(w.seq, Some(643918676885760));
145 }
146
147 #[test]
148 fn deserializes_from_legacy_integer() {
149 let w: Wrapper = serde_json::from_str(r#"{"seq":643918676885760}"#).unwrap();
150 assert_eq!(w.seq, Some(643918676885760));
151 }
152
153 #[test]
154 fn deserializes_from_corrupted_float() {
155 let w: Wrapper = serde_json::from_str(r#"{"seq":643918676885760.0}"#).unwrap();
156 assert_eq!(w.seq, Some(643918676885760));
157 }
158
159 #[test]
160 fn deserializes_negative() {
161 let w: Wrapper = serde_json::from_str(r#"{"seq":-5}"#).unwrap();
162 assert_eq!(w.seq, Some(-5));
163 let w: Wrapper = serde_json::from_str(r#"{"seq":"-5"}"#).unwrap();
164 assert_eq!(w.seq, Some(-5));
165 }
166
167 #[test]
168 fn deserializes_null_and_missing() {
169 let w: Wrapper = serde_json::from_str(r#"{"seq":null}"#).unwrap();
170 assert_eq!(w.seq, None);
171 let w: Wrapper = serde_json::from_str(r#"{}"#).unwrap();
172 assert_eq!(w.seq, None);
173 }
174
175 #[test]
176 fn rejects_non_integral_float() {
177 assert!(serde_json::from_str::<Wrapper>(r#"{"seq":1.5}"#).is_err());
178 }
179
180 #[test]
181 fn rejects_float_beyond_safe_integer_range() {
182 assert!(serde_json::from_str::<Wrapper>(r#"{"seq":9007199254740993.0}"#).is_err());
185 }
186
187 #[test]
188 fn deserializes_large_string_beyond_safe_range() {
189 let w: Wrapper = serde_json::from_str(r#"{"seq":"9007199254740993"}"#).unwrap();
191 assert_eq!(w.seq, Some(9007199254740993));
192 }
193}