Skip to main content

slack_web_api/
de.rs

1//! Lenient deserializers used by the generated response types.
2//!
3//! Slack returns some fields as a string in one place and a number in another (`ts`, `date_created`,
4//! `post_at`, ...). These functions accept such variations so that one unexpected type does not fail
5//! the whole response. They read values directly through a `Visitor`, without an intermediate tree.
6
7use serde::de::{self, Deserializer, IgnoredAny, Visitor};
8use serde::Deserialize;
9use std::fmt;
10use std::marker::PhantomData;
11
12/// Reads a string; numbers and booleans are converted to strings.
13///
14/// # Errors
15///
16/// Only when the input itself is malformed.
17pub fn opt_string<'de, D: Deserializer<'de>>(d: D) -> Result<Option<String>, D::Error> {
18    d.deserialize_any(OptVisitor(PhantomData::<String>))
19}
20
21/// Reads an integer; numeric strings and floats (truncated) are accepted.
22///
23/// # Errors
24///
25/// Only when the input itself is malformed.
26pub fn opt_i64<'de, D: Deserializer<'de>>(d: D) -> Result<Option<i64>, D::Error> {
27    d.deserialize_any(OptVisitor(PhantomData::<i64>))
28}
29
30/// Reads a float; numeric strings are accepted.
31///
32/// # Errors
33///
34/// Only when the input itself is malformed.
35pub fn opt_f64<'de, D: Deserializer<'de>>(d: D) -> Result<Option<f64>, D::Error> {
36    d.deserialize_any(OptVisitor(PhantomData::<f64>))
37}
38
39/// Reads a boolean; `0`/`1` and `"true"`/`"false"` are accepted.
40///
41/// # Errors
42///
43/// Only when the input itself is malformed.
44pub fn opt_bool<'de, D: Deserializer<'de>>(d: D) -> Result<Option<bool>, D::Error> {
45    d.deserialize_any(OptVisitor(PhantomData::<bool>))
46}
47
48/// Reads an array; `null` and non-array values become an empty `Vec`.
49///
50/// # Errors
51///
52/// When an element cannot be read as `T`.
53pub fn vec<'de, D: Deserializer<'de>, T: Deserialize<'de>>(d: D) -> Result<Vec<T>, D::Error> {
54    d.deserialize_any(VecVisitor(PhantomData))
55}
56
57/// Reads an object; `null` and non-object values (`""`, `false`, ...) become `None`.
58///
59/// # Errors
60///
61/// When the object cannot be read as `T`.
62pub fn opt_object<'de, D: Deserializer<'de>, T: Deserialize<'de>>(
63    d: D,
64) -> Result<Option<T>, D::Error> {
65    d.deserialize_any(ObjectVisitor(PhantomData))
66}
67
68// 型ごとの変換規則。読めない値は None(項目が無いのと同じ扱い)にする
69trait Lenient: Sized {
70    const EXPECTING: &'static str;
71    fn from_str(v: &str) -> Option<Self>;
72    fn from_i64(v: i64) -> Option<Self>;
73    fn from_u64(v: u64) -> Option<Self>;
74    fn from_f64(v: f64) -> Option<Self>;
75    fn from_bool(v: bool) -> Option<Self>;
76}
77
78impl Lenient for String {
79    const EXPECTING: &'static str = "a string";
80    fn from_str(v: &str) -> Option<Self> {
81        Some(v.to_owned())
82    }
83    fn from_i64(v: i64) -> Option<Self> {
84        Some(v.to_string())
85    }
86    fn from_u64(v: u64) -> Option<Self> {
87        Some(v.to_string())
88    }
89    fn from_f64(v: f64) -> Option<Self> {
90        Some(v.to_string())
91    }
92    fn from_bool(v: bool) -> Option<Self> {
93        Some(v.to_string())
94    }
95}
96
97impl Lenient for i64 {
98    const EXPECTING: &'static str = "an integer";
99    fn from_str(v: &str) -> Option<Self> {
100        v.parse::<i64>()
101            .ok()
102            .or_else(|| v.parse::<f64>().ok().map(|f| f as i64))
103    }
104    fn from_i64(v: i64) -> Option<Self> {
105        Some(v)
106    }
107    fn from_u64(v: u64) -> Option<Self> {
108        i64::try_from(v).ok()
109    }
110    fn from_f64(v: f64) -> Option<Self> {
111        Some(v as i64)
112    }
113    fn from_bool(v: bool) -> Option<Self> {
114        Some(i64::from(v))
115    }
116}
117
118impl Lenient for f64 {
119    const EXPECTING: &'static str = "a number";
120    fn from_str(v: &str) -> Option<Self> {
121        v.parse().ok()
122    }
123    fn from_i64(v: i64) -> Option<Self> {
124        Some(v as f64)
125    }
126    fn from_u64(v: u64) -> Option<Self> {
127        Some(v as f64)
128    }
129    fn from_f64(v: f64) -> Option<Self> {
130        Some(v)
131    }
132    fn from_bool(v: bool) -> Option<Self> {
133        Some(if v { 1.0 } else { 0.0 })
134    }
135}
136
137impl Lenient for bool {
138    const EXPECTING: &'static str = "a boolean";
139    fn from_str(v: &str) -> Option<Self> {
140        match v {
141            "true" | "1" => Some(true),
142            "false" | "0" | "" => Some(false),
143            _ => None,
144        }
145    }
146    fn from_i64(v: i64) -> Option<Self> {
147        Some(v != 0)
148    }
149    fn from_u64(v: u64) -> Option<Self> {
150        Some(v != 0)
151    }
152    fn from_f64(v: f64) -> Option<Self> {
153        Some(v != 0.0)
154    }
155    fn from_bool(v: bool) -> Option<Self> {
156        Some(v)
157    }
158}
159
160struct OptVisitor<T>(PhantomData<T>);
161
162impl<'de, T: Lenient> Visitor<'de> for OptVisitor<T> {
163    type Value = Option<T>;
164
165    fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166        f.write_str(T::EXPECTING)
167    }
168    fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
169        Ok(T::from_str(v))
170    }
171    fn visit_i64<E: de::Error>(self, v: i64) -> Result<Self::Value, E> {
172        Ok(T::from_i64(v))
173    }
174    fn visit_u64<E: de::Error>(self, v: u64) -> Result<Self::Value, E> {
175        Ok(T::from_u64(v))
176    }
177    fn visit_f64<E: de::Error>(self, v: f64) -> Result<Self::Value, E> {
178        Ok(T::from_f64(v))
179    }
180    fn visit_bool<E: de::Error>(self, v: bool) -> Result<Self::Value, E> {
181        Ok(T::from_bool(v))
182    }
183    fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
184        Ok(None)
185    }
186    // スカラーのはずの項目に配列・オブジェクトが来ても応答全体は失敗させない
187    fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
188        while seq.next_element::<IgnoredAny>()?.is_some() {}
189        Ok(None)
190    }
191    fn visit_map<A: de::MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
192        while map.next_entry::<IgnoredAny, IgnoredAny>()?.is_some() {}
193        Ok(None)
194    }
195}
196
197// 期待した形でない値を読み飛ばすための共通の受け口
198macro_rules! skip_other_values {
199    ($empty:expr) => {
200        fn visit_str<E: de::Error>(self, _: &str) -> Result<Self::Value, E> {
201            Ok($empty)
202        }
203        fn visit_i64<E: de::Error>(self, _: i64) -> Result<Self::Value, E> {
204            Ok($empty)
205        }
206        fn visit_u64<E: de::Error>(self, _: u64) -> Result<Self::Value, E> {
207            Ok($empty)
208        }
209        fn visit_f64<E: de::Error>(self, _: f64) -> Result<Self::Value, E> {
210            Ok($empty)
211        }
212        fn visit_bool<E: de::Error>(self, _: bool) -> Result<Self::Value, E> {
213            Ok($empty)
214        }
215        fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
216            Ok($empty)
217        }
218    };
219}
220
221struct VecVisitor<T>(PhantomData<T>);
222
223impl<'de, T: Deserialize<'de>> Visitor<'de> for VecVisitor<T> {
224    type Value = Vec<T>;
225
226    fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227        f.write_str("an array")
228    }
229    fn visit_seq<A: de::SeqAccess<'de>>(self, seq: A) -> Result<Self::Value, A::Error> {
230        Vec::deserialize(de::value::SeqAccessDeserializer::new(seq))
231    }
232    fn visit_map<A: de::MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
233        while map.next_entry::<IgnoredAny, IgnoredAny>()?.is_some() {}
234        Ok(Vec::new())
235    }
236    skip_other_values!(Vec::new());
237}
238
239struct ObjectVisitor<T>(PhantomData<T>);
240
241impl<'de, T: Deserialize<'de>> Visitor<'de> for ObjectVisitor<T> {
242    type Value = Option<T>;
243
244    fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245        f.write_str("an object")
246    }
247    fn visit_map<A: de::MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
248        T::deserialize(de::value::MapAccessDeserializer::new(map)).map(Some)
249    }
250    fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
251        while seq.next_element::<IgnoredAny>()?.is_some() {}
252        Ok(None)
253    }
254    skip_other_values!(None);
255}
256
257#[cfg(test)]
258mod tests {
259    use super::*;
260    use serde_json::json;
261
262    #[derive(Debug, Deserialize, PartialEq)]
263    struct Row {
264        #[serde(default, deserialize_with = "opt_string")]
265        s: Option<String>,
266        #[serde(default, deserialize_with = "opt_i64")]
267        i: Option<i64>,
268        #[serde(default, deserialize_with = "opt_f64")]
269        f: Option<f64>,
270        #[serde(default, deserialize_with = "opt_bool")]
271        b: Option<bool>,
272        #[serde(default, deserialize_with = "vec")]
273        v: Vec<u8>,
274    }
275
276    fn row(v: serde_json::Value) -> Row {
277        serde_json::from_value(v).unwrap()
278    }
279
280    #[test]
281    fn strings_accept_scalars() {
282        assert_eq!(row(json!({"s": "x"})).s.as_deref(), Some("x"));
283        assert_eq!(row(json!({"s": -1})).s.as_deref(), Some("-1"));
284        assert_eq!(row(json!({"s": 1})).s.as_deref(), Some("1"));
285        assert_eq!(row(json!({"s": 1.5})).s.as_deref(), Some("1.5"));
286        assert_eq!(row(json!({"s": true})).s.as_deref(), Some("true"));
287        assert_eq!(row(json!({"s": null})).s, None);
288        assert_eq!(row(json!({})).s, None);
289    }
290
291    #[test]
292    fn integers_accept_strings_and_floats() {
293        assert_eq!(row(json!({"i": 5})).i, Some(5));
294        assert_eq!(row(json!({"i": -5})).i, Some(-5));
295        assert_eq!(row(json!({"i": "1616127454"})).i, Some(1616127454));
296        assert_eq!(row(json!({"i": "1.9"})).i, Some(1));
297        assert_eq!(row(json!({"i": "x"})).i, None);
298        assert_eq!(row(json!({"i": 2.7})).i, Some(2));
299        assert_eq!(row(json!({"i": u64::MAX})).i, None);
300        assert_eq!(row(json!({"i": true})).i, Some(1));
301    }
302
303    #[test]
304    fn floats_accept_strings_and_integers() {
305        assert_eq!(row(json!({"f": 0.5})).f, Some(0.5));
306        assert_eq!(row(json!({"f": "0.25"})).f, Some(0.25));
307        assert_eq!(row(json!({"f": -2})).f, Some(-2.0));
308        assert_eq!(row(json!({"f": 3})).f, Some(3.0));
309        assert_eq!(row(json!({"f": true})).f, Some(1.0));
310        assert_eq!(row(json!({"f": false})).f, Some(0.0));
311    }
312
313    #[test]
314    fn booleans_accept_numbers_and_strings() {
315        assert_eq!(row(json!({"b": true})).b, Some(true));
316        assert_eq!(row(json!({"b": "true"})).b, Some(true));
317        assert_eq!(row(json!({"b": "1"})).b, Some(true));
318        assert_eq!(row(json!({"b": "false"})).b, Some(false));
319        assert_eq!(row(json!({"b": "0"})).b, Some(false));
320        assert_eq!(row(json!({"b": ""})).b, Some(false));
321        assert_eq!(row(json!({"b": "maybe"})).b, None);
322        assert_eq!(row(json!({"b": 0})).b, Some(false));
323        assert_eq!(row(json!({"b": -1})).b, Some(true));
324        assert_eq!(row(json!({"b": 0.0})).b, Some(false));
325    }
326
327    #[test]
328    fn structured_values_in_scalar_fields_are_dropped() {
329        let r = row(json!({"s": [1, 2], "i": {"a": 1}, "v": [1]}));
330        assert_eq!(r.s, None);
331        assert_eq!(r.i, None);
332        assert_eq!(r.v, vec![1]);
333    }
334
335    #[test]
336    fn non_array_vec_becomes_empty() {
337        for v in [
338            json!(null),
339            json!("x"),
340            json!(-1),
341            json!(1),
342            json!(1.5),
343            json!(true),
344            json!({"a": 1}),
345        ] {
346            assert!(row(json!({ "v": v })).v.is_empty());
347        }
348    }
349
350    #[derive(Debug, Deserialize, PartialEq)]
351    struct Inner {
352        a: u8,
353    }
354
355    #[derive(Debug, Deserialize, PartialEq)]
356    struct Outer {
357        #[serde(default, deserialize_with = "opt_object")]
358        o: Option<Inner>,
359    }
360
361    #[test]
362    fn objects_accept_only_maps() {
363        let o = |v: serde_json::Value| {
364            serde_json::from_value::<Outer>(json!({ "o": v }))
365                .unwrap()
366                .o
367        };
368        assert_eq!(o(json!({"a": 1})), Some(Inner { a: 1 }));
369        for v in [
370            json!(null),
371            json!(""),
372            json!(-1),
373            json!(1),
374            json!(1.5),
375            json!(false),
376            json!([1, 2]),
377        ] {
378            assert_eq!(o(v), None);
379        }
380        assert!(serde_json::from_value::<Outer>(json!({"o": {"a": "x"}})).is_err());
381    }
382
383    #[test]
384    fn expecting_message_names_the_type() {
385        // deserialize_any を使わない形式(bincode 等)では expecting が使われる。文言だけ確かめる
386        struct Probe<T>(PhantomData<T>);
387        impl<T: Lenient> fmt::Display for Probe<T> {
388            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
389                OptVisitor::<T>(PhantomData).expecting(f)
390            }
391        }
392        assert_eq!(Probe::<String>(PhantomData).to_string(), "a string");
393        assert_eq!(Probe::<i64>(PhantomData).to_string(), "an integer");
394        assert_eq!(Probe::<f64>(PhantomData).to_string(), "a number");
395        assert_eq!(Probe::<bool>(PhantomData).to_string(), "a boolean");
396        struct Expect<V>(V);
397        impl<'de, V: Visitor<'de>> fmt::Display for Expect<V> {
398            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
399                self.0.expecting(f)
400            }
401        }
402        assert_eq!(
403            Expect(VecVisitor::<u8>(PhantomData)).to_string(),
404            "an array"
405        );
406        assert_eq!(
407            Expect(ObjectVisitor::<u8>(PhantomData)).to_string(),
408            "an object"
409        );
410    }
411
412    #[test]
413    fn bytes_and_char_inputs_are_rejected_with_type_message() {
414        // serde_json は bytes を出さないので、IntoDeserializer で確かめる
415        use serde::de::value::{BytesDeserializer, Error};
416        let err = opt_string(BytesDeserializer::<Error>::new(b"x")).unwrap_err();
417        assert!(err.to_string().contains("a string"));
418    }
419}