1#![cfg(feature = "serde")]
4#![cfg_attr(docsrs, doc(cfg(feature = "serde")))]
5
6use crate::{nbytes, Bits, Uint};
7use core::{
8 fmt::{Formatter, Result as FmtResult, Write},
9 str,
10};
11use serde::{
12 de::{Error, Unexpected, Visitor},
13 Deserialize, Deserializer, Serialize, Serializer,
14};
15
16#[allow(unused_imports)]
17use alloc::string::String;
18
19const ZERO_STR: &str = "0x0";
22
23impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
24 fn serialize_human_full<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
25 if BITS == 0 {
26 return s.serialize_str(ZERO_STR);
27 }
28
29 let mut result = String::with_capacity(2 + nbytes(BITS) * 2);
30 result.push_str("0x");
31
32 self.as_le_bytes()
33 .iter()
34 .rev()
35 .try_for_each(|byte| write!(result, "{byte:02x}"))
36 .unwrap();
37
38 s.serialize_str(&result)
39 }
40
41 fn serialize_human_minimal<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
42 if self.is_zero() {
43 return s.serialize_str(ZERO_STR);
44 }
45
46 s.serialize_str(&format!("{self:#x}"))
47 }
48
49 fn serialize_binary<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
50 s.serialize_bytes(&self.to_be_bytes_vec())
51 }
52}
53
54impl<const BITS: usize, const LIMBS: usize> Serialize for Uint<BITS, LIMBS> {
59 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
60 if serializer.is_human_readable() {
61 self.serialize_human_minimal(serializer)
62 } else {
63 self.serialize_binary(serializer)
64 }
65 }
66}
67
68impl<'de, const BITS: usize, const LIMBS: usize> Deserialize<'de> for Uint<BITS, LIMBS> {
73 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
74 if deserializer.is_human_readable() {
75 deserializer.deserialize_any(HrVisitor)
76 } else {
77 deserializer.deserialize_bytes(ByteVisitor)
78 }
79 }
80}
81
82impl<const BITS: usize, const LIMBS: usize> Serialize for Bits<BITS, LIMBS> {
83 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
84 if serializer.is_human_readable() {
85 self.as_uint().serialize_human_full(serializer)
86 } else {
87 self.as_uint().serialize_binary(serializer)
88 }
89 }
90}
91
92impl<'de, const BITS: usize, const LIMBS: usize> Deserialize<'de> for Bits<BITS, LIMBS> {
93 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
94 Uint::deserialize(deserializer).map(Self::from)
95 }
96}
97
98struct HrVisitor<const BITS: usize, const LIMBS: usize>;
102
103impl<const BITS: usize, const LIMBS: usize> Visitor<'_> for HrVisitor<BITS, LIMBS> {
104 type Value = Uint<BITS, LIMBS>;
105
106 fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
107 write!(formatter, "a {} byte hex string", nbytes(BITS))
108 }
109
110 fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
111 Uint::try_from(v).map_err(|_| Error::invalid_value(Unexpected::Unsigned(v), &self))
112 }
113
114 fn visit_u128<E: Error>(self, v: u128) -> Result<Self::Value, E> {
115 Uint::try_from(v).map_err(Error::custom)
117 }
118
119 fn visit_str<E: Error>(self, value: &str) -> Result<Self::Value, E> {
120 if value == ZERO_STR {
122 return Ok(Uint::<BITS, LIMBS>::ZERO);
123 }
124 if BITS == 0 {
127 return Err(Error::invalid_value(Unexpected::Str(value), &self));
128 }
129
130 value
131 .parse()
132 .map_err(|_| Error::invalid_value(Unexpected::Str(value), &self))
133 }
134}
135
136struct ByteVisitor<const BITS: usize, const LIMBS: usize>;
138
139impl<const BITS: usize, const LIMBS: usize> Visitor<'_> for ByteVisitor<BITS, LIMBS> {
140 type Value = Uint<BITS, LIMBS>;
141
142 fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
143 write!(formatter, "{BITS} bits of binary data in big endian order")
144 }
145
146 fn visit_bytes<E: Error>(self, value: &[u8]) -> Result<Self::Value, E> {
147 if value.len() != nbytes(BITS) {
148 return Err(Error::invalid_length(value.len(), &self));
149 }
150 Uint::try_from_be_slice(value).ok_or_else(|| {
151 Error::invalid_value(
152 Unexpected::Other(&format!("too large for Uint<{BITS}>")),
153 &self,
154 )
155 })
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162 use crate::{const_for, nlimbs};
163 use proptest::proptest;
164
165 #[allow(unused_imports)]
166 use alloc::vec::Vec;
167
168 #[test]
169 fn test_serde_human_readable() {
170 const_for!(BITS in SIZES {
171 const LIMBS: usize = nlimbs(BITS);
172 proptest!(|(value: Uint<BITS, LIMBS>)| {
173 let serialized = serde_json::to_string(&value).unwrap();
174 let deserialized = serde_json::from_str(&serialized).unwrap();
175 assert_eq!(value, deserialized);
176 });
177 proptest!(|(value: Bits<BITS, LIMBS>)| {
178 let serialized = serde_json::to_string(&value).unwrap();
179 let deserialized = serde_json::from_str(&serialized).unwrap();
180 assert_eq!(value, deserialized);
181 });
182 });
183 }
184
185 #[test]
186 fn test_human_readable_de() {
187 let jason = r#"[
188 1,
189 "0x1",
190 "0o1",
191 "0b1"
192 ]"#;
193 let numbers: Vec<Uint<1, 1>> = serde_json::from_str(jason).unwrap();
194 uint! {
195 assert_eq!(numbers, vec![1_U1, 1_U1, 1_U1, 1_U1]);
196 }
197
198 let jason = r#"[
199 "",
200 "0x",
201 "0o",
202 "0b"
203 ]"#;
204 let numbers: Vec<Uint<1, 1>> = serde_json::from_str(jason).unwrap();
205 uint! {
206 assert_eq!(numbers, vec![0_U1, 0_U1, 0_U1, 0_U1]);
207 }
208 }
209
210 #[test]
211 fn test_serde_machine_readable() {
212 const_for!(BITS in SIZES {
213 const LIMBS: usize = nlimbs(BITS);
214 proptest!(|(value: Uint<BITS, LIMBS>)| {
215 let serialized = bincode::serialize(&value).unwrap();
216 let deserialized = bincode::deserialize(&serialized[..]).unwrap();
217 assert_eq!(value, deserialized);
218 });
219 proptest!(|(value: Bits<BITS, LIMBS>)| {
220 let serialized = bincode::serialize(&value).unwrap();
221 let deserialized = bincode::deserialize(&serialized[..]).unwrap();
222 assert_eq!(value, deserialized);
223 });
224 });
225 }
226
227 #[test]
228 fn test_serde_invalid_size_error() {
229 const_for!(BITS in SIZES {
232 const LIMBS: usize = nlimbs(BITS);
233 let value = Uint::<BITS, LIMBS>::MAX;
234 let mut serialized = serde_json::to_string(&value).unwrap();
235
236 assert_eq!(&serialized[..3], "\"0x");
238 assert_eq!(&serialized[serialized.len() - 1..], "\"");
240
241 serialized.pop();
243 serialized.push('0');
244 serialized.push('"');
245 let deserialized = serde_json::from_str::<Uint<BITS, LIMBS>>(&serialized);
246 assert!(deserialized.is_err(), "{BITS} {serialized}");
247 });
248 }
249}