deserialize_custom_strings/
lib.rs

1use serde::de::Error;
2use serde::Deserialize;
3
4use regex::Regex;
5
6/// In case you encounter a JSON API that does not return the `u64`
7/// as a number like you handsome and smart person deserve, but
8/// instead wraps it in a `String`, like:
9/// ```rust
10/// use serde::Deserialize;
11/// use serde_json::{Error, from_str};
12///
13/// #[derive(Deserialize)]
14/// struct Foo {
15///  definetly_a_u64: u64,
16/// }
17///
18/// let json = r#"{
19///   "definetly_a_u64": "0123456789"
20/// }"#;
21///
22/// let foo: Result<Foo, Error> = from_str(json);
23///
24/// assert!(foo.is_err());
25/// ```
26///
27/// Make the above code working with:
28/// ```rust
29/// use serde::Deserialize;
30/// use serde_json::{Error, from_str};
31///
32/// use deserialize_custom_strings::deserialize_u64;
33///
34/// #[derive(Deserialize)]
35/// struct Foo {
36///  #[serde(deserialize_with = "deserialize_u64")]
37///  definetly_a_u64: u64,
38/// }
39///
40/// let json = r#"{
41///   "definetly_a_u64": "0123456789"
42/// }"#;
43///
44/// let foo: Result<Foo, Error> = from_str(json);
45///
46/// assert!(foo.is_ok());
47/// assert_eq!(foo.unwrap().definetly_a_u64, 123456789);
48/// ```
49pub fn deserialize_u64<'de, D>(
50  deserializer: D,
51) -> Result<u64, D::Error>
52where
53  D: serde::de::Deserializer<'de>,
54{
55  let s = String::deserialize(deserializer)?;
56  s.parse().map_err(Error::custom)
57}
58
59/// See [deserialize_u64].
60///
61/// Example:
62/// ```rust
63/// use serde::Deserialize;
64/// use serde_json::{Error, from_str};
65///
66/// use deserialize_custom_strings::deserialize_option_u64;
67///
68/// #[derive(Deserialize)]
69/// struct Foo {
70///   #[serde(deserialize_with = "deserialize_option_u64")]
71///   definetly_a_option_u64: Option<u64>,
72/// }
73///
74/// let json = r#"{
75///   "definetly_a_option_u64": "0123456789"
76/// }"#;
77///
78/// let foo: Result<Foo, Error> = from_str(json);
79///
80/// assert!(foo.is_ok());
81/// assert_eq!(foo.unwrap().definetly_a_option_u64, Some(123456789));
82///
83/// let json = r#"{
84///   "definetly_a_option_u64": null
85/// }"#;
86///
87/// let foo: Result<Foo, Error> = from_str(json);
88///
89/// assert!(foo.is_ok());
90/// assert_eq!(foo.unwrap().definetly_a_option_u64, None);
91///
92/// let json = r#"{
93///   "definetly_a_option_u64": -123456789
94/// }"#;
95///
96/// let foo: Result<Foo, Error> = from_str(json);
97///
98/// assert!(foo.is_err());
99/// ```
100///
101pub fn deserialize_option_u64<'de, D>(
102  deserializer: D,
103) -> Result<Option<u64>, D::Error>
104where
105  D: serde::de::Deserializer<'de>,
106{
107  let o: Option<String> = Option::deserialize(deserializer)?;
108
109  Ok(match o {
110    Some(s) => Some(s.parse().map_err(Error::custom)?),
111    None => None,
112  })
113}
114
115pub fn deserialize_phone_number<'de, D>(
116  deserializer: D,
117) -> Result<String, D::Error>
118where
119  D: serde::de::Deserializer<'de>,
120{
121  let r = Regex::new(r"(?P<x>(^\+)|([0-9]))[^0-9]+")
122    .map_err(Error::custom)?;
123
124  let s = String::deserialize(deserializer)?;
125
126  Ok((*r.replace_all(&s, "$x")).to_owned())
127}
128
129pub fn deserialize_email<'de, D>(
130  deserializer: D,
131) -> Result<String, D::Error>
132where
133  D: serde::de::Deserializer<'de>,
134{
135  let s = String::deserialize(deserializer)?;
136  Ok(s.to_lowercase())
137}
138
139pub fn deserialize_urlencoded<'de, D>(
140  deserializer: D,
141) -> Result<String, D::Error>
142where
143  D: serde::de::Deserializer<'de>,
144{
145  let s = String::deserialize(deserializer)?;
146
147  let mut res = String::new();
148  let mut iter = s.chars();
149
150  while let Some(c) = iter.next() {
151    if c == '%' {
152      let left = iter.next();
153      let right = iter.next();
154      match (left, right) {
155        (Some(l), Some(r)) => {
156          let byte = u8::from_str_radix(&format!("{}{}", l, r), 16)
157            .map_err(Error::custom)?;
158          res += &(byte as char).to_string();
159        }
160        _ => return Err("index error").map_err(Error::custom),
161      }
162    } else {
163      res += &c.to_string();
164    }
165  }
166
167  Ok(res)
168}