use std::collections::HashMap;
use std::string::ToString;
use heck::MixedCase;
use serde::ser::Error;
use serde::ser::SerializeMap;
use serde::Serialize;
use serde::Serializer;
use crate::dsl::schema::object_types::bounds::ArrayItemObjectBounds;
use crate::dsl::schema::object_types::bounds::ArrayObjectBounds;
use crate::dsl::schema::object_types::bounds::ArrayUniqueItemBound;
use crate::dsl::schema::object_types::bounds::DefaultValue;
use crate::dsl::schema::object_types::bounds::EnumerationValue;
use crate::dsl::schema::object_types::bounds::IntegerBound;
use crate::dsl::schema::object_types::bounds::IntegerObjectBounds;
use crate::dsl::schema::object_types::bounds::StringLength;
use crate::dsl::schema::object_types::bounds::StringObjectBounds;
use crate::dsl::schema::object_types::RawObjectType;
use crate::dsl::schema::object_types::ObjectType;
use crate::dsl::schema::object_types::bounds::BooleanObjectBounds;
use crate::dsl::schema::KeysValues;
impl Serialize for EnumerationValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(None)?;
if self.annotations.title.is_some() {
map.serialize_entry("title", &self.annotations.title)?;
map.serialize_entry("enum", &vec![&self.value])?;
}
map.end()
}
}
pub fn serialize_object_type<O, E, S>(object_type: &ObjectType, map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
let raw_type = object_type.inner_raw();
let default = object_type.data().default_value();
map.serialize_entry("type", object_type_name(raw_type))?;
serialize_default(default, map)?;
match raw_type {
RawObjectType::Object => {
map.serialize_entry(
"additionalProperties",
&object_type.data().allow_additional_properties(),
)?;
}
RawObjectType::Boolean(object_bounds) => serialize_boolean(object_bounds, map)?,
RawObjectType::String(object_bounds) => serialize_string(object_bounds, map)?,
RawObjectType::Text(object_bounds) => serialize_string(object_bounds, map)?,
RawObjectType::Password(object_bounds) => serialize_password(object_bounds, map)?,
RawObjectType::Integer(object_bounds) => serialize_integer(object_bounds, map)?,
RawObjectType::Number(object_bounds) => serialize_integer(object_bounds, map)?,
RawObjectType::Port(object_bounds) => serialize_integer(object_bounds, map)?,
RawObjectType::Array(object_bounds) => serialize_array(object_bounds, map)?,
RawObjectType::Stringlist(object_bounds) => serialize_array(object_bounds, map)?,
RawObjectType::Hostname(object_bounds) => serialize_string_with_format("hostname", object_bounds, map)?,
RawObjectType::Datetime(object_bounds) => serialize_string_with_format("date-time", object_bounds, map)?,
RawObjectType::Date(object_bounds) => serialize_string_with_format("date", object_bounds, map)?,
RawObjectType::Time(object_bounds) => serialize_string_with_format("time", object_bounds, map)?,
RawObjectType::Email(object_bounds) => serialize_string_with_format("email", object_bounds, map)?,
RawObjectType::IPV4(object_bounds) => serialize_string_with_format("ipv4", object_bounds, map)?,
RawObjectType::IPV6(object_bounds) => serialize_string_with_format("ipv6", object_bounds, map)?,
RawObjectType::URI(object_bounds) => serialize_string_with_format("uri", object_bounds, map)?,
RawObjectType::File(object_bounds) => serialize_string_with_format("data-url", object_bounds, map)?,
RawObjectType::DnsmasqAddress(object_bounds) => {
serialize_string_with_format("dnsmasq-address", object_bounds, map)?
}
RawObjectType::ChronyAddress(object_bounds) => {
serialize_string_with_format("chrony-address", object_bounds, map)?
}
RawObjectType::IpTablesAddress(object_bounds) => {
serialize_string_with_format("iptables-address", object_bounds, map)?
}
};
Ok(())
}
pub fn object_type_name(object_type: &RawObjectType) -> &str {
match object_type {
RawObjectType::Object => "object",
RawObjectType::Boolean(_) => "boolean",
RawObjectType::String(_) => "string",
RawObjectType::Text(_) => "string",
RawObjectType::Password(_) => "string",
RawObjectType::Integer(_) => "integer",
RawObjectType::Number(_) => "number",
RawObjectType::Port(_) => "integer",
RawObjectType::Array(_) => "array",
RawObjectType::Stringlist(_) => "array",
RawObjectType::Hostname(_) => "string",
RawObjectType::Datetime(_) => "string",
RawObjectType::Date(_) => "string",
RawObjectType::Time(_) => "string",
RawObjectType::Email(_) => "string",
RawObjectType::IPV4(_) => "string",
RawObjectType::IPV6(_) => "string",
RawObjectType::URI(_) => "string",
RawObjectType::File(_) => "string",
RawObjectType::DnsmasqAddress(_) => "string",
RawObjectType::ChronyAddress(_) => "string",
RawObjectType::IpTablesAddress(_) => "string",
}
}
pub fn serialize_keys_values<O, E, S>(keys_values: &KeysValues, map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
let mut pattern_properties = HashMap::new();
pattern_properties.insert(keys_values.keys.pattern.to_string(), &keys_values.values);
map.serialize_entry("patternProperties", &pattern_properties)?;
Ok(())
}
fn serialize_default<O, E, S>(default: &Option<DefaultValue>, map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
for value in default {
map.serialize_entry("default", value.value())?;
}
Ok(())
}
fn serialize_boolean<O, E, S>(bounds: &Option<BooleanObjectBounds>, map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
if let Some(bounds) = bounds {
serialize_enum_bounds(&bounds.0, map)?;
}
Ok(())
}
fn serialize_string<O, E, S>(bounds: &Option<StringObjectBounds>, map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
for enumeration_values in bounds {
serialize_string_bounds(&enumeration_values, map)?;
}
Ok(())
}
fn serialize_string_with_format<O, E, S>(
format: &str,
bounds: &Option<StringObjectBounds>,
map: &mut S,
) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
map.serialize_entry("format", format)?;
serialize_string(bounds, map)
}
fn serialize_password<O, E, S>(bounds: &Option<StringObjectBounds>, map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
map.serialize_entry("writeOnly", &true)?;
serialize_string(bounds, map)?;
Ok(())
}
fn serialize_integer_bound<O, E, S>(name: &str, bound: &Option<IntegerBound>, map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
if let Some(value) = bound {
match value {
IntegerBound::Inclusive(value) => map.serialize_entry(name, &value)?,
IntegerBound::Exclusive(value) => {
map.serialize_entry(name, &value)?;
map.serialize_entry(&("exclusive ".to_string() + name).to_mixed_case(), &true)?;
}
}
}
Ok(())
}
fn serialize_array<O, E, S>(bounds: &Option<ArrayObjectBounds>, map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
if let Some(bounds) = bounds {
if let Some(max) = bounds.maximum_number_of_items {
map.serialize_entry("maxItems", &max)?;
}
if let Some(min) = bounds.minimum_number_of_items {
map.serialize_entry("minItems", &min)?;
}
if let Some(ref items) = bounds.items {
match items {
ArrayItemObjectBounds::AllItems(schema) => {
map.serialize_entry("items", &schema)?;
}
ArrayItemObjectBounds::AnyItems(schemas) => {
let mut wrapper = HashMap::new();
wrapper.insert("oneOf", schemas);
map.serialize_entry("items", &wrapper)?;
}
}
}
if let Some(ref unique_items) = bounds.unique_items {
match unique_items {
ArrayUniqueItemBound::All => {
map.serialize_entry("uniqueItems", &true)?;
}
ArrayUniqueItemBound::Specific(items) => {
map.serialize_entry("$$uniqueItemProperties", items)?;
}
}
}
}
Ok(())
}
fn serialize_integer<O, E, S>(bounds: &Option<IntegerObjectBounds>, map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
if let Some(bounds) = bounds {
match bounds {
IntegerObjectBounds::Conditions(conditions) => {
serialize_integer_bound("maximum", &conditions.maximum, map)?;
serialize_integer_bound("minimum", &conditions.minimum, map)?;
if let Some(multiple_of) = conditions.multiple_of {
map.serialize_entry("multipleOf", &multiple_of)?;
}
}
IntegerObjectBounds::Enumeration(list) => serialize_enum_bounds(list, map)?,
}
}
Ok(())
}
fn serialize_string_bounds<O, E, S>(string_bounds: &StringObjectBounds, map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
match string_bounds {
StringObjectBounds::Enumeration(values) => serialize_enum_bounds(values, map)?,
StringObjectBounds::Value(value_bounds) => {
if let Some(pattern) = &value_bounds.pattern {
map.serialize_entry("pattern", pattern.as_str())?
}
if let Some(length) = &value_bounds.length {
serialize_length_bounds(length, map)?
}
}
}
Ok(())
}
fn serialize_enum_bounds<O, E, S>(values: &[EnumerationValue], map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
if values.len() == 1 {
serialize_singular_constant_value(&values[0], map)?;
} else {
serialize_multiple_enum_values(&values, map)?;
}
Ok(())
}
fn serialize_length_bounds<O, E, S>(length_bounds: &StringLength, map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
if let Some(maximum) = length_bounds.maximum {
map.serialize_entry("maxLength", &maximum)?;
}
if let Some(minimum) = length_bounds.minimum {
map.serialize_entry("minLength", &minimum)?;
}
Ok(())
}
fn serialize_multiple_enum_values<O, E, S>(enumeration_values: &[EnumerationValue], map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
if !enumeration_values.is_empty() {
map.serialize_entry("oneOf", &enumeration_values)?;
}
Ok(())
}
fn serialize_singular_constant_value<O, E, S>(constant: &EnumerationValue, map: &mut S) -> Result<(), E>
where
E: Error,
S: SerializeMap<Ok = O, Error = E>,
{
Ok(map.serialize_entry("enum", &vec![constant.value.clone()]))?
}