{{>partial_header}}
use crate::models;
use serde::{Deserialize, Serialize};
{{#models}}
{{#model}}
{{^isEnum}}{{#vendorExtensions.x-rust-has-byte-array}}
use serde_with::serde_as;
{{/vendorExtensions.x-rust-has-byte-array}}{{/isEnum}}
{{#description}}
/// {{{classname}}} : {{{description}}}
{{/description}}
{{!-- for enum schemas --}}
{{#isEnum}}
{{#description}}
/// {{{.}}}
{{/description}}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum {{{classname}}} {
{{#allowableValues}}
{{#enumVars}}
    #[serde(rename = "{{{value}}}")]
    {{{name}}},
{{/enumVars}}{{/allowableValues}}
}

impl std::fmt::Display for {{{classname}}} {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            {{#allowableValues}}
            {{#enumVars}}
            Self::{{{name}}} => write!(f, "{{{value}}}"),
            {{/enumVars}}
            {{/allowableValues}}
        }
    }
}

impl Default for {{{classname}}} {
    fn default() -> {{{classname}}} {
        {{#allowableValues}}
        Self::{{ enumVars.0.name }}
        {{/allowableValues}}
    }
}
{{/isEnum}}
{{!-- for schemas that have a discriminator --}}
{{#discriminator}}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "{{{propertyBaseName}}}")]
pub enum {{{classname}}} {
    {{^oneOf}}
    {{#mappedModels}}
    #[serde(rename="{{mappingName}}")]
    {{{modelName}}} {
    {{#vars}}
        {{#description}}
        /// {{{.}}}
        {{/description}}
        #[serde(rename = "{{{baseName}}}"{{^required}}, skip_serializing_if = "Option::is_none"{{/required}})]
        {{{name}}}: {{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{^required}}Option<{{/required}}{{#isEnum}}{{{enumName}}}{{/isEnum}}{{^isEnum}}{{#isModel}}{{^avoidBoxedModels}}Box<{{/avoidBoxedModels}}{{{dataType}}}{{^avoidBoxedModels}}>{{/avoidBoxedModels}}{{/isModel}}{{^isModel}}{{{dataType}}}{{/isModel}}{{/isEnum}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{^required}}>{{/required}},
    {{/vars}}
    },
    {{/mappedModels}}
    {{/oneOf}}
    {{^oneOf.isEmpty}}
    {{#composedSchemas.oneOf}}
    {{#description}}
    /// {{{.}}}
    {{/description}}
    {{#baseName}}
    #[serde(rename="{{{.}}}")]
    {{/baseName}}
    {{{name}}}({{#isModel}}{{^avoidBoxedModels}}Box<{{/avoidBoxedModels}}{{/isModel}}{{{dataType}}}{{#isModel}}{{^avoidBoxedModels}}>{{/avoidBoxedModels}}{{/isModel}}),
    {{/composedSchemas.oneOf}}
    {{/oneOf.isEmpty}}
}

impl Default for {{classname}} {
    fn default() -> Self {
        {{^oneOf}}{{#mappedModels}}{{#-first}}Self::{{modelName}} {
        {{#vars}}
            {{{name}}}: Default::default(),
        {{/vars}}
        }{{/-first}}{{/mappedModels}}
        {{/oneOf}}{{^oneOf.isEmpty}}{{#composedSchemas.oneOf}}{{#-first}}Self::{{{name}}}(Default::default()){{/-first}}{{/composedSchemas.oneOf}}{{/oneOf.isEmpty}}
    }
}

{{/discriminator}}
{{!-- for non-enum schemas --}}
{{^isEnum}}
{{^discriminator}}
{{#vendorExtensions.x-rust-has-byte-array}}#[serde_as]
{{/vendorExtensions.x-rust-has-byte-array}}{{#oneOf.isEmpty}}#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct {{{classname}}} {
{{#vars}}
    {{#description}}
    /// {{{.}}}
    {{/description}}
    {{#isByteArray}}
    {{#required}}#[serde_as(as = "serde_with::base64::Base64")]{{/required}}{{^required}}#[serde_as(as = "Option<serde_with::base64::Base64>")]{{/required}}
    {{/isByteArray}}
    #[serde(rename = "{{{baseName}}}"{{^required}}{{#isNullable}}, default, with = "::serde_with::rust::double_option"{{/isNullable}}{{/required}}{{^required}}, skip_serializing_if = "Option::is_none"{{/required}}{{#required}}{{#isNullable}}, deserialize_with = "Option::deserialize"{{/isNullable}}{{/required}})]
    pub {{{name}}}: {{#isNullable}}Option<{{/isNullable}}{{^required}}Option<{{/required}}{{#isEnum}}{{#isArray}}{{#uniqueItems}}std::collections::HashSet<{{/uniqueItems}}{{^uniqueItems}}Vec<{{/uniqueItems}}{{/isArray}}{{{enumName}}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{#isModel}}{{^avoidBoxedModels}}Box<{{/avoidBoxedModels}}{{{dataType}}}{{^avoidBoxedModels}}>{{/avoidBoxedModels}}{{/isModel}}{{^isModel}}{{#isByteArray}}Vec<u8>{{/isByteArray}}{{^isByteArray}}{{{dataType}}}{{/isByteArray}}{{/isModel}}{{/isEnum}}{{#isNullable}}>{{/isNullable}}{{^required}}>{{/required}},
{{/vars}}
}

impl {{{classname}}} {
    {{#description}}
    /// {{{.}}}
    {{/description}}
    pub fn new({{#requiredVars}}{{{name}}}: {{#isNullable}}Option<{{/isNullable}}{{#isEnum}}{{#isArray}}{{#uniqueItems}}std::collections::HashSet<{{/uniqueItems}}{{^uniqueItems}}Vec<{{/uniqueItems}}{{/isArray}}{{{enumName}}}{{#isArray}}>{{/isArray}}{{/isEnum}}{{^isEnum}}{{#isByteArray}}Vec<u8>{{/isByteArray}}{{^isByteArray}}{{{dataType}}}{{/isByteArray}}{{/isEnum}}{{#isNullable}}>{{/isNullable}}{{^-last}}, {{/-last}}{{/requiredVars}}) -> {{{classname}}} {
        {{{classname}}} {
            {{#vars}}
            {{{name}}}{{^required}}: None{{/required}}{{#required}}{{#isModel}}{{^avoidBoxedModels}}: {{^isNullable}}Box::new({{{name}}}){{/isNullable}}{{#isNullable}}{{{name}}}.map(Box::new){{/isNullable}}{{/avoidBoxedModels}}{{/isModel}}{{/required}},
            {{/vars}}
        }
    }
}
{{/oneOf.isEmpty}}
{{^oneOf.isEmpty}}
{{! TODO: add other vars that are not part of the oneOf}}
{{#description}}
/// {{{.}}}
{{/description}}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum {{classname}} {
{{#composedSchemas.oneOf}}
    {{#description}}
    /// {{{.}}}
    {{/description}}
    {{{name}}}({{#isModel}}{{^avoidBoxedModels}}Box<{{/avoidBoxedModels}}{{/isModel}}{{{dataType}}}{{#isModel}}{{^avoidBoxedModels}}>{{/avoidBoxedModels}}{{/isModel}}),
{{/composedSchemas.oneOf}}
}

impl Default for {{classname}} {
    fn default() -> Self {
        {{#composedSchemas.oneOf}}{{#-first}}Self::{{{name}}}(Default::default()){{/-first}}{{/composedSchemas.oneOf}}
    }
}
{{/oneOf.isEmpty}}
{{/discriminator}}
{{/isEnum}}
{{!-- for properties that are of enum type --}}
{{#vars}}
{{#isEnum}}
{{#description}}
/// {{{.}}}
{{/description}}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum {{{enumName}}} {
{{#allowableValues}}
{{#enumVars}}
    #[serde(rename = "{{{value}}}")]
    {{{name}}},
{{/enumVars}}
{{/allowableValues}}
}

impl Default for {{{enumName}}} {
    fn default() -> {{{enumName}}} {
        {{#allowableValues}}
        Self::{{ enumVars.0.name }}
        {{/allowableValues}}
    }
}
{{/isEnum}}
{{/vars}}

{{/model}}
{{/models}}
