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