Skip to main content

rusteal_codegen/cpp_gen/
fill_table.rs

1use std::collections::BTreeMap;
2
3use crate::context::FuncEntry;
4use crate::cpp_gen::wrapper::cpp_wrapper_name;
5
6pub fn generate_fill_table(
7    prefix: &str,
8    entries: &[FuncEntry],
9    _by_class: &BTreeMap<(String, String), Vec<&FuncEntry>>,
10) -> String {
11    let mut out = String::with_capacity(entries.len() * 80 + 1024);
12
13    out.push_str("// Auto-generated by rusteal-codegen. Do not edit.\n\n");
14    out.push_str("#include \"RustealFuncIds.h\"\n\n");
15
16    out.push_str("// Forward declarations of wrapper functions\n");
17
18    for entry in entries {
19        let c_name = cpp_wrapper_name(prefix, &entry.class_name, &entry.func_name);
20        out.push_str(&format!("extern \"C\" uint32_t {c_name}(...);\n"));
21    }
22
23    out.push('\n');
24
25    out.push_str("static void* GRustealFuncTable[RustealFuncId::FUNC_COUNT];\n\n");
26
27    out.push_str(&format!("void {prefix}RustealFillFuncTable() {{\n"));
28
29    for entry in entries {
30        let const_name =
31            crate::rust_gen::func_ids::func_id_const_name(&entry.class_name, &entry.func_name);
32
33        let c_name = cpp_wrapper_name(prefix, &entry.class_name, &entry.func_name);
34
35        out.push_str(&format!(
36            "    GRustealFuncTable[RustealFuncId::{const_name}] = (void*)&{c_name};\n"
37        ));
38    }
39
40    out.push_str("}\n\n");
41
42    out.push_str(&format!("void** {prefix}RustealGetFuncTable() {{\n"));
43    out.push_str("    return GRustealFuncTable;\n");
44    out.push_str("}\n\n");
45
46    out.push_str(&format!(
47        "uint32_t {prefix}RustealGetFuncCount() {{\n    return RustealFuncId::FUNC_COUNT;\n}}\n"
48    ));
49
50    out
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    fn entry(func_id: u32, class_name: &str, func_name: &str) -> FuncEntry {
58        let func = serde_json::from_value(serde_json::json!({
59            "name": func_name,
60            "func_flags": 0,
61        }))
62        .unwrap();
63
64        FuncEntry {
65            func_id,
66            module_name: "engine".to_string(),
67            class_name: class_name.to_string(),
68            func_name: func_name.to_string(),
69            rust_func_name: func_name.to_string(),
70            func,
71            cpp_class_name: format!("A{class_name}"),
72            header: String::new(),
73        }
74    }
75
76    #[test]
77    fn game_library_keeps_the_unprefixed_names() {
78        let code = generate_fill_table("", &[entry(0, "Actor", "GetOwner")], &BTreeMap::new());
79        assert!(code.contains("void RustealFillFuncTable()"), "{code}");
80        assert!(code.contains("void** RustealGetFuncTable()"), "{code}");
81        assert!(code.contains("uint32_t RustealGetFuncCount()"), "{code}");
82        assert!(code.contains("= (void*)&Rusteal_Actor_GetOwner;"), "{code}");
83    }
84
85    #[test]
86    fn plugin_library_prefixes_every_symbol() {
87        let code = generate_fill_table(
88            "Inventory_",
89            &[entry(0, "Actor", "GetOwner")],
90            &BTreeMap::new(),
91        );
92
93        assert!(
94            code.contains("extern \"C\" uint32_t Inventory_Rusteal_Actor_GetOwner(...);"),
95            "{code}"
96        );
97
98        assert!(
99            code.contains("void Inventory_RustealFillFuncTable()"),
100            "{code}"
101        );
102
103        assert!(
104            code.contains("void** Inventory_RustealGetFuncTable()"),
105            "{code}"
106        );
107
108        assert!(
109            code.contains("uint32_t Inventory_RustealGetFuncCount()"),
110            "{code}"
111        );
112
113        assert!(!code.contains(" RustealFillFuncTable()"), "{code}");
114    }
115}