serde_flexible/deserialize/
as_bool.rs1use 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}