alef_core/config/resolved/
ffi.rs1use super::ResolvedCrateConfig;
4
5impl ResolvedCrateConfig {
6 pub fn ffi_prefix(&self) -> String {
11 self.ffi
12 .as_ref()
13 .and_then(|f| f.prefix.as_ref())
14 .cloned()
15 .unwrap_or_else(|| self.name.replace('-', "_"))
16 }
17
18 pub fn ffi_lib_name(&self) -> String {
28 if let Some(name) = self.ffi.as_ref().and_then(|f| f.lib_name.as_ref()) {
30 return name.clone();
31 }
32
33 if let Some(ffi_path) = self.explicit_output.ffi.as_ref() {
37 let crate_dir = ffi_path
38 .components()
39 .filter_map(|c| {
40 if let std::path::Component::Normal(s) = c {
41 s.to_str()
42 } else {
43 None
44 }
45 })
46 .rev()
47 .find(|&s| s != "src" && s != "lib" && s != "include");
48 if let Some(dir) = crate_dir {
49 return dir.replace('-', "_");
50 }
51 }
52
53 format!("{}_ffi", self.ffi_prefix())
55 }
56
57 pub fn ffi_header_name(&self) -> String {
61 self.ffi
62 .as_ref()
63 .and_then(|f| f.header_name.as_ref())
64 .cloned()
65 .unwrap_or_else(|| format!("{}.h", self.ffi_prefix()))
66 }
67
68 pub fn ffi_crate_path(&self) -> String {
80 if let Some(ffi_path) = self.explicit_output.ffi.as_ref() {
81 let components: Vec<&str> = ffi_path
83 .components()
84 .filter_map(|c| {
85 if let std::path::Component::Normal(s) = c {
86 s.to_str()
87 } else {
88 None
89 }
90 })
91 .collect();
92 if let Some(idx) = components
95 .iter()
96 .rposition(|&s| s != "src" && s != "lib" && s != "include")
97 {
98 let meaningful = &components[..=idx];
100 return format!("../../{}", meaningful.join("/"));
101 }
102 }
103 format!("../../crates/{}-ffi", self.name)
104 }
105
106 pub fn wasm_crate_path(&self) -> String {
119 if let Some(wasm_path) = self.explicit_output.wasm.as_ref() {
120 let components: Vec<&str> = wasm_path
121 .components()
122 .filter_map(|c| {
123 if let std::path::Component::Normal(s) = c {
124 s.to_str()
125 } else {
126 None
127 }
128 })
129 .collect();
130 if let Some(idx) = components
131 .iter()
132 .rposition(|&s| s != "src" && s != "lib" && s != "include")
133 {
134 let meaningful = &components[..=idx];
135 return format!("../../{}/pkg", meaningful.join("/"));
136 }
137 }
138 format!("../../crates/{}-wasm/pkg", self.name)
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use crate::config::new_config::NewAlefConfig;
145
146 fn resolved_one(toml: &str) -> super::super::ResolvedCrateConfig {
147 let cfg: NewAlefConfig = toml::from_str(toml).unwrap();
148 cfg.resolve().unwrap().remove(0)
149 }
150
151 fn minimal_ffi() -> super::super::ResolvedCrateConfig {
152 resolved_one(
153 r#"
154[workspace]
155languages = ["ffi"]
156
157[[crates]]
158name = "my-lib"
159sources = ["src/lib.rs"]
160"#,
161 )
162 }
163
164 #[test]
165 fn ffi_prefix_defaults_to_snake_case_name() {
166 let r = minimal_ffi();
167 assert_eq!(r.ffi_prefix(), "my_lib");
168 }
169
170 #[test]
171 fn ffi_prefix_explicit_wins() {
172 let r = resolved_one(
173 r#"
174[workspace]
175languages = ["ffi"]
176
177[[crates]]
178name = "my-lib"
179sources = ["src/lib.rs"]
180
181[crates.ffi]
182prefix = "custom_prefix"
183"#,
184 );
185 assert_eq!(r.ffi_prefix(), "custom_prefix");
186 }
187
188 #[test]
189 fn ffi_lib_name_falls_back_to_prefix_ffi() {
190 let r = minimal_ffi();
191 assert_eq!(r.ffi_lib_name(), "my_lib_ffi");
192 }
193
194 #[test]
195 fn ffi_lib_name_explicit_wins() {
196 let r = resolved_one(
197 r#"
198[workspace]
199languages = ["ffi"]
200
201[[crates]]
202name = "my-lib"
203sources = ["src/lib.rs"]
204
205[crates.ffi]
206lib_name = "libmy_custom"
207"#,
208 );
209 assert_eq!(r.ffi_lib_name(), "libmy_custom");
210 }
211
212 #[test]
213 fn ffi_header_name_defaults_to_prefix_h() {
214 let r = minimal_ffi();
215 assert_eq!(r.ffi_header_name(), "my_lib.h");
216 }
217
218 #[test]
219 fn ffi_lib_name_derives_from_explicit_output_path() {
220 let r = resolved_one(
221 r#"
222[workspace]
223languages = ["ffi"]
224
225[[crates]]
226name = "my-lib"
227sources = ["src/lib.rs"]
228
229[crates.output]
230ffi = "crates/html-to-markdown-ffi/src/"
231"#,
232 );
233 assert_eq!(r.ffi_lib_name(), "html_to_markdown_ffi");
236 }
237
238 #[test]
239 fn ffi_lib_name_explicit_lib_name_overrides_output_path_derivation() {
240 let r = resolved_one(
241 r#"
242[workspace]
243languages = ["ffi"]
244
245[[crates]]
246name = "my-lib"
247sources = ["src/lib.rs"]
248
249[crates.ffi]
250lib_name = "explicit_wins"
251
252[crates.output]
253ffi = "crates/html-to-markdown-ffi/src/"
254"#,
255 );
256 assert_eq!(r.ffi_lib_name(), "explicit_wins");
258 }
259
260 #[test]
261 fn ffi_lib_name_template_derived_output_does_not_drive_lib_name() {
262 let r = minimal_ffi();
266 assert_eq!(r.ffi_lib_name(), "my_lib_ffi");
267 }
268
269 #[test]
270 fn ffi_header_name_explicit_wins() {
271 let r = resolved_one(
272 r#"
273[workspace]
274languages = ["ffi"]
275
276[[crates]]
277name = "my-lib"
278sources = ["src/lib.rs"]
279
280[crates.ffi]
281header_name = "custom.h"
282"#,
283 );
284 assert_eq!(r.ffi_header_name(), "custom.h");
285 }
286}