mod adjacently_tagged;
mod internally_tagged;
mod untagged;
use proc_macro2::TokenStream;
use syn::{Generics, Ident};
use crate::{
DocumentArgs, DocumentVariant,
codegen::gen_simple_mapping_impl,
enums::{
adjacently_tagged::gen_adjacently_tagged_enum,
internally_tagged::gen_internally_tagged_enum,
untagged::gen_untagged_enum,
},
error::GeneratorError,
rename::RenameCasing,
};
pub(crate) enum EnumRepresentation<'a> {
Unit,
Untagged {
variants: &'a [DocumentVariant],
rename_all: Option<RenameCasing>,
},
InternallyTagged {
tag: String,
variants: &'a [DocumentVariant],
rename_all: Option<RenameCasing>,
},
AdjacentlyTagged {
tag: String,
content: String,
variants: &'a [DocumentVariant],
rename_all: Option<RenameCasing>,
},
}
pub(crate) fn classify_enum<'a>(
args: &'a DocumentArgs,
variants: &'a [DocumentVariant],
) -> Result<EnumRepresentation<'a>, GeneratorError> {
if variants.iter().all(|v| v.fields.is_unit()) {
return Ok(EnumRepresentation::Unit);
}
if args.content.is_some() && args.tag.is_none() {
return Err(GeneratorError::Custom(
"content attribute requires tag attribute".to_string(),
));
}
match (&args.tag, &args.content) {
(Some(tag), Some(content)) => Ok(EnumRepresentation::AdjacentlyTagged {
tag: tag.clone(),
content: content.clone(),
variants,
rename_all: args.rename_all,
}),
(Some(tag), None) => Ok(EnumRepresentation::InternallyTagged {
tag: tag.clone(),
variants,
rename_all: args.rename_all,
}),
(None, _) => Ok(EnumRepresentation::Untagged {
variants,
rename_all: args.rename_all,
}),
}
}
pub(crate) fn gen_enum_impl(
ident: &Ident,
generics: &Generics,
representation: EnumRepresentation,
) -> Result<TokenStream, GeneratorError> {
match representation {
EnumRepresentation::Unit => Ok(gen_simple_mapping_impl(ident, generics, "text")),
EnumRepresentation::Untagged {
variants,
rename_all,
} => {
let (properties, iterable) = gen_untagged_enum(variants, rename_all)?;
Ok(crate::codegen::gen_mapping_impl(
ident, generics, "object", properties, iterable,
))
}
EnumRepresentation::InternallyTagged {
tag,
variants,
rename_all,
} => {
let (properties, iterable) = gen_internally_tagged_enum(&tag, variants, rename_all)?;
Ok(crate::codegen::gen_mapping_impl(
ident, generics, "object", properties, iterable,
))
}
EnumRepresentation::AdjacentlyTagged {
tag,
content,
variants,
rename_all,
} => {
let (properties, iterable) =
gen_adjacently_tagged_enum(&tag, &content, variants, rename_all)?;
Ok(crate::codegen::gen_mapping_impl(
ident, generics, "object", properties, iterable,
))
}
}
}