1use std::{collections::BTreeMap, fmt, marker::PhantomData};
2
3use js_int::{Int, UInt};
4use serde::{
5 de::{self, Deserializer, IntoDeserializer as _, MapAccess, Visitor},
6 ser::Serializer,
7 Deserialize, Serialize,
8};
9
10pub fn empty_string_as_none<'de, D, T>(de: D) -> Result<Option<T>, D::Error>
22where
23 D: Deserializer<'de>,
24 T: Deserialize<'de>,
25{
26 let opt = Option::<String>::deserialize(de)?;
27 match opt.as_deref() {
28 None | Some("") => Ok(None),
29 Some(s) => T::deserialize(s.into_deserializer()).map(Some),
32 }
33}
34
35pub fn none_as_empty_string<T: Serialize, S>(
41 value: &Option<T>,
42 serializer: S,
43) -> Result<S::Ok, S::Error>
44where
45 S: Serializer,
46{
47 match value {
48 Some(x) => x.serialize(serializer),
49 None => serializer.serialize_str(""),
50 }
51}
52
53pub fn deserialize_as_number_or_string<'de, D>(de: D) -> Result<f64, D::Error>
58where
59 D: Deserializer<'de>,
60{
61 struct F64OrStringVisitor;
62
63 impl Visitor<'_> for F64OrStringVisitor {
64 type Value = f64;
65
66 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
67 formatter.write_str("a double or a string")
68 }
69
70 fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
71 where
72 E: de::Error,
73 {
74 Ok(v.into())
75 }
76
77 fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
78 where
79 E: de::Error,
80 {
81 Ok(v)
82 }
83
84 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
85 where
86 E: de::Error,
87 {
88 if v <= (f64::MAX as u64) {
89 Ok(v as f64)
90 } else {
91 Err(E::custom("u64 is too large to fit into a f64"))
92 }
93 }
94
95 fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
96 where
97 E: de::Error,
98 {
99 if v <= (f64::MAX as i64) && v >= (f64::MIN as i64) {
100 Ok(v as f64)
101 } else {
102 Err(E::custom("i64 is too large to fit into a f64"))
103 }
104 }
105
106 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
107 v.parse().map_err(E::custom)
108 }
109 }
110
111 de.deserialize_any(F64OrStringVisitor)
112}
113
114#[derive(Deserialize)]
115struct NumberOrStringWrapper(#[serde(deserialize_with = "deserialize_as_number_or_string")] f64);
116
117pub fn deserialize_as_optional_number_or_string<'de, D>(
119 deserializer: D,
120) -> Result<Option<f64>, D::Error>
121where
122 D: Deserializer<'de>,
123{
124 Ok(Option::<NumberOrStringWrapper>::deserialize(deserializer)?.map(|w| w.0))
125}
126
127pub fn deserialize_v1_powerlevel<'de, D>(de: D) -> Result<Int, D::Error>
132where
133 D: Deserializer<'de>,
134{
135 struct IntOrStringVisitor;
136
137 impl Visitor<'_> for IntOrStringVisitor {
138 type Value = Int;
139
140 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
141 formatter.write_str("an integer or a string")
142 }
143
144 fn visit_i8<E: de::Error>(self, v: i8) -> Result<Self::Value, E> {
145 Ok(v.into())
146 }
147
148 fn visit_i16<E: de::Error>(self, v: i16) -> Result<Self::Value, E> {
149 Ok(v.into())
150 }
151
152 fn visit_i32<E: de::Error>(self, v: i32) -> Result<Self::Value, E> {
153 Ok(v.into())
154 }
155
156 fn visit_i64<E: de::Error>(self, v: i64) -> Result<Self::Value, E> {
157 v.try_into().map_err(E::custom)
158 }
159
160 fn visit_i128<E: de::Error>(self, v: i128) -> Result<Self::Value, E> {
161 v.try_into().map_err(E::custom)
162 }
163
164 fn visit_u8<E: de::Error>(self, v: u8) -> Result<Self::Value, E> {
165 Ok(v.into())
166 }
167
168 fn visit_u16<E: de::Error>(self, v: u16) -> Result<Self::Value, E> {
169 Ok(v.into())
170 }
171
172 fn visit_u32<E: de::Error>(self, v: u32) -> Result<Self::Value, E> {
173 Ok(v.into())
174 }
175
176 fn visit_u64<E: de::Error>(self, v: u64) -> Result<Self::Value, E> {
177 v.try_into().map_err(E::custom)
178 }
179
180 fn visit_u128<E: de::Error>(self, v: u128) -> Result<Self::Value, E> {
181 v.try_into().map_err(E::custom)
182 }
183
184 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
185 let trimmed = v.trim();
186
187 match trimmed.strip_prefix('+') {
188 Some(without) => without.parse::<UInt>().map(|u| u.into()).map_err(E::custom),
189 None => trimmed.parse().map_err(E::custom),
190 }
191 }
192 }
193
194 de.deserialize_any(IntOrStringVisitor)
195}
196
197pub fn btreemap_deserialize_v1_powerlevel_values<'de, D, T>(
203 de: D,
204) -> Result<BTreeMap<T, Int>, D::Error>
205where
206 D: Deserializer<'de>,
207 T: Deserialize<'de> + Ord,
208{
209 #[repr(transparent)]
210 struct IntWrap(Int);
211
212 impl<'de> Deserialize<'de> for IntWrap {
213 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
214 where
215 D: Deserializer<'de>,
216 {
217 deserialize_v1_powerlevel(deserializer).map(IntWrap)
218 }
219 }
220
221 struct IntMapVisitor<T> {
222 _phantom: PhantomData<T>,
223 }
224
225 impl<T> IntMapVisitor<T> {
226 fn new() -> Self {
227 Self { _phantom: PhantomData }
228 }
229 }
230
231 impl<'de, T> Visitor<'de> for IntMapVisitor<T>
232 where
233 T: Deserialize<'de> + Ord,
234 {
235 type Value = BTreeMap<T, Int>;
236
237 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
238 formatter.write_str("a map with integers or strings as values")
239 }
240
241 fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
242 let mut res = BTreeMap::new();
243
244 while let Some((k, IntWrap(v))) = map.next_entry()? {
245 res.insert(k, v);
246 }
247
248 Ok(res)
249 }
250 }
251
252 de.deserialize_map(IntMapVisitor::new())
253}
254
255#[cfg(test)]
256mod tests {
257 use js_int::{int, Int};
258 use serde::Deserialize;
259
260 use super::deserialize_v1_powerlevel;
261
262 #[derive(Debug, Deserialize)]
263 struct Test {
264 #[serde(deserialize_with = "deserialize_v1_powerlevel")]
265 num: Int,
266 }
267
268 #[test]
269 fn int_or_string() {
270 let test = serde_json::from_value::<Test>(serde_json::json!({ "num": "0" })).unwrap();
271 assert_eq!(test.num, int!(0));
272 }
273
274 #[test]
275 fn weird_plus_string() {
276 let test =
277 serde_json::from_value::<Test>(serde_json::json!({ "num": " +0000000001000 " }))
278 .unwrap();
279 assert_eq!(test.num, int!(1000));
280 }
281
282 #[test]
283 fn weird_minus_string() {
284 let test = serde_json::from_value::<Test>(
285 serde_json::json!({ "num": " \n\n-0000000000000001000 " }),
286 )
287 .unwrap();
288 assert_eq!(test.num, int!(-1000));
289 }
290}