use crate::core::ir::{EnumDef, FieldDef, TypeRef};
pub fn gen_enum(enum_def: &EnumDef) -> String {
let has_data = enum_def.variants.iter().any(|v| !v.fields.is_empty());
let first_variant = enum_def.variants.first().map(|v| v.name.as_str()).unwrap_or("Default");
let default_variant = enum_def
.variants
.iter()
.find(|v| v.is_default)
.map(|v| v.name.as_str())
.unwrap_or(first_variant);
let first_variant_default = if has_data {
let default = enum_def
.variants
.iter()
.find(|v| v.is_default)
.unwrap_or_else(|| enum_def.variants.first().unwrap());
if default.fields.is_empty() {
String::new()
} else if enum_def.serde_untagged && default.is_tuple {
let field_defaults: Vec<&str> = default.fields.iter().map(|_| "Default::default()").collect();
format!("({})", field_defaults.join(", "))
} else {
let field_defaults: Vec<String> = default
.fields
.iter()
.map(|f| format!("{}: Default::default()", f.name))
.collect();
format!(" {{ {} }}", field_defaults.join(", "))
}
} else {
String::new()
};
let variants: Vec<minijinja::Value> = enum_def
.variants
.iter()
.map(|variant| {
let fields: Vec<minijinja::Value> = variant
.fields
.iter()
.map(|f| {
minijinja::context! {
name => &f.name,
field_type => field_type_for_serde(f),
}
})
.collect();
minijinja::context! {
name => &variant.name,
serde_rename => &variant.serde_rename,
fields => &fields,
is_tuple => variant.is_tuple,
snake_name => crate::codegen::naming::pascal_to_snake(&variant.name),
}
})
.collect();
crate::backends::magnus::template_env::render(
"enum_magnus.rs.jinja",
minijinja::context! {
enum_name => &enum_def.name,
has_data => has_data,
serde_tag => &enum_def.serde_tag,
serde_untagged => enum_def.serde_untagged,
serde_rename_all => &enum_def.serde_rename_all,
variants => &variants,
first_variant => first_variant,
default_variant => default_variant,
first_variant_default => &first_variant_default,
},
)
}
fn field_type_for_serde_inner(ty: &TypeRef) -> String {
use crate::core::ir::PrimitiveType;
match ty {
TypeRef::String | TypeRef::Char | TypeRef::Path => "String".to_string(),
TypeRef::Primitive(PrimitiveType::Bool) => "bool".to_string(),
TypeRef::Primitive(PrimitiveType::U8) => "u8".to_string(),
TypeRef::Primitive(PrimitiveType::U16) => "u16".to_string(),
TypeRef::Primitive(PrimitiveType::U32) => "u32".to_string(),
TypeRef::Primitive(PrimitiveType::U64) => "u64".to_string(),
TypeRef::Primitive(PrimitiveType::Usize) => "usize".to_string(),
TypeRef::Primitive(PrimitiveType::I8) => "i8".to_string(),
TypeRef::Primitive(PrimitiveType::I16) => "i16".to_string(),
TypeRef::Primitive(PrimitiveType::I32) => "i32".to_string(),
TypeRef::Primitive(PrimitiveType::I64) => "i64".to_string(),
TypeRef::Primitive(PrimitiveType::Isize) => "isize".to_string(),
TypeRef::Primitive(PrimitiveType::F32) => "f32".to_string(),
TypeRef::Primitive(PrimitiveType::F64) => "f64".to_string(),
TypeRef::Duration => "u64".to_string(),
TypeRef::Bytes => "Vec<u8>".to_string(),
TypeRef::Named(n) => n.clone(),
TypeRef::Vec(inner) => format!("Vec<{}>", field_type_for_serde_inner(inner)),
TypeRef::Map(_, _) => "String".to_string(),
TypeRef::Optional(inner) => format!("Option<{}>", field_type_for_serde_inner(inner)),
_ => "String".to_string(),
}
}
pub(super) fn field_type_for_serde(field: &FieldDef) -> String {
serde_field_type(&field.ty, field.optional)
}
pub(super) fn serde_field_type(ty: &TypeRef, optional: bool) -> String {
let base = field_type_for_serde_inner(ty);
if optional { format!("Option<{base}>") } else { base }
}
pub fn gen_data_enum_variant_constructors(enum_def: &EnumDef) -> String {
let constructors = crate::codegen::generators::collect_variant_constructors(enum_def);
if constructors.is_empty() {
return String::new();
}
let rendered: Vec<minijinja::Value> = constructors
.iter()
.map(|ctor| {
let params = ctor
.params
.iter()
.map(|p| format!("{}: {}", p.name, serde_field_type(&p.ty, p.optional)))
.collect::<Vec<_>>()
.join(", ");
let field_inits = ctor
.params
.iter()
.map(|p| p.name.as_str())
.collect::<Vec<_>>()
.join(", ");
minijinja::context! {
rust_fn_name => format!("_factory_{}", ctor.snake_name),
variant_name => ctor.variant_name,
params => params,
field_inits => field_inits,
}
})
.collect();
crate::backends::magnus::template_env::render(
"enum_variant_constructor.rs.jinja",
minijinja::context! {
enum_name => &enum_def.name,
constructors => rendered,
},
)
}
pub fn data_enum_variant_constructor_registrations(enum_def: &EnumDef) -> Vec<(String, String, i32)> {
crate::codegen::generators::collect_variant_constructors(enum_def)
.into_iter()
.map(|ctor| {
let arity = ctor.params.len() as i32;
(ctor.snake_name.clone(), format!("_factory_{}", ctor.snake_name), arity)
})
.collect()
}