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};