use crate::schema::*;
use crate::JsonSchema;
use crate::{gen::SchemaGenerator, Map};
use serde_json::{Error, Value};
use std::{convert::TryInto, fmt::Display};
pub(crate) struct Serializer<'a> {
pub(crate) gen: &'a mut SchemaGenerator,
pub(crate) include_title: bool,
}
pub(crate) struct SerializeSeq<'a> {
gen: &'a mut SchemaGenerator,
items: Option<Schema>,
}
pub(crate) struct SerializeTuple<'a> {
gen: &'a mut SchemaGenerator,
items: Vec<Schema>,
title: &'static str,
}
pub(crate) struct SerializeMap<'a> {
gen: &'a mut SchemaGenerator,
properties: Map<String, Schema>,
current_key: Option<String>,
title: &'static str,
}
macro_rules! forward_to_subschema_for {
($fn:ident, $ty:ty) => {
fn $fn(self, _value: $ty) -> Result<Self::Ok, Self::Error> {
Ok(self.gen.subschema_for::<$ty>())
}
};
}
macro_rules! return_instance_type {
($fn:ident, $ty:ty, $instance_type:ident) => {
fn $fn(self, _value: $ty) -> Result<Self::Ok, Self::Error> {
Ok(SchemaObject {
instance_type: Some(InstanceType::$instance_type.into()),
..Default::default()
}
.into())
}
};
}
impl<'a> serde::Serializer for Serializer<'a> {
type Ok = Schema;
type Error = Error;
type SerializeSeq = SerializeSeq<'a>;
type SerializeTuple = SerializeTuple<'a>;
type SerializeTupleStruct = SerializeTuple<'a>;
type SerializeTupleVariant = Self;
type SerializeMap = SerializeMap<'a>;
type SerializeStruct = SerializeMap<'a>;
type SerializeStructVariant = Self;
return_instance_type!(serialize_i8, i8, Integer);
return_instance_type!(serialize_i16, i16, Integer);
return_instance_type!(serialize_i32, i32, Integer);
return_instance_type!(serialize_i64, i64, Integer);
return_instance_type!(serialize_i128, i128, Integer);
return_instance_type!(serialize_u8, u8, Integer);
return_instance_type!(serialize_u16, u16, Integer);
return_instance_type!(serialize_u32, u32, Integer);
return_instance_type!(serialize_u64, u64, Integer);
return_instance_type!(serialize_u128, u128, Integer);
return_instance_type!(serialize_f32, f32, Number);
return_instance_type!(serialize_f64, f64, Number);
forward_to_subschema_for!(serialize_bool, bool);
forward_to_subschema_for!(serialize_char, char);
forward_to_subschema_for!(serialize_str, &str);
forward_to_subschema_for!(serialize_bytes, &[u8]);
fn collect_str<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
where
T: Display,
{
Ok(self.gen.subschema_for::<&str>())
}
fn collect_map<K, V, I>(self, iter: I) -> Result<Self::Ok, Self::Error>
where
K: serde::Serialize,
V: serde::Serialize,
I: IntoIterator<Item = (K, V)>,
{
let value_schema = iter
.into_iter()
.try_fold(None, |acc, (_, v)| {
if acc == Some(Schema::Bool(true)) {
return Ok(acc);
}
let schema = v.serialize(Serializer {
gen: self.gen,
include_title: false,
})?;
Ok(match &acc {
None => Some(schema),
Some(items) if items != &schema => Some(Schema::Bool(true)),
_ => acc,
})
})?
.unwrap_or(Schema::Bool(true));
Ok(SchemaObject {
instance_type: Some(InstanceType::Object.into()),
object: Some(Box::new(ObjectValidation {
additional_properties: Some(Box::new(value_schema)),
..ObjectValidation::default()
})),
..SchemaObject::default()
}
.into())
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Ok(self.gen.subschema_for::<Option<Value>>())
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
self.serialize_none()
}
fn serialize_some<T: ?Sized>(mut self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: serde::Serialize,
{
fn add_null_type(instance_type: &mut SingleOrVec<InstanceType>) {
match instance_type {
SingleOrVec::Single(ty) if **ty != InstanceType::Null => {
*instance_type = vec![**ty, InstanceType::Null].into()
}
SingleOrVec::Vec(ty) if !ty.contains(&InstanceType::Null) => {
ty.push(InstanceType::Null)
}
_ => {}
};
}
let mut schema = value.serialize(Serializer {
gen: self.gen,
include_title: false,
})?;
if self.gen.settings().option_add_null_type {
schema = match schema {
Schema::Bool(true) => Schema::Bool(true),
Schema::Bool(false) => <()>::json_schema(&mut self.gen),
Schema::Object(SchemaObject {
instance_type: Some(ref mut instance_type),
..
}) => {
add_null_type(instance_type);
schema
}
schema => SchemaObject {
subschemas: Some(Box::new(SubschemaValidation {
any_of: Some(vec![schema, <()>::json_schema(&mut self.gen)]),
..Default::default()
})),
..Default::default()
}
.into(),
}
}
if self.gen.settings().option_nullable {
let mut schema_obj = schema.into_object();
schema_obj
.extensions
.insert("nullable".to_owned(), serde_json::json!(true));
schema = Schema::Object(schema_obj);
};
Ok(schema)
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
Ok(self.gen.subschema_for::<()>())
}
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
Ok(Schema::Bool(true))
}
fn serialize_newtype_struct<T: ?Sized>(
self,
name: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::Serialize,
{
let include_title = self.include_title;
let mut result = value.serialize(self);
if include_title {
if let Ok(Schema::Object(ref mut object)) = result {
object.metadata().title = Some(name.to_string());
}
}
result
}
fn serialize_newtype_variant<T: ?Sized>(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::Serialize,
{
Ok(Schema::Bool(true))
}
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
Ok(SerializeSeq {
gen: self.gen,
items: None,
})
}
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
Ok(SerializeTuple {
gen: self.gen,
items: Vec::with_capacity(len),
title: "",
})
}
fn serialize_tuple_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
let title = if self.include_title { name } else { "" };
Ok(SerializeTuple {
gen: self.gen,
items: Vec::with_capacity(len),
title,
})
}
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
Ok(self)
}
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
Ok(SerializeMap {
gen: self.gen,
properties: Map::new(),
current_key: None,
title: "",
})
}
fn serialize_struct(
self,
name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
let title = if self.include_title { name } else { "" };
Ok(SerializeMap {
gen: self.gen,
properties: Map::new(),
current_key: None,
title,
})
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
Ok(self)
}
}
impl serde::ser::SerializeTupleVariant for Serializer<'_> {
type Ok = Schema;
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, _value: &T) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(Schema::Bool(true))
}
}
impl serde::ser::SerializeStructVariant for Serializer<'_> {
type Ok = Schema;
type Error = Error;
fn serialize_field<T: ?Sized>(
&mut self,
_key: &'static str,
_value: &T,
) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(Schema::Bool(true))
}
}
impl serde::ser::SerializeSeq for SerializeSeq<'_> {
type Ok = Schema;
type Error = Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
if self.items != Some(Schema::Bool(true)) {
let schema = value.serialize(Serializer {
gen: self.gen,
include_title: false,
})?;
match &self.items {
None => self.items = Some(schema),
Some(items) => {
if items != &schema {
self.items = Some(Schema::Bool(true))
}
}
}
}
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
let items = self.items.unwrap_or(Schema::Bool(true));
Ok(SchemaObject {
instance_type: Some(InstanceType::Array.into()),
array: Some(Box::new(ArrayValidation {
items: Some(items.into()),
..ArrayValidation::default()
})),
..SchemaObject::default()
}
.into())
}
}
impl serde::ser::SerializeTuple for SerializeTuple<'_> {
type Ok = Schema;
type Error = Error;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
let schema = value.serialize(Serializer {
gen: self.gen,
include_title: false,
})?;
self.items.push(schema);
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
let len = self.items.len().try_into().ok();
let mut schema = SchemaObject {
instance_type: Some(InstanceType::Array.into()),
array: Some(Box::new(ArrayValidation {
items: Some(SingleOrVec::Vec(self.items)),
max_items: len,
min_items: len,
..ArrayValidation::default()
})),
..SchemaObject::default()
};
if !self.title.is_empty() {
schema.metadata().title = Some(self.title.to_owned());
}
Ok(schema.into())
}
}
impl serde::ser::SerializeTupleStruct for SerializeTuple<'_> {
type Ok = Schema;
type Error = Error;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
serde::ser::SerializeTuple::serialize_element(self, value)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
serde::ser::SerializeTuple::end(self)
}
}
impl serde::ser::SerializeMap for SerializeMap<'_> {
type Ok = Schema;
type Error = Error;
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
let json = serde_json::to_string(key)?;
self.current_key = Some(
json.trim_start_matches('"')
.trim_end_matches('"')
.to_string(),
);
Ok(())
}
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
let key = self.current_key.take().unwrap_or_default();
let schema = value.serialize(Serializer {
gen: self.gen,
include_title: false,
})?;
self.properties.insert(key, schema);
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
let mut schema = SchemaObject {
instance_type: Some(InstanceType::Object.into()),
object: Some(Box::new(ObjectValidation {
properties: self.properties,
..ObjectValidation::default()
})),
..SchemaObject::default()
};
if !self.title.is_empty() {
schema.metadata().title = Some(self.title.to_owned());
}
Ok(schema.into())
}
}
impl serde::ser::SerializeStruct for SerializeMap<'_> {
type Ok = Schema;
type Error = Error;
fn serialize_field<T: ?Sized>(
&mut self,
key: &'static str,
value: &T,
) -> Result<(), Self::Error>
where
T: serde::Serialize,
{
let prop_schema = value.serialize(Serializer {
gen: self.gen,
include_title: false,
})?;
self.properties.insert(key.to_string(), prop_schema);
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
serde::ser::SerializeMap::end(self)
}
}