serde_flexible/deserialize/
as_string_opt.rs

1use serde::de::{Deserializer, Error, Visitor};
2use std::fmt;
3
4const EXPECTED: &str = "null, a string, bool, or a number";
5
6pub fn as_string_opt<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Option<String>, D::Error> {
7    deserializer.deserialize_any(AsOptString)
8}
9
10struct AsOptString;
11
12impl<'de> Visitor<'de> for AsOptString {
13    type Value = Option<String>;
14
15    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
16        formatter.write_str(EXPECTED)
17    }
18
19    fn visit_bool<E: Error>(self, v: bool) -> Result<Self::Value, E> {
20        Ok(Some(v.to_string()))
21    }
22    fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> {
23        Ok(Some(v.to_string()))
24    }
25    fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
26        Ok(Some(v.to_string()))
27    }
28    fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
29        Ok(Some(v.to_string()))
30    }
31    fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
32        Ok(Some(v.to_owned()))
33    }
34    fn visit_unit<E: Error>(self) -> Result<Self::Value, E> {
35        Ok(None)
36    }
37}
38
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43    use serde::Deserialize;
44
45    #[derive(Debug, Deserialize, PartialEq)]
46    struct Test {
47        #[serde(deserialize_with = "as_string_opt")]
48        str: Option<String>,
49    }
50
51    #[test]
52    fn test_base_good_parse() {
53        // important: str no use fn str_wrap_as_opt() and will not parse to none for strings like "null", "none", "unknown" ...
54        assert_eq!(serde_json::from_str::<Test>(r#"{"str": "null"      }"#).unwrap().str.unwrap(), "null");
55        assert_eq!(serde_json::from_str::<Test>(r#"{"str": "none"      }"#).unwrap().str.unwrap(), "none");
56        assert_eq!(serde_json::from_str::<Test>(r#"{"str": "unknown"   }"#).unwrap().str.unwrap(), "unknown");
57        assert_eq!(serde_json::from_str::<Test>(r#"{"str": "Unknown"   }"#).unwrap().str.unwrap(), "Unknown");
58        assert_eq!(serde_json::from_str::<Test>(r#"{"str": "NONE"      }"#).unwrap().str.unwrap(), "NONE");
59        assert!(serde_json::from_str::<Test>(r#"{"str": null         }"#).unwrap().str.is_none());
60
61        assert_eq!(serde_json::from_str::<Test>(r#"{"str": "Foo Boo" }"#).unwrap().str.unwrap(), "Foo Boo");
62        assert_eq!(serde_json::from_str::<Test>(r#"{"str": "hello"   }"#).unwrap().str.unwrap(), "hello");
63        assert_eq!(serde_json::from_str::<Test>(r#"{"str": 100       }"#).unwrap().str.unwrap(), "100");
64        assert_eq!(serde_json::from_str::<Test>(r#"{"str": true      }"#).unwrap().str.unwrap(), "true");
65        assert_eq!(serde_json::from_str::<Test>(r#"{"str": false     }"#).unwrap().str.unwrap(), "false");
66        assert_eq!(serde_json::from_str::<Test>(r#"{"str": 12345     }"#).unwrap().str.unwrap(), "12345");
67        assert_eq!(serde_json::from_str::<Test>(r#"{"str": -12345    }"#).unwrap().str.unwrap(), "-12345");
68        assert_eq!(serde_json::from_str::<Test>(r#"{"str": -0        }"#).unwrap().str.unwrap(), "-0");
69        assert_eq!(serde_json::from_str::<Test>(r#"{"str": 0         }"#).unwrap().str.unwrap(), "0");
70        assert_eq!(serde_json::from_str::<Test>(r#"{"str": 3.14      }"#).unwrap().str.unwrap(), "3.14");
71
72        assert!(serde_json::from_str::<Test>(r#"{"str": null         }"#).unwrap().str.is_none());
73    }
74
75    #[test]
76    fn test_base_error() {
77        assert!(serde_json::from_str::<Test>(r#"{"str": ["hello"]]   }"#).is_err());
78    }
79}