Skip to main content

weaveffi_core/
config.rs

1//! Per-target generator configuration.
2
3use serde::{Deserialize, Serialize};
4
5/// Configuration knobs that generators consult at code-generation time.
6///
7/// Every field falls back to a sensible default when `None`.
8#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9pub struct GeneratorConfig {
10    pub swift_module_name: Option<String>,
11    pub android_package: Option<String>,
12    pub node_package_name: Option<String>,
13    pub wasm_module_name: Option<String>,
14    pub c_prefix: Option<String>,
15    pub python_package_name: Option<String>,
16    pub dotnet_namespace: Option<String>,
17    pub cpp_namespace: Option<String>,
18    pub cpp_header_name: Option<String>,
19    pub cpp_standard: Option<String>,
20    pub dart_package_name: Option<String>,
21    pub go_module_path: Option<String>,
22    pub ruby_module_name: Option<String>,
23    pub ruby_gem_name: Option<String>,
24    #[serde(default)]
25    pub strip_module_prefix: bool,
26    pub template_dir: Option<String>,
27    pub pre_generate: Option<String>,
28    pub post_generate: Option<String>,
29    /// Basename of the IDL the CLI was invoked with (e.g. `weaveffi.yml`).
30    /// Generators embed this in the prelude header of every generated file.
31    /// Not user-configurable via the config file; populated by the CLI.
32    #[serde(skip)]
33    pub input_basename: Option<String>,
34}
35
36impl GeneratorConfig {
37    pub fn swift_module_name(&self) -> &str {
38        self.swift_module_name.as_deref().unwrap_or("WeaveFFI")
39    }
40
41    pub fn android_package(&self) -> &str {
42        self.android_package.as_deref().unwrap_or("com.weaveffi")
43    }
44
45    pub fn node_package_name(&self) -> &str {
46        self.node_package_name.as_deref().unwrap_or("weaveffi")
47    }
48
49    pub fn wasm_module_name(&self) -> &str {
50        self.wasm_module_name.as_deref().unwrap_or("weaveffi_wasm")
51    }
52
53    pub fn c_prefix(&self) -> &str {
54        self.c_prefix.as_deref().unwrap_or("weaveffi")
55    }
56
57    pub fn python_package_name(&self) -> &str {
58        self.python_package_name.as_deref().unwrap_or("weaveffi")
59    }
60
61    pub fn dotnet_namespace(&self) -> &str {
62        self.dotnet_namespace.as_deref().unwrap_or("WeaveFFI")
63    }
64
65    pub fn cpp_namespace(&self) -> &str {
66        self.cpp_namespace.as_deref().unwrap_or("weaveffi")
67    }
68
69    pub fn cpp_header_name(&self) -> &str {
70        self.cpp_header_name.as_deref().unwrap_or("weaveffi.hpp")
71    }
72
73    pub fn cpp_standard(&self) -> &str {
74        self.cpp_standard.as_deref().unwrap_or("17")
75    }
76
77    pub fn dart_package_name(&self) -> &str {
78        self.dart_package_name.as_deref().unwrap_or("weaveffi")
79    }
80
81    pub fn go_module_path(&self) -> &str {
82        self.go_module_path.as_deref().unwrap_or("weaveffi")
83    }
84
85    pub fn ruby_module_name(&self) -> &str {
86        self.ruby_module_name.as_deref().unwrap_or("WeaveFFI")
87    }
88
89    pub fn ruby_gem_name(&self) -> &str {
90        self.ruby_gem_name.as_deref().unwrap_or("weaveffi")
91    }
92
93    pub fn input_basename(&self) -> &str {
94        self.input_basename.as_deref().unwrap_or("weaveffi.yml")
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    #[test]
103    fn defaults_are_applied() {
104        let cfg = GeneratorConfig::default();
105
106        assert_eq!(cfg.swift_module_name(), "WeaveFFI");
107        assert_eq!(cfg.android_package(), "com.weaveffi");
108        assert_eq!(cfg.node_package_name(), "weaveffi");
109        assert_eq!(cfg.wasm_module_name(), "weaveffi_wasm");
110        assert_eq!(cfg.c_prefix(), "weaveffi");
111        assert_eq!(cfg.python_package_name(), "weaveffi");
112        assert_eq!(cfg.dotnet_namespace(), "WeaveFFI");
113        assert_eq!(cfg.cpp_namespace(), "weaveffi");
114        assert_eq!(cfg.cpp_header_name(), "weaveffi.hpp");
115        assert_eq!(cfg.cpp_standard(), "17");
116        assert_eq!(cfg.dart_package_name(), "weaveffi");
117        assert_eq!(cfg.go_module_path(), "weaveffi");
118        assert_eq!(cfg.ruby_module_name(), "WeaveFFI");
119        assert_eq!(cfg.ruby_gem_name(), "weaveffi");
120        assert!(!cfg.strip_module_prefix);
121    }
122
123    #[test]
124    fn custom_values_override_defaults() {
125        let cfg = GeneratorConfig {
126            swift_module_name: Some("MySwift".into()),
127            android_package: Some("org.example".into()),
128            node_package_name: Some("my-node-pkg".into()),
129            wasm_module_name: Some("my_wasm".into()),
130            c_prefix: Some("myffi".into()),
131            python_package_name: Some("my_python_pkg".into()),
132            dotnet_namespace: Some("MyCompany.Bindings".into()),
133            cpp_namespace: Some("mylib".into()),
134            cpp_header_name: Some("mylib.hpp".into()),
135            cpp_standard: Some("20".into()),
136            dart_package_name: Some("my_dart_pkg".into()),
137            go_module_path: Some("github.com/myorg/mylib".into()),
138            ruby_module_name: Some("MyRubyMod".into()),
139            ruby_gem_name: Some("my_ruby_gem".into()),
140            strip_module_prefix: true,
141            template_dir: None,
142            pre_generate: None,
143            post_generate: None,
144            input_basename: None,
145        };
146
147        assert_eq!(cfg.swift_module_name(), "MySwift");
148        assert_eq!(cfg.android_package(), "org.example");
149        assert_eq!(cfg.node_package_name(), "my-node-pkg");
150        assert_eq!(cfg.wasm_module_name(), "my_wasm");
151        assert_eq!(cfg.c_prefix(), "myffi");
152        assert_eq!(cfg.python_package_name(), "my_python_pkg");
153        assert_eq!(cfg.dotnet_namespace(), "MyCompany.Bindings");
154        assert_eq!(cfg.cpp_namespace(), "mylib");
155        assert_eq!(cfg.cpp_header_name(), "mylib.hpp");
156        assert_eq!(cfg.cpp_standard(), "20");
157        assert_eq!(cfg.dart_package_name(), "my_dart_pkg");
158        assert_eq!(cfg.go_module_path(), "github.com/myorg/mylib");
159        assert_eq!(cfg.ruby_module_name(), "MyRubyMod");
160        assert_eq!(cfg.ruby_gem_name(), "my_ruby_gem");
161        assert!(cfg.strip_module_prefix);
162    }
163
164    #[test]
165    fn roundtrip_json() {
166        let cfg = GeneratorConfig {
167            swift_module_name: Some("S".into()),
168            android_package: None,
169            node_package_name: None,
170            wasm_module_name: None,
171            c_prefix: None,
172            python_package_name: Some("mypkg".into()),
173            dotnet_namespace: None,
174            cpp_namespace: Some("myns".into()),
175            cpp_header_name: None,
176            cpp_standard: None,
177            dart_package_name: None,
178            go_module_path: None,
179            ruby_module_name: None,
180            ruby_gem_name: None,
181            strip_module_prefix: true,
182            template_dir: None,
183            pre_generate: None,
184            post_generate: None,
185            input_basename: Some("ignored.yml".into()),
186        };
187
188        let json = serde_json::to_string(&cfg).unwrap();
189        let back: GeneratorConfig = serde_json::from_str(&json).unwrap();
190
191        assert_eq!(back.swift_module_name(), "S");
192        assert_eq!(back.android_package(), "com.weaveffi");
193        assert_eq!(back.python_package_name(), "mypkg");
194        assert_eq!(back.dotnet_namespace(), "WeaveFFI");
195        assert_eq!(back.cpp_namespace(), "myns");
196        assert_eq!(back.cpp_header_name(), "weaveffi.hpp");
197        assert_eq!(back.cpp_standard(), "17");
198        assert_eq!(back.dart_package_name(), "weaveffi");
199        assert_eq!(back.go_module_path(), "weaveffi");
200        assert_eq!(back.ruby_module_name(), "WeaveFFI");
201        assert_eq!(back.ruby_gem_name(), "weaveffi");
202        assert!(back.strip_module_prefix);
203    }
204
205    #[test]
206    fn deserialize_empty_object_gives_defaults() {
207        let cfg: GeneratorConfig = serde_json::from_str("{}").unwrap();
208
209        assert_eq!(cfg.swift_module_name(), "WeaveFFI");
210        assert!(!cfg.strip_module_prefix);
211        assert_eq!(cfg.input_basename(), "weaveffi.yml");
212    }
213
214    #[test]
215    fn input_basename_is_skipped_during_serde() {
216        let cfg = GeneratorConfig {
217            input_basename: Some("calc.yml".into()),
218            ..GeneratorConfig::default()
219        };
220        let json = serde_json::to_string(&cfg).unwrap();
221        assert!(!json.contains("input_basename"));
222        assert!(!json.contains("calc.yml"));
223        let back: GeneratorConfig = serde_json::from_str(&json).unwrap();
224        assert_eq!(back.input_basename(), "weaveffi.yml");
225    }
226}