Skip to content

Commit

Permalink
feat: add hashset_string
Browse files Browse the repository at this point in the history
  • Loading branch information
robjtede committed May 25, 2024
1 parent e5835cb commit 0ddcc4f
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 3 deletions.
1 change: 1 addition & 0 deletions .cspell.config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ words:
- deserializers
- detrim
- docsrs
- hashset
- rdme
- serde
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"cSpell.autoFormatConfigFile": true
"cSpell.autoFormatConfigFile": true,
"rust-analyzer.cargo.features": "all",
}
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- Add `hashset_string()` function behind on-by-default `std` crate feature.

## 0.1.1

- Add `option_string()` function.
Expand Down
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ license = "MIT OR Apache-2.0"
edition = "2018"
rust-version = "1.56.1"

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[features]
default = ["std"]
std = []

[dependencies]
serde = { version = "1", default-features = false, features = ["alloc"] }

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<br />
[![CI](https://github.com/x52dev/detrim/actions/workflows/ci.yml/badge.svg)](https://github.com/x52dev/detrim/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/x52dev/detrim/branch/main/graph/badge.svg)](https://codecov.io/gh/x52dev/detrim)
![Version](https://img.shields.io/badge/rustc-1.56+-ab6000.svg)
![Version](https://img.shields.io/badge/rustc-1.56.1+-ab6000.svg)
[![Download](https://img.shields.io/crates/d/detrim.svg)](https://crates.io/crates/detrim)

<!-- prettier-ignore-end -->
Expand Down
1 change: 1 addition & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ clippy:

# Run workspace test suite.
test toolchain="":
cargo {{ toolchain }} nextest run --workspace --no-default-features
cargo {{ toolchain }} nextest run --workspace --all-features
cargo {{ toolchain }} test --doc --workspace --all-features
RUSTDOCFLAGS="-D warnings" cargo {{ toolchain }} doc --workspace --all-features --no-deps
Expand Down
88 changes: 88 additions & 0 deletions src/hashset_string.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use core::iter::FromIterator as _;
use std::collections::HashSet;

use alloc::{borrow::ToOwned as _, string::String, vec::Vec};

use serde::{Deserialize as _, Deserializer};

/// Trims set of strings during deserialization.
///
/// Strings are deduplicated _after_ being trimmed (i.e., differences in extraneous whitespace are
/// handled).
pub fn hashset_string<'a, D: Deserializer<'a>>(de: D) -> Result<HashSet<String>, D::Error> {
let mut set = Vec::<String>::deserialize(de)?;

for item in &mut set {
*item = item.trim().to_owned();
}

Ok(HashSet::from_iter(set))
}

#[cfg(test)]
mod tests {
use serde::Deserialize;

use super::*;

#[test]
fn hashset_string() {
#[derive(Debug, Deserialize, PartialEq, Eq)]
struct Foo {
#[serde(deserialize_with = "super::hashset_string")]
foo: HashSet<String>,
}

impl Foo {
fn new(foo: impl IntoIterator<Item = impl Into<String>>) -> Self {
Self {
foo: foo.into_iter().map(Into::into).collect(),
}
}
}

serde_json::from_str::<Foo>(r#"{ "foo": 1 }"#).unwrap_err();
serde_json::from_str::<Foo>(r#"{ "foo": "" }"#).unwrap_err();

assert_eq!(
Foo::new([""; 0]),
serde_json::from_str(r#"{ "foo": [] }"#).unwrap(),
);
assert_eq!(
Foo::new([""]),
serde_json::from_str(r#"{ "foo": [""] }"#).unwrap(),
);
assert_eq!(
Foo::new([""]),
serde_json::from_str(r#"{ "foo": [" "] }"#).unwrap(),
);
assert_eq!(
Foo::new(["bar"]),
serde_json::from_str(r#"{ "foo": ["bar"] }"#).unwrap(),
);
assert_eq!(
Foo::new(["bar"]),
serde_json::from_str(r#"{ "foo": [" bar"] }"#).unwrap(),
);
assert_eq!(
Foo::new(["bar"]),
serde_json::from_str(r#"{ "foo": [" bar"] }"#).unwrap(),
);
assert_eq!(
Foo::new(["bar"]),
serde_json::from_str(r#"{ "foo": ["bar "] }"#).unwrap(),
);
assert_eq!(
Foo::new(["bar"]),
serde_json::from_str(r#"{ "foo": [" bar "] }"#).unwrap(),
);
assert_eq!(
Foo::new(["bar"]),
serde_json::from_str(r#"{ "foo": [" bar ", " bar "] }"#).unwrap(),
);
assert_eq!(
Foo::new(["bar"]),
serde_json::from_str(r#"{ "foo": [" bar ", " bar"] }"#).unwrap(),
);
}
}
6 changes: 5 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//! **De**serialization **trim**ming for strings in serde models.

#![no_std]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]

extern crate alloc;

#[cfg(feature = "std")]
mod hashset_string;
mod string;
mod string_non_empty;
mod vec_string;
Expand All @@ -14,3 +16,5 @@ pub use crate::{
string_non_empty::{option_string_non_empty, string_non_empty},
vec_string::vec_string,
};
#[cfg(feature = "std")]
pub use hashset_string::hashset_string;

0 comments on commit 0ddcc4f

Please sign in to comment.