poem_openapi/types/external/
hashset.rs

1use std::{
2    borrow::Cow,
3    collections::HashSet,
4    hash::{BuildHasher, Hash},
5};
6
7use poem::web::Field as PoemField;
8use serde_json::Value;
9
10use crate::{
11    registry::{MetaSchema, MetaSchemaRef, Registry},
12    types::{
13        ParseError, ParseFromJSON, ParseFromMultipartField, ParseFromParameter, ParseResult,
14        ToJSON, Type,
15    },
16};
17
18impl<T: Type, R: Send + Sync> Type for HashSet<T, R> {
19    const IS_REQUIRED: bool = true;
20
21    type RawValueType = Self;
22
23    type RawElementValueType = T::RawValueType;
24
25    fn name() -> Cow<'static, str> {
26        format!("set_{}", T::name()).into()
27    }
28
29    fn schema_ref() -> MetaSchemaRef {
30        MetaSchemaRef::Inline(Box::new(MetaSchema {
31            items: Some(Box::new(T::schema_ref())),
32            ..MetaSchema::new("array")
33        }))
34    }
35
36    fn register(registry: &mut Registry) {
37        T::register(registry);
38    }
39
40    fn as_raw_value(&self) -> Option<&Self::RawValueType> {
41        Some(self)
42    }
43
44    fn raw_element_iter<'a>(
45        &'a self,
46    ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
47        Box::new(self.iter().filter_map(|item| item.as_raw_value()))
48    }
49
50    fn is_empty(&self) -> bool {
51        HashSet::is_empty(self)
52    }
53}
54
55impl<T: ParseFromJSON + Hash + Eq, R: Default + BuildHasher + Send + Sync> ParseFromJSON
56    for HashSet<T, R>
57{
58    fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
59        let value = value.unwrap_or_default();
60        match value {
61            Value::Array(values) => {
62                let mut res = HashSet::with_hasher(Default::default());
63                for value in values {
64                    res.insert(T::parse_from_json(Some(value)).map_err(ParseError::propagate)?);
65                }
66                Ok(res)
67            }
68            _ => Err(ParseError::expected_type(value)),
69        }
70    }
71}
72
73impl<T: ParseFromParameter + Hash + Eq, R: Send + Sync + Default + BuildHasher> ParseFromParameter
74    for HashSet<T, R>
75{
76    fn parse_from_parameter(_value: &str) -> ParseResult<Self> {
77        unreachable!()
78    }
79
80    fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
81        iter: I,
82    ) -> ParseResult<Self> {
83        let mut values = HashSet::with_hasher(Default::default());
84        for s in iter {
85            values.insert(
86                T::parse_from_parameters(std::iter::once(s.as_ref()))
87                    .map_err(ParseError::propagate)?,
88            );
89        }
90        Ok(values)
91    }
92}
93
94impl<T, R> ParseFromMultipartField for HashSet<T, R>
95where
96    T: ParseFromMultipartField + Hash + Eq,
97    R: Send + Sync + Default + BuildHasher,
98{
99    async fn parse_from_multipart(field: Option<PoemField>) -> ParseResult<Self> {
100        match field {
101            Some(field) => {
102                let item = T::parse_from_multipart(Some(field))
103                    .await
104                    .map_err(ParseError::propagate)?;
105                let mut values = HashSet::with_hasher(Default::default());
106                values.insert(item);
107                Ok(values)
108            }
109            None => Ok(Default::default()),
110        }
111    }
112
113    async fn parse_from_repeated_field(mut self, field: PoemField) -> ParseResult<Self> {
114        let item = T::parse_from_multipart(Some(field))
115            .await
116            .map_err(ParseError::propagate)?;
117        self.insert(item);
118        Ok(self)
119    }
120}
121
122impl<T: ToJSON, R: Send + Sync> ToJSON for HashSet<T, R> {
123    fn to_json(&self) -> Option<Value> {
124        let mut values = Vec::with_capacity(self.len());
125        for item in self {
126            if let Some(value) = item.to_json() {
127                values.push(value);
128            }
129        }
130        Some(Value::Array(values))
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use super::*;
137
138    #[test]
139    fn parse_from_parameters() {
140        let values = Vec::<i32>::parse_from_parameters(vec!["100", "200", "300"]).unwrap();
141        assert_eq!(values, vec![100, 200, 300]);
142    }
143}