poem_openapi/types/external/
array.rs

1use std::borrow::Cow;
2
3use serde_json::Value;
4
5use crate::{
6    registry::{MetaSchema, MetaSchemaRef, Registry},
7    types::{ParseError, ParseFromJSON, ParseFromParameter, ParseResult, ToJSON, Type},
8};
9
10impl<T: Type, const LEN: usize> Type for [T; LEN] {
11    const IS_REQUIRED: bool = true;
12
13    type RawValueType = Self;
14
15    type RawElementValueType = T::RawValueType;
16
17    fn name() -> Cow<'static, str> {
18        format!("array_{}", T::name()).into()
19    }
20
21    fn schema_ref() -> MetaSchemaRef {
22        MetaSchemaRef::Inline(Box::new(MetaSchema {
23            items: Some(Box::new(T::schema_ref())),
24            max_length: Some(LEN),
25            min_length: Some(LEN),
26            ..MetaSchema::new("array")
27        }))
28    }
29
30    fn register(registry: &mut Registry) {
31        T::register(registry);
32    }
33
34    fn as_raw_value(&self) -> Option<&Self::RawValueType> {
35        Some(self)
36    }
37
38    fn raw_element_iter<'a>(
39        &'a self,
40    ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
41        Box::new(self.iter().filter_map(|item| item.as_raw_value()))
42    }
43}
44
45impl<T: ParseFromJSON, const LEN: usize> ParseFromJSON for [T; LEN] {
46    fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
47        let value = value.unwrap_or_default();
48        match value {
49            Value::Array(values) => {
50                if values.len() != LEN {
51                    return Err(ParseError::custom(format!(
52                        "the length of the list must be `{LEN}`."
53                    )));
54                }
55
56                let mut res = Vec::with_capacity(values.len());
57                for value in values {
58                    res.push(T::parse_from_json(Some(value)).map_err(ParseError::propagate)?);
59                }
60
61                Ok(res.try_into().ok().unwrap())
62            }
63            _ => Err(ParseError::expected_type(value)),
64        }
65    }
66}
67
68impl<T: ParseFromParameter, const LEN: usize> ParseFromParameter for [T; LEN] {
69    fn parse_from_parameter(_value: &str) -> ParseResult<Self> {
70        unreachable!()
71    }
72
73    fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
74        iter: I,
75    ) -> ParseResult<Self> {
76        let mut values = Vec::new();
77
78        for s in iter {
79            values.push(
80                T::parse_from_parameters(std::iter::once(s.as_ref()))
81                    .map_err(ParseError::propagate)?,
82            );
83        }
84
85        if values.len() != LEN {
86            return Err(ParseError::custom(format!(
87                "the length of the list must be `{LEN}`."
88            )));
89        }
90
91        Ok(values.try_into().ok().unwrap())
92    }
93}
94
95impl<T: ToJSON, const LEN: usize> ToJSON for [T; LEN] {
96    fn to_json(&self) -> Option<Value> {
97        let mut values = Vec::with_capacity(self.len());
98        for item in self {
99            if let Some(value) = item.to_json() {
100                values.push(value);
101            }
102        }
103        Some(Value::Array(values))
104    }
105}