serde_trim/
lib.rs

1use std::collections::*;
2
3use serde::{de, Deserialize};
4pub use trim_in_place::*;
5
6pub fn string_trim<'de, D>(d: D) -> Result<String, D::Error>
7where
8    D: de::Deserializer<'de>,
9{
10    let mut de_string = String::deserialize(d)?;
11    de_string.trim_in_place();
12    Ok(de_string)
13}
14
15pub fn option_string_trim<'de, D>(d: D) -> Result<Option<String>, D::Error>
16where
17    D: de::Deserializer<'de>,
18{
19    let mut de_string: Option<String> = Option::deserialize(d)?;
20    if let Some(ref mut de_string) = de_string {
21        if de_string.trim_in_place().is_empty() {
22            return Ok(None);
23        }
24    }
25    Ok(de_string)
26}
27
28macro_rules! iter_trim {
29    ($fn_name:ident,$t:ty) => {
30        pub fn $fn_name<'de, D>(d: D) -> Result<$t, D::Error>
31        where
32            D: de::Deserializer<'de>,
33        {
34            collection_trim(d)
35        }
36    };
37}
38
39macro_rules! iter_non_empty_trim {
40    ($fn_name:ident,$t:ty) => {
41        pub fn $fn_name<'de, D>(d: D) -> Result<$t, D::Error>
42        where
43            D: de::Deserializer<'de>,
44        {
45            collection_non_empty_trim(d)
46        }
47    };
48}
49
50iter_trim!(btreeset_string_trim, BTreeSet<String>);
51iter_trim!(vec_string_trim, Vec<String>);
52iter_trim!(hashset_string_trim, HashSet<String>);
53iter_trim!(vecdeque_string_trim, VecDeque<String>);
54iter_trim!(linkedlist_string_trim, LinkedList<String>);
55iter_trim!(binaryheap_string_trim, BinaryHeap<String>);
56
57iter_non_empty_trim!(btreeset_non_empty_string_trim, BTreeSet<String>);
58iter_non_empty_trim!(vec_non_empty_string_trim, Vec<String>);
59iter_non_empty_trim!(hashset_non_empty_string_trim, HashSet<String>);
60iter_non_empty_trim!(vecdeque_non_empty_string_trim, VecDeque<String>);
61iter_non_empty_trim!(linkedlist_non_empty_string_trim, LinkedList<String>);
62iter_non_empty_trim!(binaryheap_non_empty_string_trim, BinaryHeap<String>);
63
64fn collection_trim<'de, C, D, S>(d: D) -> Result<C, D::Error>
65where
66    S: TrimInPlace,
67    C: Deserialize<'de> + IntoIterator<Item = S> + FromIterator<String>,
68    D: de::Deserializer<'de>,
69{
70    let de_string: C = C::deserialize(d)?
71        .into_iter()
72        .map(|mut x| x.trim_in_place().to_string())
73        .collect();
74    Ok(de_string)
75}
76
77fn collection_non_empty_trim<'de, C, D, S>(d: D) -> Result<C, D::Error>
78where
79    S: TrimInPlace,
80    C: Deserialize<'de> + IntoIterator<Item = S> + FromIterator<String>,
81    D: de::Deserializer<'de>,
82{
83    let de_string: C = C::deserialize(d)?
84        .into_iter()
85        .filter_map(|mut x| {
86            let x = x.trim_in_place().to_string();
87            if x.is_empty() {
88                None
89            } else {
90                Some(x)
91            }
92        })
93        .collect();
94    Ok(de_string)
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn test_string_trim() {
103        #[derive(Deserialize)]
104        struct Foo {
105            #[serde(deserialize_with = "string_trim")]
106            name: String,
107        }
108        let json = r#"{"name":" "}"#;
109        let foo = serde_json::from_str::<Foo>(json).unwrap();
110        assert_eq!(foo.name, "");
111    }
112
113    #[test]
114    fn test_option_string_trim() {
115        #[derive(Deserialize)]
116        struct OptionFoo {
117            #[serde(deserialize_with = "option_string_trim")]
118            name: Option<String>,
119        }
120        let json = r#"{"name":" "}"#;
121        let foo = serde_json::from_str::<OptionFoo>(json).unwrap();
122        assert_eq!(foo.name, None);
123
124        #[derive(Deserialize)]
125        struct OptionBar {
126            #[serde(default, deserialize_with = "option_string_trim")]
127            name: Option<String>,
128            addr: String,
129        }
130        let json = r#"{"addr":"ABC"}"#;
131        let foo = serde_json::from_str::<OptionBar>(json).unwrap();
132        assert_eq!(foo.name, None);
133        assert_eq!(foo.addr, "ABC");
134    }
135
136    #[test]
137    fn test_vec_string_trim() {
138        #[derive(Deserialize)]
139        struct VecFoo {
140            #[serde(deserialize_with = "vec_string_trim")]
141            name: Vec<String>,
142        }
143        let json = r#"{"name":["   ","foo","b ar","hello ","  rust"]}"#;
144        let foo = serde_json::from_str::<VecFoo>(json).unwrap();
145        assert_eq!(foo.name, vec!["", "foo", "b ar", "hello", "rust"]);
146    }
147
148    #[test]
149    fn test_btreeset_string_trim() {
150        #[derive(Deserialize)]
151        struct BTreeSetFoo {
152            #[serde(deserialize_with = "btreeset_string_trim")]
153            name: BTreeSet<String>,
154        }
155        let json = r#"{"name":["   ","foo","b ar","hello ","  rust"]}"#;
156        let foo = serde_json::from_str::<BTreeSetFoo>(json).unwrap();
157        let expected: BTreeSet<String> = BTreeSet::from_iter([
158            "".into(),
159            "foo".into(),
160            "b ar".into(),
161            "hello".into(),
162            "rust".into(),
163        ]);
164        assert_eq!(foo.name, expected);
165    }
166
167    #[test]
168    fn test_hashset_string_trim() {
169        #[derive(Deserialize)]
170        struct HashSetFoo {
171            #[serde(deserialize_with = "hashset_string_trim")]
172            name: HashSet<String>,
173        }
174        let json = r#"{"name":["   ","foo","b ar","hello ","  rust","  rust"]}"#;
175        let foo = serde_json::from_str::<HashSetFoo>(json).unwrap();
176        let expected: HashSet<String> = HashSet::from_iter([
177            "".into(),
178            "foo".into(),
179            "b ar".into(),
180            "hello".into(),
181            "rust".into(),
182        ]);
183        assert_eq!(foo.name, expected);
184    }
185
186    #[test]
187    fn test_vecdeque_string_trim() {
188        #[derive(Deserialize)]
189        struct VecDequeFoo {
190            #[serde(deserialize_with = "vecdeque_string_trim")]
191            name: VecDeque<String>,
192        }
193        let json = r#"{"name":["   ","foo","b ar","hello ","  rust"]}"#;
194        let foo = serde_json::from_str::<VecDequeFoo>(json).unwrap();
195        assert_eq!(foo.name, vec!["", "foo", "b ar", "hello", "rust"]);
196    }
197
198    #[test]
199    fn test_linkedlist_string_trim() {
200        #[derive(Deserialize)]
201        struct LinkedListFoo {
202            #[serde(deserialize_with = "linkedlist_string_trim")]
203            name: LinkedList<String>,
204        }
205        let json = r#"{"name":["   ","foo","b ar","hello ","  rust"]}"#;
206        let foo = serde_json::from_str::<LinkedListFoo>(json).unwrap();
207        assert_eq!(
208            foo.name,
209            LinkedList::from_iter([
210                "".into(),
211                "foo".into(),
212                "b ar".into(),
213                "hello".into(),
214                "rust".into(),
215            ])
216        );
217    }
218
219    #[test]
220    fn test_binaryheap_string_trim() {
221        #[derive(Deserialize)]
222        struct BinaryHeapFoo {
223            #[serde(deserialize_with = "binaryheap_string_trim")]
224            name: BinaryHeap<String>,
225        }
226        let json = r#"{"name":["   ","foo","b ar","hello ","  rust"]}"#;
227        let foo = serde_json::from_str::<BinaryHeapFoo>(json).unwrap();
228        assert_eq!(
229            foo.name.into_vec(),
230            vec!["rust", "hello", "b ar", "", "foo"]
231        );
232    }
233
234    #[test]
235    fn test_vec_non_empty_string_trim() {
236        #[derive(Deserialize)]
237        struct VecFoo {
238            #[serde(deserialize_with = "vec_non_empty_string_trim")]
239            name: Vec<String>,
240        }
241        let json = r#"{"name":["   ","foo","b ar","hello ","  rust"]}"#;
242        let foo = serde_json::from_str::<VecFoo>(json).unwrap();
243        assert_eq!(foo.name, vec!["foo", "b ar", "hello", "rust"]);
244    }
245
246    #[test]
247    fn test_btreeset_non_empty_string_trim() {
248        #[derive(Deserialize)]
249        struct BTreeSetFoo {
250            #[serde(deserialize_with = "btreeset_non_empty_string_trim")]
251            name: BTreeSet<String>,
252        }
253        let json = r#"{"name":["   ","foo","b ar","hello ","  rust"]}"#;
254        let foo = serde_json::from_str::<BTreeSetFoo>(json).unwrap();
255        let expected: BTreeSet<String> =
256            BTreeSet::from_iter(["foo".into(), "b ar".into(), "hello".into(), "rust".into()]);
257        assert_eq!(foo.name, expected);
258    }
259
260    #[test]
261    fn test_hashset_non_empty_string_trim() {
262        #[derive(Deserialize)]
263        struct HashSetFoo {
264            #[serde(deserialize_with = "hashset_non_empty_string_trim")]
265            name: HashSet<String>,
266        }
267        let json = r#"{"name":["   ","foo","b ar","hello ","  rust","  rust"]}"#;
268        let foo = serde_json::from_str::<HashSetFoo>(json).unwrap();
269        let expected: HashSet<String> =
270            HashSet::from_iter(["foo".into(), "b ar".into(), "hello".into(), "rust".into()]);
271        assert_eq!(foo.name, expected);
272    }
273
274    #[test]
275    fn test_vecdeque_non_empty_string_trim() {
276        #[derive(Deserialize)]
277        struct VecDequeFoo {
278            #[serde(deserialize_with = "vecdeque_non_empty_string_trim")]
279            name: VecDeque<String>,
280        }
281        let json = r#"{"name":["   ","foo","b ar","hello ","  rust"]}"#;
282        let foo = serde_json::from_str::<VecDequeFoo>(json).unwrap();
283        assert_eq!(foo.name, vec!["foo", "b ar", "hello", "rust"]);
284    }
285
286    #[test]
287    fn test_linkedlist_non_empty_string_trim() {
288        #[derive(Deserialize)]
289        struct LinkedListFoo {
290            #[serde(deserialize_with = "linkedlist_non_empty_string_trim")]
291            name: LinkedList<String>,
292        }
293        let json = r#"{"name":["   ","foo","b ar","hello ","  rust"]}"#;
294        let foo = serde_json::from_str::<LinkedListFoo>(json).unwrap();
295        assert_eq!(
296            foo.name,
297            LinkedList::from_iter(["foo".into(), "b ar".into(), "hello".into(), "rust".into(),])
298        );
299    }
300
301    #[test]
302    fn test_binaryheap_non_empty_string_trim() {
303        #[derive(Deserialize)]
304        struct BinaryHeapFoo {
305            #[serde(deserialize_with = "binaryheap_non_empty_string_trim")]
306            name: BinaryHeap<String>,
307        }
308        let json = r#"{"name":["   ","foo","b ar","hello ","  rust"]}"#;
309        let foo = serde_json::from_str::<BinaryHeapFoo>(json).unwrap();
310        assert_eq!(foo.name.into_vec(), vec!["rust", "hello", "b ar", "foo"]);
311    }
312}