rusteal_codegen/
config.rs1use serde::Deserialize;
9use std::collections::HashMap;
10use std::path::{Path, PathBuf};
11
12pub const FILE_NAME: &str = "rusteal.toml";
14
15#[derive(Deserialize)]
17pub struct ProjectConfig {
18 pub project: ProjectSection,
19 pub codegen: CodegenConfig,
20}
21
22#[derive(Deserialize)]
23pub struct ProjectSection {
24 #[serde(rename = "crate")]
26 pub crate_name: String,
27 #[serde(default)]
29 pub features: Vec<String>,
30}
31
32#[derive(Deserialize)]
33pub struct CodegenConfig {
34 pub features: Vec<String>,
35 pub modules: HashMap<String, ModuleMapping>,
36 #[serde(default)]
37 pub blocklist: Blocklist,
38}
39
40#[derive(Deserialize)]
41pub struct ModuleMapping {
42 pub module: String,
43 pub feature: String,
44 #[serde(default)]
47 pub plugin: Option<String>,
48}
49
50#[derive(Deserialize, Default)]
51pub struct Blocklist {
52 #[serde(default)]
53 pub classes: Vec<String>,
54 #[serde(default)]
55 pub structs: Vec<String>,
56 #[serde(default)]
58 pub functions: Vec<String>,
59}
60
61impl Blocklist {
62 pub fn function_tuples(&self) -> Vec<(String, String)> {
64 self.functions
65 .iter()
66 .filter_map(|entry| {
67 let (class, func) = entry.split_once('.')?;
68 Some((class.to_string(), func.to_string()))
69 })
70 .collect()
71 }
72}
73
74impl ProjectConfig {
75 pub fn load(root: &Path) -> Result<Self, String> {
77 let path = root.join(FILE_NAME);
78 let text = std::fs::read_to_string(&path)
79 .map_err(|e| format!("cannot read {}: {e}", path.display()))?;
80 toml::from_str(&text).map_err(|e| format!("cannot parse {}: {e}", path.display()))
81 }
82}
83
84pub struct ProjectLayout {
87 pub root: PathBuf,
89}
90
91impl ProjectLayout {
92 pub fn new(root: &Path) -> Self {
93 Self { root: root.to_path_buf() }
94 }
95
96 pub fn uproject(&self) -> Option<PathBuf> {
98 find_uproject(&self.root)
99 }
100
101 pub fn rust_workspace(&self) -> PathBuf {
103 self.root.join("Rust")
104 }
105
106 pub fn bindings_crate(&self) -> PathBuf {
108 self.rust_workspace().join("bindings")
109 }
110
111 pub fn cpp_generated(&self) -> PathBuf {
113 self.root.join("Plugins/Rusteal/Source/Rusteal/Generated")
114 }
115
116 pub fn plugin_descriptor(&self) -> PathBuf {
118 self.root.join("Plugins/Rusteal/Rusteal.uplugin")
119 }
120
121 pub fn uht_json(&self) -> PathBuf {
123 self.root.join("Intermediate/Rusteal/uht")
124 }
125
126 pub fn config_file(&self) -> PathBuf {
128 self.root.join(FILE_NAME)
129 }
130}
131
132pub fn find_uproject(dir: &Path) -> Option<PathBuf> {
134 std::fs::read_dir(dir)
135 .ok()?
136 .flatten()
137 .map(|entry| entry.path())
138 .find(|path| path.extension().is_some_and(|ext| ext == "uproject"))
139}
140
141pub fn find_project_root(start: &Path) -> Option<PathBuf> {
143 let start = start.canonicalize().ok()?;
144 start
145 .ancestors()
146 .find(|dir| find_uproject(dir).is_some())
147 .map(Path::to_path_buf)
148}