Skip to content

Commit

Permalink
Support for custom hash functions for HashMap (#654)
Browse files Browse the repository at this point in the history
  • Loading branch information
a14e committed Sep 26, 2023
1 parent 6baeae8 commit a2e8b98
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 21 deletions.
19 changes: 14 additions & 5 deletions poem-openapi/src/types/external/hashmap.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
use std::{borrow::Cow, collections::HashMap, fmt::Display, hash::Hash, str::FromStr};
use std::{
borrow::Cow,
collections::HashMap,
fmt::Display,
hash::{BuildHasher, Hash},
str::FromStr,
};

use serde_json::Value;

Expand All @@ -7,10 +13,11 @@ use crate::{
types::{ParseError, ParseFromJSON, ParseResult, ToJSON, Type},
};

impl<K, V> Type for HashMap<K, V>
impl<K, V, R> Type for HashMap<K, V, R>
where
K: ToString + FromStr + Eq + Hash + Sync + Send,
V: Type,
R: Sync + Send,
{
const IS_REQUIRED: bool = true;

Expand Down Expand Up @@ -48,16 +55,17 @@ where
}
}

impl<K, V> ParseFromJSON for HashMap<K, V>
impl<K, V, R> ParseFromJSON for HashMap<K, V, R>
where
K: ToString + FromStr + Eq + Hash + Sync + Send,
K::Err: Display,
V: ParseFromJSON,
R: Sync + Send + Default + BuildHasher,
{
fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
let value = value.unwrap_or_default();
if let Value::Object(value) = value {
let mut obj = HashMap::new();
let mut obj = HashMap::with_hasher(R::default());
for (key, value) in value {
let key = key
.parse()
Expand All @@ -72,10 +80,11 @@ where
}
}

impl<K, V> ToJSON for HashMap<K, V>
impl<K, V, R> ToJSON for HashMap<K, V, R>
where
K: ToString + FromStr + Eq + Hash + Sync + Send,
V: ToJSON,
R: Sync + Send,
{
fn to_json(&self) -> Option<Value> {
let mut map = serde_json::Map::new();
Expand Down
30 changes: 20 additions & 10 deletions poem-openapi/src/types/external/hashset.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use std::{borrow::Cow, collections::HashSet, hash::Hash};
use std::{
borrow::Cow,
collections::HashSet,
hash::{BuildHasher, Hash},
};

use poem::web::Field as PoemField;
use serde_json::Value;
Expand All @@ -11,7 +15,7 @@ use crate::{
},
};

impl<T: Type> Type for HashSet<T> {
impl<T: Type, R: Send + Sync> Type for HashSet<T, R> {
const IS_REQUIRED: bool = true;

type RawValueType = Self;
Expand Down Expand Up @@ -48,12 +52,14 @@ impl<T: Type> Type for HashSet<T> {
}
}

impl<T: ParseFromJSON + Hash + Eq> ParseFromJSON for HashSet<T> {
impl<T: ParseFromJSON + Hash + Eq, R: Default + BuildHasher + Send + Sync> ParseFromJSON
for HashSet<T, R>
{
fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
let value = value.unwrap_or_default();
match value {
Value::Array(values) => {
let mut res = HashSet::new();
let mut res = HashSet::with_hasher(Default::default());
for value in values {
res.insert(T::parse_from_json(Some(value)).map_err(ParseError::propagate)?);
}
Expand All @@ -64,15 +70,17 @@ impl<T: ParseFromJSON + Hash + Eq> ParseFromJSON for HashSet<T> {
}
}

impl<T: ParseFromParameter + Hash + Eq> ParseFromParameter for HashSet<T> {
impl<T: ParseFromParameter + Hash + Eq, R: Send + Sync + Default + BuildHasher> ParseFromParameter
for HashSet<T, R>
{
fn parse_from_parameter(_value: &str) -> ParseResult<Self> {
unreachable!()
}

fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
iter: I,
) -> ParseResult<Self> {
let mut values = HashSet::new();
let mut values = HashSet::with_hasher(Default::default());
for s in iter {
values.insert(
T::parse_from_parameters(std::iter::once(s.as_ref()))
Expand All @@ -84,18 +92,20 @@ impl<T: ParseFromParameter + Hash + Eq> ParseFromParameter for HashSet<T> {
}

#[poem::async_trait]
impl<T: ParseFromMultipartField + Hash + Eq> ParseFromMultipartField for HashSet<T> {
impl<T: ParseFromMultipartField + Hash + Eq, R: Send + Sync + Default + BuildHasher>
ParseFromMultipartField for HashSet<T, R>
{
async fn parse_from_multipart(field: Option<PoemField>) -> ParseResult<Self> {
match field {
Some(field) => {
let item = T::parse_from_multipart(Some(field))
.await
.map_err(ParseError::propagate)?;
let mut values = HashSet::new();
let mut values = HashSet::with_hasher(Default::default());
values.insert(item);
Ok(values)
}
None => Ok(HashSet::new()),
None => Ok(Default::default()),
}
}

Expand All @@ -108,7 +118,7 @@ impl<T: ParseFromMultipartField + Hash + Eq> ParseFromMultipartField for HashSet
}
}

impl<T: ToJSON> ToJSON for HashSet<T> {
impl<T: ToJSON, R: Send + Sync> ToJSON for HashSet<T, R> {
fn to_json(&self) -> Option<Value> {
let mut values = Vec::with_capacity(self.len());
for item in self {
Expand Down
4 changes: 2 additions & 2 deletions poem-openapi/src/validation/max_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ impl MaxProperties {
}
}

impl<K, V> Validator<HashMap<K, V>> for MaxProperties {
impl<K, V, R> Validator<HashMap<K, V, R>> for MaxProperties {
#[inline]
fn check(&self, value: &HashMap<K, V>) -> bool {
fn check(&self, value: &HashMap<K, V, R>) -> bool {
value.len() <= self.len
}
}
Expand Down
4 changes: 2 additions & 2 deletions poem-openapi/src/validation/min_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ impl MinProperties {
}
}

impl<K, V> Validator<HashMap<K, V>> for MinProperties {
impl<K, V, R> Validator<HashMap<K, V, R>> for MinProperties {
#[inline]
fn check(&self, value: &HashMap<K, V>) -> bool {
fn check(&self, value: &HashMap<K, V, R>) -> bool {
value.len() >= self.len
}
}
Expand Down
4 changes: 2 additions & 2 deletions poem/src/i18n/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ impl<'a> I18NArgs<'a> {
}
}

impl<'a, K, V> From<HashMap<K, V>> for I18NArgs<'a>
impl<'a, K, V, R> From<HashMap<K, V, R>> for I18NArgs<'a>
where
K: Into<Cow<'a, str>>,
V: Into<FluentValue<'a>>,
{
fn from(map: HashMap<K, V>) -> Self {
fn from(map: HashMap<K, V, R>) -> Self {
let mut args = FluentArgs::new();
for (key, value) in map {
args.set(key, value);
Expand Down

0 comments on commit a2e8b98

Please sign in to comment.