poem_openapi/types/external/
btreeset.rs

1use 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}