Skip to main content

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}