diff --git a/Cargo.toml b/Cargo.toml index 016b200..eb6c26c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "serde_trim" version = "0.4.0" authors = ["baoyachi "] edition = "2021" -description = "serde deserialize_with String trim" +description = "serde deserialize_with String trim.Supports multiple std::collections types" keywords = ["serde", "serde_trim", "deserialize_trim", "deserialize_with", "serde_json"] readme = "README.md" categories = ["encoding"] diff --git a/README.md b/README.md index 8da17aa..8112ae0 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,24 @@ ## Support trim * `String` +* `Option` * `Vec` * `BTreeSet` -* `Option` +* `HashSet` +* `VecDeque` +* `LinkedList` +* `BinaryHeap` + +Supports multiple [std::collections](https://doc.rust-lang.org/stable/std/collections/) types + ## how to use ```rust +use serde_derive::Deserialize; +use serde_trim::*; +use std::collections::*; + fn main() { #[derive(Deserialize)] struct Foo { @@ -72,5 +83,61 @@ fn main() { "rust".into(), ]); assert_eq!(foo.name, expected); + + #[derive(Deserialize)] + struct HashSetFoo { + #[serde(deserialize_with = "hashset_string_trim")] + name: HashSet, + } + let json = r#"{"name":[" ","foo","b ar","hello "," rust"]}"#; + let foo = serde_json::from_str::(json).unwrap(); + let expected: HashSet = HashSet::from_iter([ + "".into(), + "foo".into(), + "b ar".into(), + "hello".into(), + "rust".into(), + ]); + assert_eq!(foo.name, expected); + + #[derive(Deserialize)] + struct VecDequeFoo { + #[serde(deserialize_with = "vecdeque_string_trim")] + name: VecDeque, + } + let json = r#"{"name":[" ","foo","b ar","hello "," rust"]}"#; + let foo = serde_json::from_str::(json).unwrap(); + assert_eq!(foo.name, vec!["", "foo", "b ar", "hello", "rust"]); + + #[derive(Deserialize)] + struct LinkedListFoo { + #[serde(deserialize_with = "linkedlist_string_trim")] + name: LinkedList, + } + let json = r#"{"name":[" ","foo","b ar","hello "," rust"]}"#; + let foo = serde_json::from_str::(json).unwrap(); + assert_eq!( + foo.name, + LinkedList::from_iter([ + "".into(), + "foo".into(), + "b ar".into(), + "hello".into(), + "rust".into(), + ]) + ); + + #[derive(Deserialize)] + struct BinaryHeapFoo { + #[serde(deserialize_with = "binaryheap_string_trim")] + name: BinaryHeap, + } + let json = r#"{"name":[" ","foo","b ar","hello "," rust"]}"#; + let foo = serde_json::from_str::(json).unwrap(); + assert_eq!( + foo.name.into_vec(), + vec!["rust", "hello", "b ar", "", "foo"] + ); } + ``` diff --git a/lib.rs b/lib.rs index aa972b6..973d653 100644 --- a/lib.rs +++ b/lib.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeSet; +use std::collections::*; use serde::{de, Deserialize}; pub use trim_in_place::*; @@ -12,17 +12,6 @@ where Ok(de_string) } -pub fn vec_string_trim<'de, D>(d: D) -> Result, D::Error> -where - D: de::Deserializer<'de>, -{ - let de_string: Vec = Vec::::deserialize(d)? - .into_iter() - .map(|mut x| x.trim_in_place().to_string()) - .collect(); - Ok(de_string) -} - pub fn option_string_trim<'de, D>(d: D) -> Result, D::Error> where D: de::Deserializer<'de>, @@ -36,79 +25,171 @@ where Ok(de_string) } -pub fn btreeset_string_trim<'de, D>(d: D) -> Result, D::Error> +macro_rules! iter_trim { + ($fn_name:ident,$t:ty) => { + pub fn $fn_name<'de, D>(d: D) -> Result<$t, D::Error> + where + D: de::Deserializer<'de>, + { + collection_trim(d) + } + }; +} + +iter_trim!(btreeset_string_trim, BTreeSet); +iter_trim!(vec_string_trim, Vec); +iter_trim!(hashset_string_trim, HashSet); +iter_trim!(vecdeque_string_trim, VecDeque); +iter_trim!(linkedlist_string_trim, LinkedList); +iter_trim!(binaryheap_string_trim, BinaryHeap); + +fn collection_trim<'de, C, D, S>(d: D) -> Result where + S: TrimInPlace, + C: Deserialize<'de> + IntoIterator + FromIterator, D: de::Deserializer<'de>, { - let de_string: BTreeSet = BTreeSet::::deserialize(d)? + let de_string: C = C::deserialize(d)? .into_iter() .map(|mut x| x.trim_in_place().to_string()) .collect(); Ok(de_string) } -#[test] -fn test_vec_string_trim() { - #[derive(Deserialize)] - struct VecFoo { - #[serde(deserialize_with = "vec_string_trim")] - name: Vec, +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_string_trim() { + #[derive(Deserialize)] + struct Foo { + #[serde(deserialize_with = "string_trim")] + name: String, + } + let json = r#"{"name":" "}"#; + let foo = serde_json::from_str::(json).unwrap(); + assert_eq!(foo.name, ""); } - let json = r#"{"name":[" ","foo","b ar","hello "," rust"]}"#; - let foo = serde_json::from_str::(json).unwrap(); - assert_eq!(foo.name, vec!["", "foo", "b ar", "hello", "rust"]); -} -#[test] -fn test_string_trim() { - #[derive(Deserialize)] - struct Foo { - #[serde(deserialize_with = "string_trim")] - name: String, + #[test] + fn test_option_string_trim() { + #[derive(Deserialize)] + struct OptionFoo { + #[serde(deserialize_with = "option_string_trim")] + name: Option, + } + let json = r#"{"name":" "}"#; + let foo = serde_json::from_str::(json).unwrap(); + assert_eq!(foo.name, None); + + #[derive(Deserialize)] + struct OptionBar { + #[serde(default, deserialize_with = "option_string_trim")] + name: Option, + addr: String, + } + let json = r#"{"addr":"ABC"}"#; + let foo = serde_json::from_str::(json).unwrap(); + assert_eq!(foo.name, None); + assert_eq!(foo.addr, "ABC"); } - let json = r#"{"name":" "}"#; - let foo = serde_json::from_str::(json).unwrap(); - assert_eq!(foo.name, ""); -} -#[test] -fn test_option_string_trim() { - #[derive(Deserialize)] - struct OptionFoo { - #[serde(deserialize_with = "option_string_trim")] - name: Option, + #[test] + fn test_vec_string_trim() { + #[derive(Deserialize)] + struct VecFoo { + #[serde(deserialize_with = "vec_string_trim")] + name: Vec, + } + let json = r#"{"name":[" ","foo","b ar","hello "," rust"]}"#; + let foo = serde_json::from_str::(json).unwrap(); + assert_eq!(foo.name, vec!["", "foo", "b ar", "hello", "rust"]); } - let json = r#"{"name":" "}"#; - let foo = serde_json::from_str::(json).unwrap(); - assert_eq!(foo.name, None); - - #[derive(Deserialize)] - struct OptionBar { - #[serde(default, deserialize_with = "option_string_trim")] - name: Option, - addr: String, + + #[test] + fn test_btreeset_string_trim() { + #[derive(Deserialize)] + struct BTreeSetFoo { + #[serde(deserialize_with = "btreeset_string_trim")] + name: BTreeSet, + } + let json = r#"{"name":[" ","foo","b ar","hello "," rust"]}"#; + let foo = serde_json::from_str::(json).unwrap(); + let expected: BTreeSet = BTreeSet::from_iter([ + "".into(), + "foo".into(), + "b ar".into(), + "hello".into(), + "rust".into(), + ]); + assert_eq!(foo.name, expected); } - let json = r#"{"addr":"ABC"}"#; - let foo = serde_json::from_str::(json).unwrap(); - assert_eq!(foo.name, None); - assert_eq!(foo.addr, "ABC"); -} -#[test] -fn test_btreeset_string_trim() { - #[derive(Deserialize)] - struct BTreeSetFoo { - #[serde(deserialize_with = "btreeset_string_trim")] - name: BTreeSet, + #[test] + fn test_hashset_string_trim() { + #[derive(Deserialize)] + struct HashSetFoo { + #[serde(deserialize_with = "hashset_string_trim")] + name: HashSet, + } + let json = r#"{"name":[" ","foo","b ar","hello "," rust"," rust"]}"#; + let foo = serde_json::from_str::(json).unwrap(); + let expected: HashSet = HashSet::from_iter([ + "".into(), + "foo".into(), + "b ar".into(), + "hello".into(), + "rust".into(), + ]); + assert_eq!(foo.name, expected); + } + + #[test] + fn test_vecdeque_string_trim() { + #[derive(Deserialize)] + struct VecDequeFoo { + #[serde(deserialize_with = "vecdeque_string_trim")] + name: VecDeque, + } + let json = r#"{"name":[" ","foo","b ar","hello "," rust"]}"#; + let foo = serde_json::from_str::(json).unwrap(); + assert_eq!(foo.name, vec!["", "foo", "b ar", "hello", "rust"]); + } + + #[test] + fn test_linkedlist_string_trim() { + #[derive(Deserialize)] + struct LinkedListFoo { + #[serde(deserialize_with = "linkedlist_string_trim")] + name: LinkedList, + } + let json = r#"{"name":[" ","foo","b ar","hello "," rust"]}"#; + let foo = serde_json::from_str::(json).unwrap(); + assert_eq!( + foo.name, + LinkedList::from_iter([ + "".into(), + "foo".into(), + "b ar".into(), + "hello".into(), + "rust".into(), + ]) + ); + } + + #[test] + fn test_binaryheap_string_trim() { + #[derive(Deserialize)] + struct BinaryHeapFoo { + #[serde(deserialize_with = "binaryheap_string_trim")] + name: BinaryHeap, + } + let json = r#"{"name":[" ","foo","b ar","hello "," rust"]}"#; + let foo = serde_json::from_str::(json).unwrap(); + assert_eq!( + foo.name.into_vec(), + vec!["rust", "hello", "b ar", "", "foo"] + ); } - let json = r#"{"name":[" ","foo","b ar","hello "," rust"]}"#; - let foo = serde_json::from_str::(json).unwrap(); - let expected: BTreeSet = BTreeSet::from_iter([ - "".into(), - "foo".into(), - "b ar".into(), - "hello".into(), - "rust".into(), - ]); - assert_eq!(foo.name, expected); }