alef_core/backend.rs
1use crate::config::{AlefConfig, Language};
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: &AlefConfig) -> anyhow::Result<Vec<GeneratedFile>>;
94
95 /// Generate type stubs (.pyi, .rbs, .d.ts). Optional — default returns empty.
96 fn generate_type_stubs(&self, _api: &ApiSurface, _config: &AlefConfig) -> anyhow::Result<Vec<GeneratedFile>> {
97 Ok(vec![])
98 }
99
100 /// Generate package scaffolding. Optional — default returns empty.
101 fn generate_scaffold(&self, _api: &ApiSurface, _config: &AlefConfig) -> anyhow::Result<Vec<GeneratedFile>> {
102 Ok(vec![])
103 }
104
105 /// Generate language-native public API wrappers. Optional — default returns empty.
106 fn generate_public_api(&self, _api: &ApiSurface, _config: &AlefConfig) -> anyhow::Result<Vec<GeneratedFile>> {
107 Ok(vec![])
108 }
109
110 /// Build configuration for this backend. Returns `None` if build is not supported.
111 fn build_config(&self) -> Option<BuildConfig> {
112 None
113 }
114}