use crate::context::CodegenContext;
use crate::schema::StructInfo;
use super::properties::{self, PropertyContext};
pub fn generate_struct(s: &StructInfo, ctx: &CodegenContext) -> String {
let mut out = String::with_capacity(2048);
let name = &s.cpp_name;
let stripped = &s.name;
out.push_str("use super::*;\n");
out.push_str("use rusteal_core::{UeClass, UeStruct, UeEnum};\n");
let current_module = ctx
.package_to_module
.get(&s.package)
.map(|s| s.as_str())
.unwrap_or("");
let mut modules: Vec<&String> = ctx.enabled_modules.iter().collect();
modules.sort();
for module in modules {
if module != current_module {
if let Some(feature) = ctx.feature_for_module(module) {
out.push_str(&format!("#[cfg(feature = \"{feature}\")]\n"));
}
out.push_str(&format!("use crate::{module}::*;\n"));
}
}
out.push('\n');
out.push_str(&format!(
"/// Opaque UE struct `{name}`. Layout managed by C++ side.\n\
pub struct {name};\n\n"
));
if s.has_static_struct {
let name_bytes = stripped.as_bytes();
let name_len = name_bytes.len();
let byte_lit = format!("b\"{stripped}\\0\"");
out.push_str(&format!(
"impl rusteal_core::UeStruct for {name} {{\n\
\x20 fn static_struct() -> rusteal_core::UStructHandle {{\n\
\x20 static CACHE: std::sync::OnceLock<rusteal_core::UStructHandle> = std::sync::OnceLock::new();\n\
\x20 *CACHE.get_or_init(|| unsafe {{\n\
\x20 rusteal_core::ffi_dispatch::reflection_find_struct({byte_lit}.as_ptr(), {name_len})\n\
\x20 }})\n\
\x20 }}\n\
}}\n\n"
));
let (_, deduped_props) = properties::collect_deduped_properties(&s.props, Some(ctx));
if !deduped_props.is_empty() {
let pctx = PropertyContext {
find_prop_fn: "find_struct_property".to_string(),
handle_expr: format!("{name}::static_struct()"),
pre_access: String::new(),
container_expr: "self.as_ptr()".to_string(),
};
let trait_name = format!("{name}Ext");
let no_suppress = std::collections::HashSet::new();
let mut body_buf = String::new();
for prop in &deduped_props {
properties::generate_property(&mut body_buf, prop, &pctx, ctx, &no_suppress);
}
out.push_str(&format!("pub trait {trait_name} {{\n"));
for line in body_buf.lines() {
if line.starts_with(" fn ") && line.ends_with(" {") {
out.push_str(&line[..line.len() - 2]);
out.push_str(";\n");
}
}
out.push_str("}\n\n");
out.push_str(&format!(
"impl {trait_name} for rusteal_core::UStructRef<{name}> {{\n"
));
out.push_str(&body_buf);
out.push_str("}\n");
}
}
out
}