mod any;
mod base64_type;
mod binary;
mod error;
mod external;
mod string_types;
pub mod multipart;
use std::{borrow::Cow, sync::Arc};
pub use any::Any;
pub use base64_type::Base64;
pub use binary::Binary;
pub use error::{ParseError, ParseResult};
use poem::{http::HeaderValue, web::Field as PoemField};
use serde_json::Value;
#[cfg(feature = "email")]
pub use string_types::Email;
#[cfg(feature = "hostname")]
pub use string_types::Hostname;
pub use string_types::Password;
use crate::registry::{MetaSchemaRef, Registry};
pub trait Type: Send + Sync {
const IS_REQUIRED: bool;
type RawValueType;
type RawElementValueType;
fn name() -> Cow<'static, str>;
fn schema_ref() -> MetaSchemaRef;
#[allow(unused_variables)]
fn register(registry: &mut Registry) {}
fn as_raw_value(&self) -> Option<&Self::RawValueType>;
fn raw_element_iter<'a>(
&'a self,
) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a>;
}
pub trait ParseFromJSON: Sized + Type {
fn parse_from_json(value: Value) -> ParseResult<Self>;
}
pub trait ParseFromParameter: Sized + Type {
fn parse_from_parameter(value: &str) -> ParseResult<Self>;
fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
iter: I,
) -> ParseResult<Self> {
let mut iter = iter.into_iter();
match iter.next().as_ref().map(|item| item.as_ref()) {
Some(value) => Self::parse_from_parameter(value),
None => Err(ParseError::expected_input()),
}
}
}
#[poem::async_trait]
pub trait ParseFromMultipartField: Sized + Type {
async fn parse_from_multipart(field: Option<PoemField>) -> ParseResult<Self>;
async fn parse_from_repeated_field(self, _field: PoemField) -> ParseResult<Self> {
Err(ParseError::<Self>::custom("repeated field"))
}
}
pub trait ToJSON: Type {
fn to_json(&self) -> Value;
}
pub trait ToHeader: Type {
fn to_header(&self) -> Option<HeaderValue>;
}
impl<T: Type> Type for &T {
const IS_REQUIRED: bool = T::IS_REQUIRED;
type RawValueType = T::RawValueType;
type RawElementValueType = T::RawElementValueType;
fn name() -> Cow<'static, str> {
T::name()
}
fn schema_ref() -> MetaSchemaRef {
T::schema_ref()
}
fn register(registry: &mut Registry) {
T::register(registry);
}
fn as_raw_value(&self) -> Option<&Self::RawValueType> {
(*self).as_raw_value()
}
fn raw_element_iter<'a>(
&'a self,
) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
(*self).raw_element_iter()
}
}
impl<T: ToJSON> ToJSON for &T {
fn to_json(&self) -> Value {
T::to_json(self)
}
}
impl<T: ToHeader> ToHeader for &T {
fn to_header(&self) -> Option<HeaderValue> {
T::to_header(self)
}
}
impl<T: Type> Type for Arc<T> {
const IS_REQUIRED: bool = T::IS_REQUIRED;
type RawValueType = T::RawValueType;
type RawElementValueType = T::RawElementValueType;
fn name() -> Cow<'static, str> {
T::name()
}
fn schema_ref() -> MetaSchemaRef {
T::schema_ref()
}
fn register(registry: &mut Registry) {
T::register(registry);
}
fn as_raw_value(&self) -> Option<&Self::RawValueType> {
self.as_ref().as_raw_value()
}
fn raw_element_iter<'a>(
&'a self,
) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
self.as_ref().raw_element_iter()
}
}
impl<T: ParseFromJSON> ParseFromJSON for Arc<T> {
fn parse_from_json(value: Value) -> ParseResult<Self> {
T::parse_from_json(value)
.map_err(ParseError::propagate)
.map(Arc::new)
}
}
impl<T: ParseFromParameter> ParseFromParameter for Arc<T> {
fn parse_from_parameter(_value: &str) -> ParseResult<Self> {
unreachable!()
}
fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
iter: I,
) -> ParseResult<Self> {
T::parse_from_parameters(iter)
.map_err(ParseError::propagate)
.map(Arc::new)
}
}
impl<T: ToJSON> ToJSON for Arc<T> {
fn to_json(&self) -> Value {
self.as_ref().to_json()
}
}
impl<T: ToHeader> ToHeader for Arc<T> {
fn to_header(&self) -> Option<HeaderValue> {
self.as_ref().to_header()
}
}
impl<T: Type> Type for Box<T> {
const IS_REQUIRED: bool = T::IS_REQUIRED;
type RawValueType = T::RawValueType;
type RawElementValueType = T::RawElementValueType;
fn name() -> Cow<'static, str> {
T::name()
}
fn schema_ref() -> MetaSchemaRef {
T::schema_ref()
}
fn register(registry: &mut Registry) {
T::register(registry);
}
fn as_raw_value(&self) -> Option<&Self::RawValueType> {
self.as_ref().as_raw_value()
}
fn raw_element_iter<'a>(
&'a self,
) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
self.as_ref().raw_element_iter()
}
}
impl<T: ParseFromJSON> ParseFromJSON for Box<T> {
fn parse_from_json(value: Value) -> ParseResult<Self> {
T::parse_from_json(value)
.map_err(ParseError::propagate)
.map(Box::new)
}
}
impl<T: ParseFromParameter> ParseFromParameter for Box<T> {
fn parse_from_parameter(_value: &str) -> ParseResult<Self> {
unreachable!()
}
fn parse_from_parameters<I: IntoIterator<Item = A>, A: AsRef<str>>(
iter: I,
) -> ParseResult<Self> {
T::parse_from_parameters(iter)
.map_err(ParseError::propagate)
.map(Box::new)
}
}
#[poem::async_trait]
impl<T: ParseFromMultipartField> ParseFromMultipartField for Box<T> {
async fn parse_from_multipart(field: Option<PoemField>) -> ParseResult<Self> {
T::parse_from_multipart(field)
.await
.map_err(ParseError::propagate)
.map(Box::new)
}
async fn parse_from_repeated_field(self, field: PoemField) -> ParseResult<Self> {
T::parse_from_repeated_field(*self, field)
.await
.map_err(ParseError::propagate)
.map(Box::new)
}
}
impl<T: ToJSON> ToJSON for Box<T> {
fn to_json(&self) -> Value {
self.as_ref().to_json()
}
}
impl<T: ToHeader> ToHeader for Box<T> {
fn to_header(&self) -> Option<HeaderValue> {
self.as_ref().to_header()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn arc_type() {
assert_eq!(Arc::<i32>::IS_REQUIRED, true);
assert_eq!(Arc::<i32>::name(), "integer(int32)");
assert_eq!(Arc::new(100).as_raw_value(), Some(&100));
let value: Arc<i32> = ParseFromJSON::parse_from_json(Value::Number(100.into())).unwrap();
assert_eq!(value, Arc::new(100));
let value: Arc<i32> =
ParseFromParameter::parse_from_parameters(std::iter::once("100")).unwrap();
assert_eq!(value, Arc::new(100));
assert_eq!(ToJSON::to_json(&Arc::new(100)), Value::Number(100.into()));
}
#[test]
fn box_type() {
assert_eq!(Box::<i32>::IS_REQUIRED, true);
assert_eq!(Box::<i32>::name(), "integer(int32)");
assert_eq!(Box::new(100).as_raw_value(), Some(&100));
let value: Box<i32> = ParseFromJSON::parse_from_json(Value::Number(100.into())).unwrap();
assert_eq!(value, Box::new(100));
let value: Box<i32> = ParseFromJSON::parse_from_json(Value::Number(100.into())).unwrap();
assert_eq!(value, Box::new(100));
let value: Box<i32> =
ParseFromParameter::parse_from_parameters(std::iter::once("100")).unwrap();
assert_eq!(value, Box::new(100));
assert_eq!(ToJSON::to_json(&Box::new(100)), Value::Number(100.into()));
}
}