poem_openapi/types/
mod.rs1mod any;
4mod base64_type;
5mod binary;
6mod error;
7mod external;
8mod maybe_undefined;
9mod string_types;
10
11pub mod multipart;
12
13use std::{borrow::Cow, future::Future, sync::Arc};
14
15pub use any::Any;
16pub use base64_type::Base64;
17pub use binary::Binary;
18pub use error::{ParseError, ParseResult};
19pub use maybe_undefined::MaybeUndefined;
20use poem::{http::HeaderValue, web::Field as PoemField};
21use serde_json::Value;
22#[cfg(feature = "email")]
23pub use string_types::Email;
24#[cfg(feature = "hostname")]
25pub use string_types::Hostname;
26pub use string_types::Password;
27
28use crate::registry::{MetaSchemaRef, Registry};
29
30pub trait Type: Send + Sync {
32 const IS_REQUIRED: bool;
34
35 type RawValueType;
44
45 type RawElementValueType;
47
48 fn name() -> Cow<'static, str>;
50
51 fn schema_ref() -> MetaSchemaRef;
53
54 #[allow(unused_variables)]
56 fn register(registry: &mut Registry) {}
57
58 fn as_raw_value(&self) -> Option<&Self::RawValueType>;
60
61 fn raw_element_iter<'a>(
63 &'a self,
64 ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a>;
65
66 #[inline]
71 fn is_empty(&self) -> bool {
72 false
73 }
74
75 #[inline]
80 fn is_none(&self) -> bool {
81 false
82 }
83}
84
85pub trait IsObjectType: Type {}
87
88pub trait ParseFromJSON: Sized + Type {
90 fn parse_from_json(value: Option<Value>) -> ParseResult<Self>;
92
93 fn parse_from_json_string(s: &str) -> ParseResult<Self> {
95 let value = serde_json::from_str(s).map_err(|err| ParseError::custom(err.to_string()))?;
96 Self::parse_from_json(value)
97 }
98}
99
100pub trait ParseFromXML: Sized + Type {
102 fn parse_from_xml(value: Option<Value>) -> ParseResult<Self>;
104
105 fn parse_from_xml_string(s: &str) -> ParseResult<Self> {
107 let value =
108 quick_xml::de::from_str(s).map_err(|err| ParseError::custom(err.to_string()))?;
109 Self::parse_from_xml(value)
110 }
111}
112
113pub trait ParseFromYAML: Sized + Type {
115 fn parse_from_yaml(value: Option<Value>) -> ParseResult<Self>;
117
118 fn parse_from_yaml_string(s: &str) -> ParseResult<Self> {
120 let value = serde_yaml::from_str(s).map_err(|err| ParseError::custom(err.to_string()))?;
121 Self::parse_from_yaml(value)
122 }
123}
124
125pub trait ParseFromParameter: Sized + Type {
128 fn parse_from_parameter(value: &str) -> ParseResult<Self>;
130
131 fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
133 iter: I,
134 ) -> ParseResult<Self> {
135 let mut iter = iter.into_iter();
136 match iter.next().as_ref().map(|item| item.as_ref()) {
137 Some(value) => Self::parse_from_parameter(value),
138 None => Err(ParseError::expected_input()),
139 }
140 }
141}
142
143pub trait ParseFromMultipartField: Sized + Type {
145 fn parse_from_multipart(
147 field: Option<PoemField>,
148 ) -> impl Future<Output = ParseResult<Self>> + Send;
149
150 fn parse_from_repeated_field(
152 self,
153 _field: PoemField,
154 ) -> impl Future<Output = ParseResult<Self>> + Send {
155 async move { Err(ParseError::<Self>::custom("repeated field")) }
156 }
157}
158
159pub trait ToJSON: Type {
161 fn to_json(&self) -> Option<Value>;
163
164 fn to_json_string(&self) -> String {
166 serde_json::to_string(&self.to_json()).unwrap_or_default()
167 }
168}
169
170pub trait ToXML: Type {
172 fn to_xml(&self) -> Option<Value>;
174
175 fn to_xml_string(&self) -> String {
177 quick_xml::se::to_string(&self.to_xml()).unwrap_or_default()
178 }
179}
180
181pub trait ToYAML: Type {
183 fn to_yaml(&self) -> Option<Value>;
185
186 fn to_yaml_string(&self) -> String {
188 serde_yaml::to_string(&self.to_yaml()).unwrap_or_default()
189 }
190}
191
192pub trait ToHeader: Type {
194 fn to_header(&self) -> Option<HeaderValue>;
196}
197
198impl<T: Type> Type for &T {
199 const IS_REQUIRED: bool = T::IS_REQUIRED;
200
201 type RawValueType = T::RawValueType;
202
203 type RawElementValueType = T::RawElementValueType;
204
205 fn name() -> Cow<'static, str> {
206 T::name()
207 }
208
209 fn schema_ref() -> MetaSchemaRef {
210 T::schema_ref()
211 }
212
213 fn register(registry: &mut Registry) {
214 T::register(registry);
215 }
216
217 fn as_raw_value(&self) -> Option<&Self::RawValueType> {
218 (*self).as_raw_value()
219 }
220
221 fn raw_element_iter<'a>(
222 &'a self,
223 ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
224 (*self).raw_element_iter()
225 }
226}
227
228impl<T: ToJSON> ToJSON for &T {
229 fn to_json(&self) -> Option<Value> {
230 T::to_json(self)
231 }
232}
233
234impl<T: ToXML> ToXML for &T {
235 fn to_xml(&self) -> Option<Value> {
236 T::to_xml(self)
237 }
238}
239
240impl<T: ToYAML> ToYAML for &T {
241 fn to_yaml(&self) -> Option<Value> {
242 T::to_yaml(self)
243 }
244}
245
246impl<T: ToHeader> ToHeader for &T {
247 fn to_header(&self) -> Option<HeaderValue> {
248 T::to_header(self)
249 }
250}
251
252impl<T: Type> Type for Arc<T> {
253 const IS_REQUIRED: bool = T::IS_REQUIRED;
254
255 type RawValueType = T::RawValueType;
256
257 type RawElementValueType = T::RawElementValueType;
258
259 fn name() -> Cow<'static, str> {
260 T::name()
261 }
262
263 fn schema_ref() -> MetaSchemaRef {
264 T::schema_ref()
265 }
266
267 fn register(registry: &mut Registry) {
268 T::register(registry);
269 }
270
271 fn as_raw_value(&self) -> Option<&Self::RawValueType> {
272 self.as_ref().as_raw_value()
273 }
274
275 fn raw_element_iter<'a>(
276 &'a self,
277 ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
278 self.as_ref().raw_element_iter()
279 }
280}
281
282impl<T: ParseFromJSON> ParseFromJSON for Arc<T> {
283 fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
284 T::parse_from_json(value)
285 .map_err(ParseError::propagate)
286 .map(Arc::new)
287 }
288}
289
290impl<T: ParseFromXML> ParseFromXML for Arc<T> {
291 fn parse_from_xml(value: Option<Value>) -> ParseResult<Self> {
292 T::parse_from_xml(value)
293 .map_err(ParseError::propagate)
294 .map(Arc::new)
295 }
296}
297
298impl<T: ParseFromParameter> ParseFromParameter for Arc<T> {
299 fn parse_from_parameter(_value: &str) -> ParseResult<Self> {
300 unreachable!()
301 }
302
303 fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
304 iter: I,
305 ) -> ParseResult<Self> {
306 T::parse_from_parameters(iter)
307 .map_err(ParseError::propagate)
308 .map(Arc::new)
309 }
310}
311
312impl<T: ToJSON> ToJSON for Arc<T> {
313 fn to_json(&self) -> Option<Value> {
314 self.as_ref().to_json()
315 }
316}
317
318impl<T: ToXML> ToXML for Arc<T> {
319 fn to_xml(&self) -> Option<Value> {
320 self.as_ref().to_xml()
321 }
322}
323
324impl<T: ToHeader> ToHeader for Arc<T> {
325 fn to_header(&self) -> Option<HeaderValue> {
326 self.as_ref().to_header()
327 }
328}
329
330impl<T: Type> Type for Box<T> {
331 const IS_REQUIRED: bool = T::IS_REQUIRED;
332
333 type RawValueType = T::RawValueType;
334
335 type RawElementValueType = T::RawElementValueType;
336
337 fn name() -> Cow<'static, str> {
338 T::name()
339 }
340
341 fn schema_ref() -> MetaSchemaRef {
342 T::schema_ref()
343 }
344
345 fn register(registry: &mut Registry) {
346 T::register(registry);
347 }
348
349 fn as_raw_value(&self) -> Option<&Self::RawValueType> {
350 self.as_ref().as_raw_value()
351 }
352
353 fn raw_element_iter<'a>(
354 &'a self,
355 ) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
356 self.as_ref().raw_element_iter()
357 }
358}
359
360impl<T: ParseFromJSON> ParseFromJSON for Box<T> {
361 fn parse_from_json(value: Option<Value>) -> ParseResult<Self> {
362 T::parse_from_json(value)
363 .map_err(ParseError::propagate)
364 .map(Box::new)
365 }
366}
367
368impl<T: ParseFromXML> ParseFromXML for Box<T> {
369 fn parse_from_xml(value: Option<Value>) -> ParseResult<Self> {
370 T::parse_from_xml(value)
371 .map_err(ParseError::propagate)
372 .map(Box::new)
373 }
374}
375
376impl<T: ParseFromParameter> ParseFromParameter for Box<T> {
377 fn parse_from_parameter(_value: &str) -> ParseResult<Self> {
378 unreachable!()
379 }
380
381 fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
382 iter: I,
383 ) -> ParseResult<Self> {
384 T::parse_from_parameters(iter)
385 .map_err(ParseError::propagate)
386 .map(Box::new)
387 }
388}
389
390impl<T: ParseFromMultipartField> ParseFromMultipartField for Box<T> {
391 async fn parse_from_multipart(field: Option<PoemField>) -> ParseResult<Self> {
392 T::parse_from_multipart(field)
393 .await
394 .map_err(ParseError::propagate)
395 .map(Box::new)
396 }
397
398 async fn parse_from_repeated_field(self, field: PoemField) -> ParseResult<Self> {
399 T::parse_from_repeated_field(*self, field)
400 .await
401 .map_err(ParseError::propagate)
402 .map(Box::new)
403 }
404}
405
406impl<T: ToJSON> ToJSON for Box<T> {
407 fn to_json(&self) -> Option<Value> {
408 self.as_ref().to_json()
409 }
410}
411
412impl<T: ToXML> ToXML for Box<T> {
413 fn to_xml(&self) -> Option<Value> {
414 self.as_ref().to_xml()
415 }
416}
417
418impl<T: ToYAML> ToYAML for Box<T> {
419 fn to_yaml(&self) -> Option<Value> {
420 self.as_ref().to_yaml()
421 }
422}
423
424impl<T: ToHeader> ToHeader for Box<T> {
425 fn to_header(&self) -> Option<HeaderValue> {
426 self.as_ref().to_header()
427 }
428}
429
430pub trait Example {
432 fn example() -> Self;
434}
435
436#[cfg(test)]
437mod tests {
438 use super::*;
439
440 #[test]
441 #[allow(clippy::assertions_on_constants)]
442 fn arc_type() {
443 assert!(Arc::<i32>::IS_REQUIRED);
444 assert_eq!(Arc::<i32>::name(), "integer_int32");
445 assert_eq!(Arc::new(100).as_raw_value(), Some(&100));
446
447 let value: Arc<i32> =
448 ParseFromJSON::parse_from_json(Some(Value::Number(100.into()))).unwrap();
449 assert_eq!(value, Arc::new(100));
450
451 let value: Arc<i32> =
452 ParseFromXML::parse_from_xml(Some(Value::Number(100.into()))).unwrap();
453 assert_eq!(value, Arc::new(100));
454
455 let value: Arc<i32> =
456 ParseFromParameter::parse_from_parameters(std::iter::once("100")).unwrap();
457 assert_eq!(value, Arc::new(100));
458
459 assert_eq!(
460 ToJSON::to_json(&Arc::new(100)),
461 Some(Value::Number(100.into()))
462 );
463
464 assert_eq!(
465 ToXML::to_xml(&Arc::new(100)),
466 Some(Value::Number(100.into()))
467 );
468 }
469
470 #[test]
471 #[allow(clippy::assertions_on_constants)]
472 #[allow(unused_allocation)]
473 fn box_type() {
474 assert!(Box::<i32>::IS_REQUIRED);
475 assert_eq!(Box::<i32>::name(), "integer_int32");
476 assert_eq!(Box::new(100).as_raw_value(), Some(&100));
477
478 let value: Box<i32> =
479 ParseFromJSON::parse_from_json(Some(Value::Number(100.into()))).unwrap();
480 assert_eq!(value, Box::new(100));
481
482 let value: Box<i32> =
483 ParseFromJSON::parse_from_json(Some(Value::Number(100.into()))).unwrap();
484 assert_eq!(value, Box::new(100));
485
486 let value: Box<i32> =
487 ParseFromXML::parse_from_xml(Some(Value::Number(100.into()))).unwrap();
488 assert_eq!(value, Box::new(100));
489
490 let value: Box<i32> =
491 ParseFromParameter::parse_from_parameters(std::iter::once("100")).unwrap();
492 assert_eq!(value, Box::new(100));
493
494 assert_eq!(
495 ToJSON::to_json(&Box::new(100)),
496 Some(Value::Number(100.into()))
497 );
498
499 assert_eq!(
500 ToXML::to_xml(&Box::new(100)),
501 Some(Value::Number(100.into()))
502 );
503 }
504}