Skip to main content

rusteal_codegen/rust_gen/
structs.rs

1use crate::context::CodegenContext;
2use crate::schema::StructInfo;
3
4use super::properties::{self, PropertyContext};
5
6pub fn generate_struct(s: &StructInfo, ctx: &CodegenContext) -> String {
7    let mut out = String::with_capacity(2048);
8    let name = &s.cpp_name;
9    let stripped = &s.name;
10
11    out.push_str("use super::*;\n");
12    out.push_str("use rusteal_core::{UeClass, UeStruct, UeEnum};\n");
13
14    let current_module = ctx
15        .package_to_module
16        .get(&s.package)
17        .map(|s| s.as_str())
18        .unwrap_or("");
19
20    let mut modules: Vec<&String> = ctx.enabled_modules.iter().collect();
21    modules.sort();
22
23    for module in modules {
24        if module != current_module {
25            if let Some(feature) = ctx.feature_for_module(module) {
26                out.push_str(&format!("#[cfg(feature = \"{feature}\")]\n"));
27            }
28
29            out.push_str(&format!("use crate::{module}::*;\n"));
30        }
31    }
32
33    out.push('\n');
34
35    out.push_str(&format!(
36        "/// Opaque UE struct `{name}`. Layout managed by C++ side.\n\
37         pub struct {name};\n\n"
38    ));
39
40    if s.has_static_struct {
41        let name_bytes = stripped.as_bytes();
42        let name_len = name_bytes.len();
43        let byte_lit = format!("b\"{stripped}\\0\"");
44
45        out.push_str(&format!(
46            "impl rusteal_core::UeStruct for {name} {{\n\
47             \x20   fn static_struct() -> rusteal_core::UStructHandle {{\n\
48             \x20       static CACHE: std::sync::OnceLock<rusteal_core::UStructHandle> = std::sync::OnceLock::new();\n\
49             \x20       *CACHE.get_or_init(|| unsafe {{\n\
50             \x20           rusteal_core::ffi_dispatch::reflection_find_struct({byte_lit}.as_ptr(), {name_len})\n\
51             \x20       }})\n\
52             \x20   }}\n\
53             }}\n\n"
54        ));
55
56        let (_, deduped_props) = properties::collect_deduped_properties(&s.props, Some(ctx));
57
58        if !deduped_props.is_empty() {
59            let pctx = PropertyContext {
60                find_prop_fn: "find_struct_property".to_string(),
61                handle_expr: format!("{name}::static_struct()"),
62                pre_access: String::new(),
63                container_expr: "self.as_ptr()".to_string(),
64            };
65
66            let trait_name = format!("{name}Ext");
67
68            let no_suppress = std::collections::HashSet::new();
69            let mut body_buf = String::new();
70
71            for prop in &deduped_props {
72                properties::generate_property(&mut body_buf, prop, &pctx, ctx, &no_suppress);
73            }
74
75            out.push_str(&format!("pub trait {trait_name} {{\n"));
76
77            for line in body_buf.lines() {
78                if line.starts_with("    fn ") && line.ends_with(" {") {
79                    out.push_str(&line[..line.len() - 2]);
80                    out.push_str(";\n");
81                }
82            }
83
84            out.push_str("}\n\n");
85
86            out.push_str(&format!(
87                "impl {trait_name} for rusteal_core::UStructRef<{name}> {{\n"
88            ));
89
90            out.push_str(&body_buf);
91            out.push_str("}\n");
92        }
93    }
94
95    out
96}