1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::core::config::extras::Language;
/// Custom modules that alef should declare (mod X;) but not generate.
/// These are hand-written modules imported by the generated lib.rs.
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct CustomModulesConfig {
#[serde(default)]
pub python: Vec<String>,
#[serde(default)]
pub node: Vec<String>,
#[serde(default)]
pub ruby: Vec<String>,
#[serde(default)]
pub php: Vec<String>,
#[serde(default)]
pub elixir: Vec<String>,
#[serde(default)]
pub wasm: Vec<String>,
/// Hand-written Rust modules to declare in the generated FFI `lib.rs` via
/// `pub mod <name>;`. Alef requires `<name>.rs` or `<name>/mod.rs` to already
/// exist under the FFI crate's `src/` directory before generation runs, and
/// fails with a clear error naming the missing path if neither does — the
/// module's *contents* are never generated, only the declaration.
///
/// Declarations are emitted at the top of the file, in configured order,
/// immediately after the generated imports. Only `pub mod` is emitted (no
/// `pub use <name>::*;` re-export): a `#[no_mangle] extern "C" fn` is exported
/// into the compiled artifact, and seen by cbindgen's header generation,
/// regardless of the enclosing module's path, so flattening the names into
/// crate-root scope isn't needed and would risk colliding with a generated
/// item of the same name. Contrast with `[crates.wasm].custom_rust_modules`,
/// which does add `pub use` because wasm-bindgen's glue needs the re-exported
/// names in scope unqualified.
///
/// This is the mechanism for compiling a hand-authored opaque-handle wrapper
/// (e.g. around a core type marked `alef(skip)`) into the FFI crate: without
/// an entry here, a hand-written sibling `.rs` file under the crate's `src/`
/// is never reached from the generated crate root, so its `extern "C"`
/// functions are silently absent from both the cdylib and the header. ~keep
#[serde(default)]
pub ffi: Vec<String>,
#[serde(default)]
pub go: Vec<String>,
#[serde(default)]
pub java: Vec<String>,
#[serde(default)]
pub csharp: Vec<String>,
#[serde(default)]
pub r: Vec<String>,
}
impl CustomModulesConfig {
pub fn for_language(&self, lang: Language) -> &[String] {
match lang {
Language::Python => &self.python,
Language::Node => &self.node,
Language::Ruby => &self.ruby,
Language::Php => &self.php,
Language::Elixir => &self.elixir,
Language::Wasm => &self.wasm,
Language::Ffi => &self.ffi,
Language::Go => &self.go,
Language::Java => &self.java,
Language::Csharp => &self.csharp,
Language::R => &self.r,
Language::Rust => &[],
Language::Kotlin
| Language::KotlinAndroid
| Language::Swift
| Language::Dart
| Language::Gleam
| Language::Zig
| Language::Jni
| Language::C => &[],
}
}
}
/// Custom classes/functions from hand-written modules to register in module init.
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct CustomRegistration {
#[serde(default)]
pub classes: Vec<String>,
#[serde(default)]
pub functions: Vec<String>,
#[serde(default)]
pub init_calls: Vec<String>,
}
/// Per-language custom registrations.
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct CustomRegistrationsConfig {
#[serde(default)]
pub python: Option<CustomRegistration>,
#[serde(default)]
pub node: Option<CustomRegistration>,
#[serde(default)]
pub ruby: Option<CustomRegistration>,
#[serde(default)]
pub php: Option<CustomRegistration>,
#[serde(default)]
pub elixir: Option<CustomRegistration>,
#[serde(default)]
pub wasm: Option<CustomRegistration>,
}
impl CustomRegistrationsConfig {
pub fn for_language(&self, lang: Language) -> Option<&CustomRegistration> {
match lang {
Language::Python => self.python.as_ref(),
Language::Node => self.node.as_ref(),
Language::Ruby => self.ruby.as_ref(),
Language::Php => self.php.as_ref(),
Language::Elixir => self.elixir.as_ref(),
Language::Wasm => self.wasm.as_ref(),
_ => None,
}
}
}