alef_core/backend.rs
1use crate::config::{Language, ResolvedCrateConfig};
2use crate::ir::ApiSurface;
3use std::path::PathBuf;
4
5/// Build-time dependency for a language backend.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7pub enum BuildDependency {
8 /// Backend has no external build dependencies.
9 #[default]
10 None,
11 /// Backend depends on the C FFI base being built first (Go, Java, C#, Zig).
12 Ffi,
13 /// Backend depends on the Rustler NIF being built first (Gleam).
14 Rustler,
15}
16
17/// Build configuration for a language backend.
18#[derive(Debug, Clone)]
19pub struct BuildConfig {
20 /// Build tool name (e.g., "napi", "maturin", "wasm-pack", "cargo", "mvn", "dotnet", "mix").
21 pub tool: &'static str,
22 /// Crate suffix for Rust binding crate (e.g., "-node", "-py", "-wasm", "-ffi").
23 pub crate_suffix: &'static str,
24 /// Build-time dependency for this backend.
25 pub build_dep: BuildDependency,
26 /// Post-processing steps to run after build.
27 pub post_build: Vec<PostBuildStep>,
28}
29
30impl BuildConfig {
31 /// Returns whether this backend depends on the C FFI base (backwards compatibility).
32 pub fn depends_on_ffi(&self) -> bool {
33 matches!(self.build_dep, BuildDependency::Ffi)
34 }
35}
36
37/// A post-build processing step.
38#[derive(Debug, Clone)]
39pub enum PostBuildStep {
40 /// Replace all occurrences of `find` with `replace` in `path` (relative to crate dir).
41 PatchFile {
42 /// File path relative to the binding crate directory.
43 path: &'static str,
44 /// Text to find.
45 find: &'static str,
46 /// Text to replace with.
47 replace: &'static str,
48 },
49 /// Run an external command (e.g., for generated code post-processing via flutter_rust_bridge).
50 RunCommand {
51 /// Command to execute.
52 cmd: &'static str,
53 /// Command arguments.
54 args: Vec<&'static str>,
55 },
56}
57
58/// A generated file to write to disk.
59#[derive(Debug, Clone)]
60pub struct GeneratedFile {
61 /// Path relative to the output root.
62 pub path: PathBuf,
63 /// File content.
64 pub content: String,
65 /// Whether to prepend a "DO NOT EDIT" header.
66 pub generated_header: bool,
67}
68
69/// Capabilities supported by a backend.
70#[derive(Debug, Clone, Default)]
71pub struct Capabilities {
72 pub supports_async: bool,
73 pub supports_classes: bool,
74 pub supports_enums: bool,
75 pub supports_option: bool,
76 pub supports_result: bool,
77 pub supports_callbacks: bool,
78 pub supports_streaming: bool,
79}
80
81/// Trait that all language backends implement.
82pub trait Backend: Send + Sync {
83 /// Backend identifier (e.g., "pyo3", "napi", "ffi").
84 fn name(&self) -> &str;
85
86 /// Target language.
87 fn language(&self) -> Language;
88
89 /// What this backend supports.
90 fn capabilities(&self) -> Capabilities;
91
92 /// Generate binding source code.
93 fn generate_bindings(&self, api: &ApiSurface, config: &ResolvedCrateConfig) -> anyhow::Result<Vec<GeneratedFile>>;
94
95 /// Generate type stubs (.pyi, .rbs, .d.ts). Optional — default returns empty.
96 fn generate_type_stubs(
97 &self,
98 _api: &ApiSurface,
99 _config: &ResolvedCrateConfig,
100 ) -> anyhow::Result<Vec<GeneratedFile>> {
101 Ok(vec![])
102 }
103
104 /// Generate package scaffolding. Optional — default returns empty.
105 fn generate_scaffold(
106 &self,
107 _api: &ApiSurface,
108 _config: &ResolvedCrateConfig,
109 ) -> anyhow::Result<Vec<GeneratedFile>> {
110 Ok(vec![])
111 }
112
113 /// Generate language-native public API wrappers. Optional — default returns empty.
114 fn generate_public_api(
115 &self,
116 _api: &ApiSurface,
117 _config: &ResolvedCrateConfig,
118 ) -> anyhow::Result<Vec<GeneratedFile>> {
119 Ok(vec![])
120 }
121
122 /// Build configuration for this backend. Returns `None` if build is not supported.
123 fn build_config(&self) -> Option<BuildConfig> {
124 None
125 }
126}