Skip to main content

rusteal_codegen/rust_gen/
cargo_toml.rs

1use std::collections::{BTreeMap, BTreeSet};
2use std::path::Path;
3
4use crate::config::CodegenConfig;
5use crate::context::CodegenContext;
6
7const README: &str = "\
8# bindings
9
10Rust bindings for the Unreal Engine modules this project uses, generated by
11`rusteal build --all` from the engine's reflection data, together with the C++
12wrappers in `Plugins/Rusteal/Source/Rusteal/Generated/`.
13
14Do not edit: every file here is overwritten on the next run. Regenerate after
15changing the engine version, the enabled modules or the blocklist in
16`rusteal.toml`, and commit the result — the game crate depends on it.
17";
18
19pub fn write_crate_files(crate_dir: &Path, ctx: &CodegenContext, config: &CodegenConfig) {
20    let manifest = format!(
21        "# Generated by rusteal-codegen. Do not edit.\n\
22         \n\
23         [package]\n\
24         name = \"bindings\"\n\
25         version = \"0.1.0\"\n\
26         edition = \"2024\"\n\
27         publish = false\n\
28         \n\
29         [dependencies]\n\
30         rusteal-core = {{ workspace = true }}\n\
31         rusteal-ffi = {{ workspace = true }}\n\
32         glam = {{ workspace = true }}\n\
33         \n\
34         {features}\
35         \n\
36         {lints}",
37        features = render_features_section(ctx, config),
38        lints = render_lints_section(),
39    );
40
41    let manifest_path = crate_dir.join("Cargo.toml");
42
43    crate::write_if_changed(&manifest_path, &manifest)
44        .unwrap_or_else(|e| panic!("Failed to write {}: {e}", manifest_path.display()));
45
46    let readme_path = crate_dir.join("README.md");
47
48    crate::write_if_changed(&readme_path, README)
49        .unwrap_or_else(|e| panic!("Failed to write {}: {e}", readme_path.display()));
50
51    eprintln!("  Cargo.toml: {} features", config.features.len());
52}
53
54fn render_features_section(ctx: &CodegenContext, config: &CodegenConfig) -> String {
55    let mut feature_to_modules: BTreeMap<String, Vec<String>> = BTreeMap::new();
56
57    for mapping in config.modules.values() {
58        feature_to_modules
59            .entry(mapping.feature.clone())
60            .or_default()
61            .push(mapping.module.clone());
62    }
63
64    let generated: BTreeSet<String> = config.features.iter().cloned().collect();
65
66    let mut out = String::from("[features]\n");
67
68    out.push_str(&format!(
69        "default = {}\n",
70        format_dep_array(&generated.iter().cloned().collect::<Vec<_>>())
71    ));
72
73    for feature in &generated {
74        let mut dep_features: BTreeSet<String> = BTreeSet::new();
75
76        if let Some(modules) = feature_to_modules.get(feature) {
77            for module in modules {
78                if let Some(module_deps) = ctx.module_deps.get(module) {
79                    for dep_module in module_deps {
80                        if let Some(dep_feature) = ctx.feature_for_module(dep_module)
81                            && dep_feature != feature
82                        {
83                            dep_features.insert(dep_feature.to_string());
84                        }
85                    }
86                }
87            }
88        }
89
90        out.push_str(&format!(
91            "{feature} = {}\n",
92            format_dep_array(&dep_features.iter().cloned().collect::<Vec<_>>())
93        ));
94    }
95
96    out
97}
98
99fn render_lints_section() -> String {
100    let features: Vec<String> = super::manual::gating_features()
101        .into_iter()
102        .map(|f| format!("\"{f}\""))
103        .collect();
104
105    format!(
106        "[lints.rust]\n\
107         unexpected_cfgs = {{ level = \"warn\", check-cfg = ['cfg(feature, values({}))'] }}\n",
108        features.join(", ")
109    )
110}
111
112fn format_dep_array(deps: &[String]) -> String {
113    if deps.is_empty() {
114        "[]".to_string()
115    } else {
116        let items: Vec<String> = deps.iter().map(|d| format!("\"{d}\"")).collect();
117
118        format!("[{}]", items.join(", "))
119    }
120}