use protox::prost_reflect::MessageDescriptor;
use crate::codegen::{Generator, case, enums, module, one_of, utils};
pub(crate) fn generate(
ctx: &Generator,
parent: &mut module::Module,
module_path: &str,
ty: MessageDescriptor,
) {
if ty.is_map_entry() {
return;
}
let qualified_name = ty.full_name();
if ctx.resolve_ident(qualified_name).is_some() {
return;
}
if !ctx.filter(qualified_name) {
return;
}
if let Some(one_of) = one_of::is_unwrappable_one_of(&ty) {
one_of::generate_unwrapped(ctx, parent, module_path, one_of);
return;
}
tracing::info!("generating message: {qualified_name}");
let attributes = ctx.attributes(qualified_name);
let module = module::create_child(parent, module_path);
let ty_name = case::convert(ty.name(), case::Case::Pascal);
let name = quote::format_ident!("{}", ty_name);
let mut body = quote::quote!();
for field in ty.fields() {
let id = field.number();
if let Some(one_of) = one_of::fetch_one_of(&field) {
let Some(first) = one_of.fields().next() else {
continue;
};
if first.name() != field.name() {
continue;
}
let field_name = case::convert(one_of.name(), case::Case::Snake);
let field_name = quote::format_ident!("{}", field_name);
let field_type = utils::resolve_message(ctx, qualified_name, one_of.full_name());
body.extend(quote::quote! {
#[gin(id = 0 )]
pub #field_name: #field_type,
});
continue;
}
let field_name = quote::format_ident!("{}", field.name());
let field_type = utils::field_type(ctx, qualified_name, &field);
let proto_attributes = utils::proto_attribute(&field);
body.extend(quote::quote! {
#[gin(id = #id #proto_attributes)]
pub #field_name: #field_type,
});
}
module.extend(quote::quote! {
#[derive(Clone, Debug, Message)]
#attributes
pub struct #name {
#body
}
});
{
let module_path = ty.name();
for child in ty.child_enums() {
enums::generate(ctx, module, module_path, child);
}
for child in ty.child_messages() {
generate(ctx, module, module_path, child);
}
for one_of in ty.oneofs() {
one_of::generate(ctx, module, module_path, one_of);
}
}
}