use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::{
entity::parse::{CommandDef, CommandKindHint, CommandSource, EntityDef},
utils::marker
};
pub fn generate(entity: &EntityDef) -> TokenStream {
let commands = entity.command_defs();
if commands.is_empty() {
return TokenStream::new();
}
let vis = &entity.vis;
let entity_name = entity.name();
let enum_name = format_ident!("{}CommandResult", entity_name);
let marker = marker::generated();
let variants = generate_variants(entity, commands);
let doc = format!(
"Result enum for [`{}`] command execution.\n\n\
Each variant contains the result of the corresponding command.",
entity_name
);
quote! {
#marker
#[doc = #doc]
#[derive(Debug, Clone)]
#vis enum #enum_name {
#variants
}
}
}
fn generate_variants(entity: &EntityDef, commands: &[CommandDef]) -> TokenStream {
let entity_name = entity.name();
let variants: Vec<TokenStream> = commands
.iter()
.map(|cmd| {
let variant_name = &cmd.name;
let result_type = if let Some(ref custom_type) = cmd.result_type {
Some(quote! { #custom_type })
} else if matches!(cmd.source, CommandSource::None) {
None
} else {
match cmd.kind {
CommandKindHint::Create | CommandKindHint::Update => {
Some(quote! { #entity_name })
}
CommandKindHint::Delete => None, CommandKindHint::Custom => {
if matches!(cmd.source, CommandSource::Custom(_)) {
None } else {
Some(quote! { #entity_name })
}
}
}
};
let doc = format!("Result of {} command.", variant_name);
if let Some(ty) = result_type {
quote! {
#[doc = #doc]
#variant_name(#ty),
}
} else {
quote! {
#[doc = #doc]
#variant_name,
}
}
})
.collect();
quote! { #(#variants)* }
}
pub fn command_result_type(entity: &EntityDef, cmd: &CommandDef) -> Option<TokenStream> {
let entity_name = entity.name();
if let Some(ref custom_type) = cmd.result_type {
Some(quote! { #custom_type })
} else if matches!(cmd.source, CommandSource::None) {
None
} else {
match cmd.kind {
CommandKindHint::Create | CommandKindHint::Update => Some(quote! { #entity_name }),
CommandKindHint::Delete => None,
CommandKindHint::Custom => {
if matches!(cmd.source, CommandSource::Custom(_)) {
None
} else {
Some(quote! { #entity_name })
}
}
}
}
}