alux_shape_rust/
written.rs1use serde::de::{Error as DeError, Unexpected};
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9use std::fmt::Display;
10use std::str::FromStr;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
14pub struct Hex<T>(pub T);
15
16fn write_hex<S>(bytes: &[u8], writer: S) -> Result<S::Ok, S::Error>
18where
19 S: Serializer,
20{
21 let mut text = String::with_capacity(2 + bytes.len() * 2);
22 text.push_str("0x");
23
24 for byte in bytes {
25 text.push_str(&format!("{byte:02x}"));
26 }
27
28 writer.serialize_str(&text)
29}
30
31fn read_hex<E>(text: &str) -> Result<Vec<u8>, E>
33where
34 E: DeError,
35{
36 let digits = text
37 .strip_prefix("0x")
38 .ok_or_else(|| E::invalid_value(Unexpected::Str(text), &"hexadecimal text, `0x`-prefixed"))?;
39
40 if digits.len() % 2 != 0 {
41 return Err(E::invalid_length(digits.len(), &"an even number of hexadecimal digits"));
42 }
43
44 (0..digits.len() / 2)
45 .map(|index| {
46 u8::from_str_radix(&digits[index * 2..index * 2 + 2], 16)
47 .map_err(|_| E::invalid_value(Unexpected::Str(text), &"hexadecimal digits"))
48 })
49 .collect()
50}
51
52impl<const N: usize> Serialize for Hex<[u8; N]> {
53 fn serialize<S>(&self, writer: S) -> Result<S::Ok, S::Error>
54 where
55 S: Serializer,
56 {
57 write_hex(&self.0, writer)
58 }
59}
60
61impl<'de, const N: usize> Deserialize<'de> for Hex<[u8; N]> {
62 fn deserialize<D>(reader: D) -> Result<Self, D::Error>
63 where
64 D: Deserializer<'de>,
65 {
66 let text = String::deserialize(reader)?;
67 let bytes = read_hex::<D::Error>(&text)?;
68
69 bytes.try_into().map(Hex).map_err(|bytes: Vec<u8>| D::Error::invalid_length(bytes.len(), &"the stated length"))
70 }
71}
72
73impl Serialize for Hex<Vec<u8>> {
74 fn serialize<S>(&self, writer: S) -> Result<S::Ok, S::Error>
75 where
76 S: Serializer,
77 {
78 write_hex(&self.0, writer)
79 }
80}
81
82impl<'de> Deserialize<'de> for Hex<Vec<u8>> {
83 fn deserialize<D>(reader: D) -> Result<Self, D::Error>
84 where
85 D: Deserializer<'de>,
86 {
87 let text = String::deserialize(reader)?;
88
89 read_hex::<D::Error>(&text).map(Hex)
90 }
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
95pub struct Decimal<T>(pub T);
96
97impl<T> Serialize for Decimal<T>
98where
99 T: Display,
100{
101 fn serialize<S>(&self, writer: S) -> Result<S::Ok, S::Error>
102 where
103 S: Serializer,
104 {
105 writer.collect_str(&self.0)
106 }
107}
108
109impl<'de, T> Deserialize<'de> for Decimal<T>
110where
111 T: FromStr,
112 T::Err: Display,
113{
114 fn deserialize<D>(reader: D) -> Result<Self, D::Error>
115 where
116 D: Deserializer<'de>,
117 {
118 let text = String::deserialize(reader)?;
119
120 text.parse().map(Decimal).map_err(D::Error::custom)
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn bytes_are_written_and_read_as_hexadecimal() {
130 let value = Hex([0xbe_u8, 0xef]);
131 let json = serde_json::to_string(&value).expect("writes");
132
133 assert_eq!(json, "\"0xbeef\"");
134 assert_eq!(serde_json::from_str::<Hex<[u8; 2]>>(&json).expect("reads"), value);
135 }
136
137 #[test]
138 fn a_wide_number_is_written_and_read_as_decimal_text() {
139 let value = Decimal(u128::from(u64::MAX) + 1);
140 let json = serde_json::to_string(&value).expect("writes");
141
142 assert_eq!(json, "\"18446744073709551616\"");
143 assert_eq!(serde_json::from_str::<Decimal<u128>>(&json).expect("reads"), value);
144 }
145
146 #[test]
147 fn text_that_is_not_hexadecimal_is_not_read() {
148 assert!(serde_json::from_str::<Hex<[u8; 2]>>("\"beef\"").is_err());
149 assert!(serde_json::from_str::<Hex<[u8; 2]>>("\"0xbe\"").is_err());
150 }
151}