serde_flexible/deserialize/
as_bool.rs

1use serde::de::{Deserializer, Error, Expected, Unexpected, Visitor};
2use std::fmt;
3
4const EXPECTED: &str = "an integer (0 or 1) or a case insensitive string (true/false, yes/no, on/off, y/n, t/f, 1/0, ok)";
5
6pub fn as_bool<'de, D: Deserializer<'de>>(deserializer: D) -> Result<bool, D::Error> {
7    deserializer.deserialize_any(AsBool)
8}
9
10struct AsBool;
11
12impl<'de> Visitor<'de> for AsBool {
13    type Value = bool;
14
15    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str(EXPECTED) }
16    fn visit_bool<E: Error>(self, v: bool) -> Result<Self::Value, E> { Ok(v) }
17    fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> { parse_i64(v, &EXPECTED) }
18    fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> { parse_u64(v, &EXPECTED) }
19    fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> { parse_str(v, &EXPECTED) }
20}
21
22pub(super) fn parse_i64<E: Error>(v: i64, exp: &dyn Expected) -> Result<bool, E> {
23    match v {
24        0 => Ok(false),
25        1 => Ok(true),
26        _ => Err(Error::invalid_value(Unexpected::Signed(v), exp)),
27    }
28}
29
30pub(super) fn parse_u64<E: Error>(v: u64, exp: &dyn Expected) -> Result<bool, E> {
31    match v {
32        0 => Ok(false),
33        1 => Ok(true),
34        _ => Err(Error::invalid_value(Unexpected::Unsigned(v), exp)),
35    }
36}
37
38pub(super) fn parse_str<E: Error>(v: &str, exp: &dyn Expected) -> Result<bool, E> {
39    match v {
40        "1" | "true" | "True" => Ok(true),
41        "0" | "false" | "False" => Ok(false),
42        _ => {
43            match v.to_lowercase().as_str() {
44                "true" | "yes" | "on" | "y" | "t" | "ok" => Ok(true),
45                "false" | "no" | "off" | "n" | "f" => Ok(false),
46                _ => Err(Error::invalid_value(Unexpected::Str(v), exp)),
47            }
48        }
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55    use serde::Deserialize;
56
57    #[derive(Debug, Deserialize, PartialEq)]
58    struct Test {
59        #[serde(deserialize_with = "as_bool")]
60        bool: bool,
61    }
62
63    #[test]
64    fn test_base_good_parse() {
65        assert!(serde_json::from_str::<Test>(r#"{"bool": true     }"#).unwrap().bool);
66        assert!(serde_json::from_str::<Test>(r#"{"bool": 1        }"#).unwrap().bool);
67        assert!(serde_json::from_str::<Test>(r#"{"bool": "1"      }"#).unwrap().bool);
68        assert!(serde_json::from_str::<Test>(r#"{"bool": "true"   }"#).unwrap().bool);
69        assert!(serde_json::from_str::<Test>(r#"{"bool": "True"   }"#).unwrap().bool);
70        assert!(serde_json::from_str::<Test>(r#"{"bool": "TRue"   }"#).unwrap().bool);
71        assert!(serde_json::from_str::<Test>(r#"{"bool": "TRUE"   }"#).unwrap().bool);
72        assert!(serde_json::from_str::<Test>(r#"{"bool": "yes"    }"#).unwrap().bool);
73        assert!(serde_json::from_str::<Test>(r#"{"bool": "Yes"    }"#).unwrap().bool);
74        assert!(serde_json::from_str::<Test>(r#"{"bool": "YeS"    }"#).unwrap().bool);
75        assert!(serde_json::from_str::<Test>(r#"{"bool": "on"     }"#).unwrap().bool);
76        assert!(serde_json::from_str::<Test>(r#"{"bool": "On"     }"#).unwrap().bool);
77        assert!(serde_json::from_str::<Test>(r#"{"bool": "ON"     }"#).unwrap().bool);
78        assert!(serde_json::from_str::<Test>(r#"{"bool": "oN"     }"#).unwrap().bool);
79        assert!(serde_json::from_str::<Test>(r#"{"bool": "y"      }"#).unwrap().bool);
80        assert!(serde_json::from_str::<Test>(r#"{"bool": "Y"      }"#).unwrap().bool);
81        assert!(serde_json::from_str::<Test>(r#"{"bool": "t"      }"#).unwrap().bool);
82        assert!(serde_json::from_str::<Test>(r#"{"bool": "T"      }"#).unwrap().bool);
83        assert!(serde_json::from_str::<Test>(r#"{"bool": "ok"     }"#).unwrap().bool);
84        assert!(serde_json::from_str::<Test>(r#"{"bool": "Ok"     }"#).unwrap().bool);
85        assert!(serde_json::from_str::<Test>(r#"{"bool": "OK"     }"#).unwrap().bool);
86        assert!(serde_json::from_str::<Test>(r#"{"bool": "oK"     }"#).unwrap().bool);
87
88        assert!(!serde_json::from_str::<Test>(r#"{"bool": false   }"#).unwrap().bool);
89        assert!(!serde_json::from_str::<Test>(r#"{"bool": 0       }"#).unwrap().bool);
90        assert!(!serde_json::from_str::<Test>(r#"{"bool": "0"     }"#).unwrap().bool);
91        assert!(!serde_json::from_str::<Test>(r#"{"bool": "false" }"#).unwrap().bool);
92        assert!(!serde_json::from_str::<Test>(r#"{"bool": "False" }"#).unwrap().bool);
93        assert!(!serde_json::from_str::<Test>(r#"{"bool": "FalsE" }"#).unwrap().bool);
94        assert!(!serde_json::from_str::<Test>(r#"{"bool": "FALSE" }"#).unwrap().bool);
95        assert!(!serde_json::from_str::<Test>(r#"{"bool": "no"    }"#).unwrap().bool);
96        assert!(!serde_json::from_str::<Test>(r#"{"bool": "NO"    }"#).unwrap().bool);
97        assert!(!serde_json::from_str::<Test>(r#"{"bool": "nO"    }"#).unwrap().bool);
98        assert!(!serde_json::from_str::<Test>(r#"{"bool": "No"    }"#).unwrap().bool);
99        assert!(!serde_json::from_str::<Test>(r#"{"bool": "off"   }"#).unwrap().bool);
100        assert!(!serde_json::from_str::<Test>(r#"{"bool": "Off"   }"#).unwrap().bool);
101        assert!(!serde_json::from_str::<Test>(r#"{"bool": "OfF"   }"#).unwrap().bool);
102        assert!(!serde_json::from_str::<Test>(r#"{"bool": "n"     }"#).unwrap().bool);
103        assert!(!serde_json::from_str::<Test>(r#"{"bool": "N"     }"#).unwrap().bool);
104        assert!(!serde_json::from_str::<Test>(r#"{"bool": "f"     }"#).unwrap().bool);
105        assert!(!serde_json::from_str::<Test>(r#"{"bool": "F"     }"#).unwrap().bool);
106    }
107
108    #[test]
109    fn test_parse_error() {
110        assert!(serde_json::from_str::<Test>(r#"{"bool": null          }"#).is_err());
111        assert!(serde_json::from_str::<Test>(r#"{"bool": 2             }"#).is_err());
112        assert!(serde_json::from_str::<Test>(r#"{"bool": -1            }"#).is_err());
113        assert!(serde_json::from_str::<Test>(r#"{"bool": 1.0           }"#).is_err());
114        assert!(serde_json::from_str::<Test>(r#"{"bool": 0.0           }"#).is_err());
115        assert!(serde_json::from_str::<Test>(r#"{"bool": 3.14          }"#).is_err());
116        assert!(serde_json::from_str::<Test>(r#"{"bool": "false 100%"  }"#).is_err());
117    }
118
119    #[test]
120    fn test_parse_error_message() {
121        assert!(serde_json::from_str::<Test>(r#"{"bool": null}"#).unwrap_err().to_string().contains(EXPECTED));
122        assert!(serde_json::from_str::<Test>(r#"{"bool": ["first", "second"]}"#).unwrap_err().to_string().contains(EXPECTED));
123        assert!(serde_json::from_str::<Test>(r#"{"bool": -100}"#).unwrap_err().to_string().contains(EXPECTED));
124        assert!(serde_json::from_str::<Test>(r#"{"bool": "unknown"}"#).unwrap_err().to_string().contains(EXPECTED));
125    }
126}