Skip to main content

alef_codegen/generators/
mod.rs

1use ahash::AHashMap;
2
3pub mod binding_helpers;
4pub mod enums;
5pub mod functions;
6pub mod methods;
7pub mod structs;
8pub mod trait_bridge;
9pub mod type_paths;
10
11/// Map of adapter-generated method/function bodies.
12/// Key: "TypeName.method_name" for methods, "function_name" for free functions.
13pub type AdapterBodies = AHashMap<String, String>;
14
15/// Async support pattern for the backend.
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub enum AsyncPattern {
18    /// No async support
19    None,
20    /// PyO3: pyo3_async_runtimes::tokio::future_into_py
21    Pyo3FutureIntoPy,
22    /// NAPI-RS: native async fn → auto-Promise
23    NapiNativeAsync,
24    /// wasm-bindgen: native async fn → auto-Promise
25    WasmNativeAsync,
26    /// Block on Tokio runtime (Ruby, PHP)
27    TokioBlockOn,
28}
29
30/// Configuration for Rust binding code generation.
31pub struct RustBindingConfig<'a> {
32    /// Attrs applied to generated structs, e.g. `["pyclass(frozen)"]`.
33    pub struct_attrs: &'a [&'a str],
34    /// Attrs applied to each field, e.g. `["pyo3(get)"]`.
35    pub field_attrs: &'a [&'a str],
36    /// Derives applied to generated structs, e.g. `["Clone"]`.
37    pub struct_derives: &'a [&'a str],
38    /// Attr wrapping the impl block, e.g. `Some("pymethods")`.
39    pub method_block_attr: Option<&'a str>,
40    /// Attr placed on the constructor, e.g. `"#[new]"`.
41    pub constructor_attr: &'a str,
42    /// Attr placed on static methods, e.g. `Some("staticmethod")`.
43    pub static_attr: Option<&'a str>,
44    /// Attr placed on free functions, e.g. `"#[pyfunction]"`.
45    pub function_attr: &'a str,
46    /// Attrs applied to generated enums, e.g. `["pyclass(eq, eq_int)"]`.
47    pub enum_attrs: &'a [&'a str],
48    /// Derives applied to generated enums, e.g. `["Clone", "PartialEq"]`.
49    pub enum_derives: &'a [&'a str],
50    /// Whether the backend requires `#[pyo3(signature = (...))]`-style annotations.
51    pub needs_signature: bool,
52    /// Prefix for the signature annotation, e.g. `"#[pyo3(signature = ("`.
53    pub signature_prefix: &'a str,
54    /// Suffix for the signature annotation, e.g. `"))]"`.
55    pub signature_suffix: &'a str,
56    /// Core crate import path, e.g. `"liter_llm"`. Used to generate calls into core.
57    pub core_import: &'a str,
58    /// Async pattern supported by this backend.
59    pub async_pattern: AsyncPattern,
60    /// Whether serde/serde_json are available in the output crate's dependencies.
61    /// When true, the generator can use serde-based param conversion and add `serde::Serialize` derives.
62    /// When false, non-convertible Named params fall back to `gen_unimplemented_body`.
63    pub has_serde: bool,
64    /// Prefix for binding type names (e.g. "Js" for NAPI/WASM, "" for PyO3/PHP).
65    /// Used in impl block targets: `impl {prefix}{TypeName}`.
66    pub type_name_prefix: &'a str,
67    /// When true, non-optional Duration fields on `has_default` types are emitted as
68    /// `Option<u64>` in the binding struct so that unset fields fall back to the core
69    /// type's `Default` implementation rather than `Duration::ZERO`.
70    /// Used by PyO3 to prevent validation failures when `request_timeout` is unset.
71    pub option_duration_on_defaults: bool,
72    /// Opaque type names. Structs with non-optional fields of these types
73    /// skip `Default`/`Serialize`/`Deserialize` derives since opaque wrappers don't impl them.
74    pub opaque_type_names: &'a [String],
75    /// When true, the impl block constructor (`fn new(...)`) is suppressed regardless of
76    /// whether the type has fields. Useful for backends (e.g. extendr) that generate a
77    /// separate kwargs-style free-function constructor instead of an in-class `new()`.
78    pub skip_impl_constructor: bool,
79    /// When true, small unsigned/signed ints (u8, u16, u32, i8, i16) are cast from i32 in
80    /// `gen_lossy_binding_to_core_fields`. Used by the extendr backend where R maps small
81    /// ints to i32.
82    pub cast_uints_to_i32: bool,
83    /// When true, large int/size types (u64, usize, isize) are cast from f64 in
84    /// `gen_lossy_binding_to_core_fields`. Used by the extendr backend where R maps large
85    /// ints to f64.
86    pub cast_large_ints_to_f64: bool,
87    /// When true, Named non-opaque struct parameters in free function signatures are emitted
88    /// as `&T` (reference) instead of `T` (owned). Required for the extendr backend because
89    /// `#[extendr]` only generates `TryFrom<&Robj> for &T`, not `for T`, so owned struct
90    /// params cannot be passed through the FFI layer.
91    pub named_non_opaque_params_by_ref: bool,
92    /// Types that have no `From<BindingType>` impl (e.g. output-only flat data enums).
93    /// When `gen_lossy_binding_to_core_fields` encounters a field whose `TypeRef::Named` type
94    /// is in this slice, it emits `Default::default()` instead of `.clone().into()`.
95    pub lossy_skip_types: &'a [String],
96    /// Subset of `opaque_type_names` whose binding wrappers DO implement
97    /// `serde::Serialize`/`Deserialize` (e.g. data-enum wrappers via `gen_pyo3_data_enum`,
98    /// which emit forwarding impls delegating to the core type). Fields whose type
99    /// references a name in this slice will NOT receive `#[serde(skip)]`, even when
100    /// the name is also in `opaque_type_names`. Required so `from_json`/`to_json`
101    /// round-trips on parent structs (e.g. `ChatCompletionRequest.messages: Vec<Message>`)
102    /// don't silently drop the field to `Default::default()`.
103    pub serializable_opaque_type_names: &'a [String],
104}
105
106/// Method names that conflict with standard trait methods.
107/// When a generated method has one of these names, we add
108/// `#[allow(clippy::should_implement_trait)]` to suppress the lint.
109pub(super) const TRAIT_METHOD_NAMES: &[&str] = &[
110    "default", "from", "from_str", "into", "eq", "ne", "lt", "le", "gt", "ge", "add", "sub", "mul", "div", "rem",
111    "neg", "not", "index", "deref",
112];
113
114// Re-exports for backwards compatibility — callers use `crate::generators::*`.
115pub use binding_helpers::{
116    gen_async_body, gen_call_args, gen_call_args_with_let_bindings, gen_lossy_binding_to_core_fields,
117    gen_lossy_binding_to_core_fields_mut, gen_named_let_bindings_no_promote, gen_named_let_bindings_pub,
118    gen_serde_let_bindings, gen_unimplemented_body, has_named_params, is_simple_non_opaque_param, wrap_return,
119    wrap_return_with_mutex,
120};
121pub use enums::{enum_has_data_variants, gen_enum, gen_pyo3_data_enum};
122pub use functions::{collect_explicit_core_imports, collect_trait_imports, gen_function, has_unresolved_trait_methods};
123pub use methods::{
124    gen_constructor, gen_constructor_with_renames, gen_impl_block, gen_impl_block_with_renames, gen_method,
125    gen_opaque_impl_block, gen_static_method, is_trait_method_name,
126};
127pub use structs::{
128    can_generate_default_impl, gen_opaque_struct, gen_opaque_struct_prefixed, gen_struct, gen_struct_default_impl,
129    gen_struct_with_per_field_attrs, gen_struct_with_rename, type_needs_mutex, type_needs_tokio_mutex,
130};