poem_openapi/types/external/
hashset.rs1use 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}