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