dade_derive 0.1.4

dade is data definition for Rust structures.
Documentation
use proc_macro2::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::{Ident, Lit, LitFloat, LitInt, LitStr, Token};

pub(crate) trait ToToken {
    fn to_token(&self, variable: &Ident) -> TokenStream;
}

pub(crate) trait ToSchema {
    fn to_schema(&self) -> TokenStream;
}

pub(crate) struct MinLengthTerm {
    pub value: LitInt,
}

impl ToToken for MinLengthTerm {
    fn to_token(&self, variable: &Ident) -> TokenStream {
        let val = &self.value;
        quote! { #variable.len() >= #val }
    }
}

impl ToSchema for MinLengthTerm {
    fn to_schema(&self) -> TokenStream {
        let val = &self.value;
        quote! {
            "minLength".to_string(),
            dade::JsonValue::Number(dade::Number::from(#val))
        }
    }
}

pub(crate) struct MaxLengthTerm {
    pub value: LitInt,
}

impl ToToken for MaxLengthTerm {
    fn to_token(&self, variable: &Ident) -> TokenStream {
        let val = &self.value;
        quote! { #variable.len() <= #val }
    }
}

impl ToSchema for MaxLengthTerm {
    fn to_schema(&self) -> TokenStream {
        let val = &self.value;
        quote! {
            "maxLength".to_string(),
            dade::JsonValue::Number(dade::Number::from(#val))
        }
    }
}

pub(crate) struct MinItemsTerm {
    pub value: LitInt,
}

impl ToToken for MinItemsTerm {
    fn to_token(&self, variable: &Ident) -> TokenStream {
        let val = &self.value;
        quote! { #variable.len() >= #val }
    }
}

impl ToSchema for MinItemsTerm {
    fn to_schema(&self) -> TokenStream {
        let val = &self.value;
        quote! {
            "minItems".to_string(),
            dade::JsonValue::Number(dade::Number::from(#val))
        }
    }
}

pub(crate) struct MaxItemsTerm {
    pub value: LitInt,
}

impl ToToken for MaxItemsTerm {
    fn to_token(&self, variable: &Ident) -> TokenStream {
        let val = &self.value;
        quote! { #variable.len() <= #val }
    }
}
impl ToSchema for MaxItemsTerm {
    fn to_schema(&self) -> TokenStream {
        let val = &self.value;
        quote! {
            "maxItems".to_string(),
            dade::JsonValue::Number(dade::Number::from(#val))
        }
    }
}

pub(crate) enum LitNumber {
    Int(LitInt),
    Float(LitFloat),
}

impl Parse for LitNumber {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let lit: Lit = input.parse()?;
        match lit {
            Lit::Int(val) => Ok(LitNumber::Int(val)),
            Lit::Float(val) => Ok(LitNumber::Float(val)),
            _ => Err(input.error("Un support Type")),
        }
    }
}

impl quote::ToTokens for LitNumber {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            LitNumber::Int(val) => val.to_tokens(tokens),
            LitNumber::Float(val) => val.to_tokens(tokens),
        }
    }
}

impl ToString for LitNumber {
    fn to_string(&self) -> String {
        match self {
            LitNumber::Int(val) => val.to_string(),
            LitNumber::Float(val) => val.to_string(),
        }
    }
}

pub(crate) struct GtTerm {
    pub value: LitNumber,
}

impl ToToken for GtTerm {
    fn to_token(&self, variable: &Ident) -> TokenStream {
        let val = &self.value;
        quote! { #variable > #val }
    }
}

impl ToSchema for GtTerm {
    fn to_schema(&self) -> TokenStream {
        let val = &self.value;
        quote! {
            "exclusiveMinimum".to_string(),
            dade::JsonValue::Number(dade::Number::from(#val))
        }
    }
}

pub(crate) struct GeTerm {
    pub value: LitNumber,
}

impl ToToken for GeTerm {
    fn to_token(&self, variable: &Ident) -> TokenStream {
        let val = &self.value;
        quote! { #variable >= #val }
    }
}

impl ToSchema for GeTerm {
    fn to_schema(&self) -> TokenStream {
        let val = &self.value;
        quote! {
            "minimum".to_string(),
            dade::JsonValue::Number(dade::Number::from(#val))
        }
    }
}

pub(crate) struct LtTerm {
    pub value: LitNumber,
}

impl ToToken for LtTerm {
    fn to_token(&self, variable: &Ident) -> TokenStream {
        let val = &self.value;
        quote! { #variable < #val }
    }
}

impl ToSchema for LtTerm {
    fn to_schema(&self) -> TokenStream {
        let val = &self.value;
        quote! {
            "exclusiveMaximum".to_string(),
            dade::JsonValue::Number(dade::Number::from(#val))
        }
    }
}

pub(crate) struct LeTerm {
    pub value: LitNumber,
}

impl LeTerm {
    pub fn to_token(&self, variable: &Ident) -> TokenStream {
        let val = &self.value;
        quote! { #variable <= #val }
    }
}

impl ToSchema for LeTerm {
    fn to_schema(&self) -> TokenStream {
        let val = &self.value;
        quote! {
            "maximum".to_string(),
            dade::JsonValue::Number(dade::Number::from(#val))
        }
    }
}

pub(crate) struct AliasTerm {
    pub value: LitStr,
}

pub(crate) struct IdentDefaultTerm {
    pub value: Ident,
}

pub(crate) struct LitDefaultTerm {
    pub value: Lit,
}

pub(crate) enum DefaultTerm {
    Ident(IdentDefaultTerm),
    Lit(LitDefaultTerm),
}

impl Parse for DefaultTerm {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        if input.peek(Ident) {
            let ident: Ident = input.parse()?;
            return Ok(DefaultTerm::Ident(IdentDefaultTerm { value: ident }));
        }
        let lit: Lit = input.parse()?;
        Ok(DefaultTerm::Lit(LitDefaultTerm { value: lit }))
    }
}

pub(crate) struct ValidateTerm {
    pub value: Ident,
}

pub(crate) enum Term {
    MinLength(MinLengthTerm),
    MaxLength(MaxLengthTerm),
    MinItems(MinItemsTerm),
    MaxItems(MaxItemsTerm),
    Gt(GtTerm),
    Ge(GeTerm),
    Lt(LtTerm),
    Le(LeTerm),
    Alias(AliasTerm),
    Default(DefaultTerm),
    Validate(ValidateTerm),
}

impl Parse for Term {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let ident = input
            .parse()
            .map(|ident: Ident| ident.to_string())
            .or_else(|_| {
                input
                    .parse()
                    .map(|_: Token![default]| "default".to_string())
            })?;
        let _eq_token: Token![=] = input.parse()?;
        if ident == "min_length" {
            Ok(Term::MinLength(MinLengthTerm {
                value: input.parse()?,
            }))
        } else if ident == "max_length" {
            Ok(Term::MaxLength(MaxLengthTerm {
                value: input.parse()?,
            }))
        } else if ident == "min_items" {
            Ok(Term::MinItems(MinItemsTerm {
                value: input.parse()?,
            }))
        } else if ident == "max_items" {
            Ok(Term::MaxItems(MaxItemsTerm {
                value: input.parse()?,
            }))
        } else if ident == "gt" {
            Ok(Term::Gt(GtTerm {
                value: input.parse()?,
            }))
        } else if ident == "ge" {
            Ok(Term::Ge(GeTerm {
                value: input.parse()?,
            }))
        } else if ident == "lt" {
            Ok(Term::Lt(LtTerm {
                value: input.parse()?,
            }))
        } else if ident == "le" {
            Ok(Term::Le(LeTerm {
                value: input.parse()?,
            }))
        } else if ident == "alias" {
            Ok(Term::Alias(AliasTerm {
                value: input.parse()?,
            }))
        } else if ident == "default" {
            let term: DefaultTerm = input.parse()?;
            Ok(Term::Default(term))
        } else if ident == "validate" {
            Ok(Term::Validate(ValidateTerm {
                value: input.parse()?,
            }))
        } else {
            Err(input.error("un support type"))
        }
    }
}

pub(crate) enum Condition {
    MinLength(MinLengthTerm),
    MaxLength(MaxLengthTerm),
    MinItems(MinItemsTerm),
    MaxItems(MaxItemsTerm),
    Gt(GtTerm),
    Ge(GeTerm),
    Lt(LtTerm),
    Le(LeTerm),
}