poem_openapi/types/external/
btreemap.rs

1use std::{borrow::Cow, collections::BTreeMap, fmt::Display, str::FromStr};
2
3use serde_json::Value;
4
5use crate::{
6    registry::{MetaSchema, MetaSchemaRef, Registry},
7    types::{ParseError, ParseFromJSON, ParseResult, ToJSON, Type},
8};
9
10impl<K, V> Type for BTreeMap<K, V>
11where
12    K: ToString + FromStr + Ord + Sync + Send,
13    V: Type,
14{
15    const IS_REQUIRED: bool = true;
16
17    type RawValueType = Self;
18
19    type RawElementValueType = V::RawValueType;
20
21    fn name() -> Cow<'static, str> {
22        format!("map_{}", V::name()).into()
23    }
24
25    fn schema_ref() -> MetaSchemaRef {
26        MetaSchemaRef::Inline(Box::new(MetaSchema {
27            additional_properties: Some(Box::new(V::schema_ref())),
28            ..MetaSchema::new("object")
29        }))
30    }
31
32    fn register(registry: &mut Registry) {
33        V::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.values().filter_map(|item| item.as_raw_value()))
44    }
45
46    fn is_empty(&self) -> bool {
47        BTreeMap::is_empty(self)
48    }
49}
50
51impl<K, V> ParseFromJSON for BTreeMap<K, V>
52where
53    K: ToString + FromStr + Ord + Sync + Send,
54    K::Err: Display,
55    V: ParseFromJSON,
56{
57    fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
58        let value = value.unwrap_or_default();
59        if let Value::Object(value) = value {
60            let mut obj = BTreeMap::new();
61            for (key, value) in value {
62                let key = key
63                    .parse()
64                    .map_err(|err| ParseError::custom(format!("object key: {err}")))?;
65                let value = V::parse_from_json(Some(value)).map_err(ParseError::propagate)?;
66                obj.insert(key, value);
67            }
68            Ok(obj)
69        } else {
70            Err(ParseError::expected_type(value))
71        }
72    }
73}
74
75impl<K, V> ToJSON for BTreeMap<K, V>
76where
77    K: ToString + FromStr + Ord + Sync + Send,
78    V: ToJSON,
79{
80    fn to_json(&self) -> Option<Value> {
81        let mut map = serde_json::Map::new();
82        for (name, value) in self {
83            if let Some(value) = value.to_json() {
84                map.insert(name.to_string(), value);
85            }
86        }
87        Some(Value::Object(map))
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn test_hashmap() {
97        type MyObj = BTreeMap<String, i32>;
98
99        assert_eq!(
100            MyObj::schema_ref().unwrap_inline(),
101            &MetaSchema {
102                additional_properties: Some(Box::new(i32::schema_ref())),
103                ..MetaSchema::new("object")
104            }
105        );
106    }
107}