use crate::utils::{type_to_ident, type_to_ident_unnamed};
use convert_case::{Case, Casing};
use quote::quote;
use std::str::FromStr;
use syn::Fields;
pub struct SchemaEnum(syn::ItemEnum);
impl SchemaEnum {
pub fn new(input: syn::ItemEnum) -> Self {
Self(input)
}
}
impl SchemaEnum {
pub fn render(self) -> proc_macro::TokenStream {
let mut enm = self.0.clone();
let enum_name = &enm.ident;
let mut schema_fn_schema_stream: proc_macro2::TokenStream = proc_macro2::TokenStream::new();
let mut schema_fn_schema_value_stream: proc_macro2::TokenStream =
proc_macro2::TokenStream::new();
let mut schema_fn_schema_variants = vec![format!("let mut variants = VecMap::<String, Schema>::new();")];
enm.variants.iter_mut().for_each(|variant| {
let variant_name = &variant.ident;
let formated_variant_name = variant_name
.to_string()
.to_case(Case::Snake)
.parse::<proc_macro2::TokenStream>()
.unwrap();
let mut schema_fn_schema_value_variant = vec![];
if matches!(variant.fields, Fields::Unit) {
schema_fn_schema_variants.push(format!(
"variants.insert(String::from(\"{}\"), Schema::Null);",
variant_name
));
schema_fn_schema_value_variant.push(format!(
"Self::{} => SchemaValue::Enum(String::from(\"{}\"), Box::new(SchemaValue::Null)),",
variant_name, variant_name
));
} else {
schema_fn_schema_variants.push(format!(
"let mut {} = VecMap::new();",
formated_variant_name
));
schema_fn_schema_value_variant.push(format!("Self::{} ", variant_name));
schema_fn_schema_value_variant.push(format!(
"let mut {} = VecMap::new();",
formated_variant_name
));
if let Fields::Named(fields) = &mut variant.fields {
schema_fn_schema_value_variant[0].push_str("{");
fields.named.iter_mut().for_each(|field| {
let ident = field.ident.as_ref().unwrap().to_string();
let type_ident = type_to_ident(&ident, &field.ty).unwrap();
schema_fn_schema_variants.push(format!(
"{}.insert(String::from(\"{}\"), {}::schema());",
formated_variant_name, ident, type_ident
));
schema_fn_schema_value_variant[0].push_str(&format!("{}, ", ident));
schema_fn_schema_value_variant.push(format!(
"{}.insert( String::from(\"{}\"), {}.schema_value() );",
formated_variant_name, ident, ident
));
});
schema_fn_schema_value_variant[0].push_str("} => {");
} else if let Fields::Unnamed(fields) = &mut variant.fields {
schema_fn_schema_value_variant[0].push_str("(");
fields.unnamed.iter_mut().enumerate().for_each(|(i, f)| {
let type_ident = type_to_ident_unnamed(i, &f.ty).unwrap();
schema_fn_schema_variants.push(format!(
"{}.insert(String::from(\"{}\"), {}::schema());",
formated_variant_name, i, type_ident
));
schema_fn_schema_value_variant[0].push_str(&format!("item_{}, ", i));
schema_fn_schema_value_variant.push(format!(
"{}.insert( String::from(\"{}\"), item_{}.schema_value() );",
formated_variant_name, i, i
));
});
schema_fn_schema_value_variant[0].push_str(") => {");
}
schema_fn_schema_variants.push(format!(
"variants.insert(String::from(\"{}\"), Schema::Object({}));",
variant_name, formated_variant_name
));
schema_fn_schema_value_variant.push(format!(
"SchemaValue::Enum(String::from(\"{}\"), Box::new(SchemaValue::Object({})))",
variant_name, formated_variant_name
));
schema_fn_schema_value_variant.push("}".to_string());
}
schema_fn_schema_value_stream.extend::<proc_macro2::TokenStream>(
proc_macro2::TokenStream::from_str(
&schema_fn_schema_value_variant
.into_iter()
.fold(String::new(), |acc, s| acc + &s),
)
.unwrap(),
);
});
schema_fn_schema_variants.push("Schema::Enum(variants)".to_string());
schema_fn_schema_stream.extend::<proc_macro2::TokenStream>(
proc_macro2::TokenStream::from_str(
&schema_fn_schema_variants
.into_iter()
.fold(String::new(), |acc, s| acc + &s),
)
.unwrap(),
);
let stream: proc_macro2::TokenStream = quote! {
impl ToSchema for #enum_name {
fn schema() -> Schema {
#schema_fn_schema_stream
}
fn schema_value(&self) -> SchemaValue {
match self {
#schema_fn_schema_value_stream
_ => {
panic!("Unsupported version");
}
}
}
}
};
stream.into()
}
}