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/// In-process post-processor applied to a generated file after external build tools run.
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub enum PostProcessor {
40    /// Rewrite frb-generated Dart sealed-class factory params from positional names (`field0`)
41    /// to payload-derived names (e.g. `metadata` for a `PdfMetadata` payload).
42    FrbDartSealedVariants,
43}
44
45/// A post-build processing step.
46#[derive(Debug, Clone)]
47pub enum PostBuildStep {
48    /// Replace all occurrences of `find` with `replace` in `path` (relative to crate dir).
49    PatchFile {
50        /// File path relative to the binding crate directory.
51        path: &'static str,
52        /// Text to find.
53        find: &'static str,
54        /// Text to replace with.
55        replace: &'static str,
56    },
57    /// Run an external command (e.g., for generated code post-processing via flutter_rust_bridge).
58    RunCommand {
59        /// Command to execute.
60        cmd: &'static str,
61        /// Command arguments.
62        args: Vec<&'static str>,
63    },
64    /// Apply an in-process [`PostProcessor`] to the file at `path` (relative to crate dir).
65    PostProcessFile {
66        /// File path relative to the binding crate directory.
67        path: PathBuf,
68        /// In-process processor to apply.
69        processor: PostProcessor,
70    },
71}
72
73/// A generated file to write to disk.
74#[derive(Debug, Clone)]
75pub struct GeneratedFile {
76    /// Path relative to the output root.
77    pub path: PathBuf,
78    /// File content.
79    pub content: String,
80    /// Whether to prepend a "DO NOT EDIT" header.
81    pub generated_header: bool,
82}
83
84/// Capabilities supported by a backend.
85#[derive(Debug, Clone, Default)]
86pub struct Capabilities {
87    pub supports_async: bool,
88    pub supports_classes: bool,
89    pub supports_enums: bool,
90    pub supports_option: bool,
91    pub supports_result: bool,
92    pub supports_callbacks: bool,
93    pub supports_streaming: bool,
94}
95
96/// Trait that all language backends implement.
97pub trait Backend: Send + Sync {
98    /// Backend identifier (e.g., "pyo3", "napi", "ffi").
99    fn name(&self) -> &str;
100
101    /// Target language.
102    fn language(&self) -> Language;
103
104    /// What this backend supports.
105    fn capabilities(&self) -> Capabilities;
106
107    /// Generate binding source code.
108    fn generate_bindings(&self, api: &ApiSurface, config: &ResolvedCrateConfig) -> anyhow::Result<Vec<GeneratedFile>>;
109
110    /// Generate type stubs (.pyi, .rbs, .d.ts). Optional — default returns empty.
111    fn generate_type_stubs(
112        &self,
113        _api: &ApiSurface,
114        _config: &ResolvedCrateConfig,
115    ) -> anyhow::Result<Vec<GeneratedFile>> {
116        Ok(vec![])
117    }
118
119    /// Generate package scaffolding. Optional — default returns empty.
120    fn generate_scaffold(
121        &self,
122        _api: &ApiSurface,
123        _config: &ResolvedCrateConfig,
124    ) -> anyhow::Result<Vec<GeneratedFile>> {
125        Ok(vec![])
126    }
127
128    /// Generate language-native public API wrappers. Optional — default returns empty.
129    fn generate_public_api(
130        &self,
131        _api: &ApiSurface,
132        _config: &ResolvedCrateConfig,
133    ) -> anyhow::Result<Vec<GeneratedFile>> {
134        Ok(vec![])
135    }
136
137    /// Build configuration for this backend. Returns `None` if build is not supported.
138    fn build_config(&self) -> Option<BuildConfig> {
139        None
140    }
141}