poem_openapi/types/external/
optional.rs

1use std::borrow::Cow;
2
3use poem::{http::HeaderValue, web::Field as PoemField};
4use serde_json::Value;
5
6use crate::{
7    registry::{MetaSchemaRef, Registry},
8    types::{
9        ParseError, ParseFromJSON, ParseFromMultipartField, ParseFromParameter, ParseResult,
10        ToHeader, ToJSON, Type,
11    },
12};
13
14impl<T: Type> Type for Option<T> {
15    const IS_REQUIRED: bool = false;
16
17    type RawValueType = T::RawValueType;
18
19    type RawElementValueType = T::RawElementValueType;
20
21    fn name() -> Cow<'static, str> {
22        format!("optional_{}", T::name()).into()
23    }
24
25    fn schema_ref() -> MetaSchemaRef {
26        T::schema_ref()
27    }
28
29    fn register(registry: &mut Registry) {
30        T::register(registry);
31    }
32
33    fn as_raw_value(&self) -> Option<&Self::RawValueType> {
34        match self {
35            Some(value) => value.as_raw_value(),
36            None => None,
37        }
38    }
39
40    fn raw_element_iter<'a>(
41        &'a self,
42    ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
43        match self {
44            Some(value) => value.raw_element_iter(),
45            None => Box::new(std::iter::empty()),
46        }
47    }
48
49    #[inline]
50    fn is_none(&self) -> bool {
51        <Option<T>>::is_none(self)
52    }
53}
54
55impl<T: ParseFromJSON> ParseFromJSON for Option<T> {
56    fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
57        match value.unwrap_or_default() {
58            Value::Null => Ok(None),
59            value => Ok(Some(
60                T::parse_from_json(Some(value)).map_err(ParseError::propagate)?,
61            )),
62        }
63    }
64}
65
66impl<T: ParseFromParameter> ParseFromParameter for Option<T> {
67    fn parse_from_parameter(_value: &str) -> ParseResult<Self> {
68        unreachable!()
69    }
70
71    fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
72        iter: I,
73    ) -> ParseResult<Self> {
74        let mut iter = iter.into_iter().peekable();
75
76        if iter.peek().is_none() {
77            return Ok(None);
78        }
79
80        T::parse_from_parameters(iter)
81            .map_err(ParseError::propagate)
82            .map(Some)
83    }
84}
85
86impl<T: ParseFromMultipartField> ParseFromMultipartField for Option<T> {
87    async fn parse_from_multipart(value: Option<PoemField>) -> ParseResult<Self> {
88        match value {
89            Some(value) => T::parse_from_multipart(Some(value))
90                .await
91                .map_err(ParseError::propagate)
92                .map(Some),
93            None => Ok(None),
94        }
95    }
96}
97
98impl<T: ToJSON> ToJSON for Option<T> {
99    fn to_json(&self) -> Option<Value> {
100        match self {
101            Some(value) => value.to_json(),
102            None => Some(Value::Null),
103        }
104    }
105}
106
107impl<T: ToHeader> ToHeader for Option<T> {
108    fn to_header(&self) -> Option<HeaderValue> {
109        match self {
110            Some(value) => value.to_header(),
111            None => None,
112        }
113    }
114}