Skip to main content

alef_core/
ir.rs

1use serde::{Deserialize, Serialize};
2
3/// Indicates the core Rust type wraps the resolved type in a smart pointer or cow.
4/// Used by codegen to generate correct From/Into conversions.
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
6pub enum CoreWrapper {
7    #[default]
8    None,
9    /// `Cow<'static, str>` — binding uses String, core needs `.into()`
10    Cow,
11    /// `Arc<T>` — binding unwraps, core wraps with `Arc::new()`
12    Arc,
13    /// `bytes::Bytes` — binding uses `Vec<u8>`, core needs `Bytes::from()`
14    Bytes,
15    /// `Arc<Mutex<T>>` — binding wraps with `Arc::new(Mutex::new())`, methods call `.lock()`
16    ArcMutex,
17}
18
19/// Typed default value for a field, enabling backends to emit language-native defaults.
20#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
21pub enum DefaultValue {
22    BoolLiteral(bool),
23    StringLiteral(String),
24    IntLiteral(i64),
25    FloatLiteral(f64),
26    EnumVariant(String),
27    /// Empty collection or Default::default()
28    Empty,
29    /// None / null
30    None,
31}
32
33/// Complete API surface extracted from a Rust crate's public interface.
34#[derive(Debug, Clone, Default, Serialize, Deserialize)]
35pub struct ApiSurface {
36    pub crate_name: String,
37    pub version: String,
38    pub types: Vec<TypeDef>,
39    pub functions: Vec<FunctionDef>,
40    pub enums: Vec<EnumDef>,
41    pub errors: Vec<ErrorDef>,
42    /// Type names → fully qualified rust_paths for types that were extracted but
43    /// then excluded from the public binding surface. Preserved so trait_bridge
44    /// codegen can still reference them by qualified path when they appear in
45    /// trait method signatures (e.g. `Renderer::render(&InternalDocument)`).
46    #[serde(default)]
47    pub excluded_type_paths: std::collections::HashMap<String, String>,
48}
49
50/// A public struct exposed to bindings.
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct TypeDef {
53    pub name: String,
54    pub rust_path: String,
55    /// Original rust_path before path mapping rewrites. Used for From impl
56    /// targets to avoid orphan rule violations when core_import is a re-export facade.
57    #[serde(default)]
58    pub original_rust_path: String,
59    pub fields: Vec<FieldDef>,
60    pub methods: Vec<MethodDef>,
61    pub is_opaque: bool,
62    pub is_clone: bool,
63    /// True if the type derives `Copy` (or is bitwise-copyable).
64    /// Used by FFI codegen to avoid emitting `.clone()` (which trips clippy::clone_on_copy).
65    #[serde(default)]
66    pub is_copy: bool,
67    pub doc: String,
68    #[serde(default)]
69    pub cfg: Option<String>,
70    /// True if this type was extracted from a trait definition.
71    /// Trait types need `dyn` keyword when used as opaque inner types.
72    #[serde(default)]
73    pub is_trait: bool,
74    /// True if the type implements Default (via derive or manual impl).
75    /// Used by backends like NAPI to make all fields optional with defaults.
76    #[serde(default)]
77    pub has_default: bool,
78    /// True if some fields were stripped due to `#[cfg]` conditions.
79    /// When true, struct literal initializers need `..Default::default()` to fill
80    /// the missing fields that may exist when the core crate is compiled with features.
81    #[serde(default)]
82    pub has_stripped_cfg_fields: bool,
83    /// True if this type appears as a function return type.
84    /// Used to select output DTO style (e.g., TypedDict for Python return types).
85    #[serde(default)]
86    pub is_return_type: bool,
87    /// Serde `rename_all` strategy for this type (e.g., `"camelCase"`, `"snake_case"`).
88    /// Used by Go/Java/C# backends to emit correct JSON tags matching Rust serde config.
89    #[serde(default)]
90    pub serde_rename_all: Option<String>,
91    /// True if the type derives `serde::Serialize` and `serde::Deserialize`.
92    /// Used by FFI backend to gate `from_json`/`to_json` generation — types
93    /// without serde derives cannot be (de)serialized.
94    #[serde(default)]
95    pub has_serde: bool,
96    /// Super-traits of this trait (e.g., `["Plugin"]` for `OcrBackend: Plugin`).
97    /// Only populated when `is_trait` is true. Used by trait bridge codegen
98    /// to determine which super-trait impls to generate.
99    #[serde(default)]
100    pub super_traits: Vec<String>,
101    /// True when source metadata explicitly excludes this type/trait from generated
102    /// polyglot binding surfaces (via `#[cfg_attr(alef, alef(skip))]` or `#[doc(hidden)]`).
103    #[serde(default)]
104    pub binding_excluded: bool,
105    /// Human-readable reason for `binding_excluded`, used in diagnostics.
106    #[serde(default)]
107    pub binding_exclusion_reason: Option<String>,
108}
109
110/// A field on a public struct.
111#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct FieldDef {
113    pub name: String,
114    pub ty: TypeRef,
115    pub optional: bool,
116    pub default: Option<String>,
117    pub doc: String,
118    /// True if this field's type was sanitized (e.g., Duration→u64, trait object→String).
119    /// Fields marked sanitized cannot participate in auto-generated From/Into conversions.
120    #[serde(default)]
121    pub sanitized: bool,
122    /// True if the core field type is `Box<T>` (or `Option<Box<T>>`).
123    /// Used by FFI backends to insert proper deref when cloning field values.
124    #[serde(default)]
125    pub is_boxed: bool,
126    /// Fully qualified Rust path for the field's type (e.g. `my_crate::types::OutputFormat`).
127    /// Used by backends to disambiguate types with the same short name.
128    #[serde(default)]
129    pub type_rust_path: Option<String>,
130    /// `#[cfg(...)]` condition string on this field, if any.
131    /// Used by backends to conditionally include fields in struct literals.
132    #[serde(default)]
133    pub cfg: Option<String>,
134    /// Typed default value for language-native default emission.
135    #[serde(default)]
136    pub typed_default: Option<DefaultValue>,
137    /// Core wrapper on this field (Cow, Arc, Bytes). Affects From/Into codegen.
138    #[serde(default)]
139    pub core_wrapper: CoreWrapper,
140    /// Core wrapper on Vec inner elements (e.g., `Vec<Arc<T>>`).
141    #[serde(default)]
142    pub vec_inner_core_wrapper: CoreWrapper,
143    /// Full Rust path of the newtype wrapper that was resolved away for this field,
144    /// e.g. `"my_crate::NodeIndex"` when `NodeIndex(u32)` was resolved to `u32`.
145    /// When set, binding→core codegen must wrap values into the newtype
146    /// (e.g. `my_crate::NodeIndex(val.field)`) and core→binding codegen must unwrap (`.0`).
147    #[serde(default)]
148    pub newtype_wrapper: Option<String>,
149    /// Explicit `#[serde(rename = "...")]` on this field, if any. Preserved so binding
150    /// structs that mirror the core struct can serialize/deserialize using the same wire
151    /// names (e.g. core `tool_type` with `#[serde(rename = "type")]` round-trips as `"type"`).
152    #[serde(default)]
153    pub serde_rename: Option<String>,
154    /// True when the field carries `#[serde(flatten)]`. Backends use this to emit
155    /// language-native flatten support: Jackson `@JsonAnyGetter`/`@JsonAnySetter`
156    /// in Java, `[JsonExtensionData]` in C# — both keyed `Map<String, Object>` /
157    /// `Dictionary<string, JsonElement>` so unknown sibling fields land under the
158    /// flattened bag instead of being rejected.
159    #[serde(default)]
160    pub serde_flatten: bool,
161    /// True when source metadata explicitly excludes this field from generated
162    /// polyglot binding surfaces.
163    #[serde(default)]
164    pub binding_excluded: bool,
165    /// Human-readable reason for `binding_excluded`, used in diagnostics.
166    #[serde(default)]
167    pub binding_exclusion_reason: Option<String>,
168    /// Original Rust type string before sanitization (e.g. `"Vec<(String, String)>"`).
169    /// Populated by `sanitize_unknown_types()` when a type is downgraded.
170    /// Allows backends to reconstruct proper serialization/deserialization logic
171    /// even when the sanitized `ty` field only carries the simplified type.
172    #[serde(default)]
173    pub original_type: Option<String>,
174}
175
176/// A method on a public struct.
177#[derive(Debug, Clone, Serialize, Deserialize)]
178pub struct MethodDef {
179    pub name: String,
180    pub params: Vec<ParamDef>,
181    pub return_type: TypeRef,
182    pub is_async: bool,
183    pub is_static: bool,
184    pub error_type: Option<String>,
185    pub doc: String,
186    pub receiver: Option<ReceiverKind>,
187    /// True if any param or return type was sanitized during unknown type resolution.
188    /// Methods with sanitized signatures cannot be auto-delegated.
189    #[serde(default)]
190    pub sanitized: bool,
191    /// Fully qualified trait path if this method comes from a trait impl
192    /// (e.g. "liter_llm::LlmClient"). None for inherent methods.
193    #[serde(default)]
194    pub trait_source: Option<String>,
195    /// True if the core function returns a reference (`&T`, `Option<&T>`, etc.).
196    /// Used by code generators to insert `.clone()` before type conversion.
197    #[serde(default)]
198    pub returns_ref: bool,
199    /// True if the core function returns `Cow<'_, T>` where T is a named type (not str/bytes).
200    /// Used by code generators to emit `.into_owned()` before type conversion.
201    #[serde(default)]
202    pub returns_cow: bool,
203    /// Full Rust path of the newtype wrapper that was resolved away for the return type,
204    /// e.g. `"my_crate::NodeIndex"` when the return type `NodeIndex(u32)` was resolved to `u32`.
205    /// When set, codegen must unwrap the returned newtype value (e.g. `result.0`) before returning.
206    #[serde(default)]
207    pub return_newtype_wrapper: Option<String>,
208    /// True if this method has a default implementation in the trait definition.
209    /// Methods with defaults can be optionally implemented by the foreign object
210    /// in trait bridge codegen.
211    #[serde(default)]
212    pub has_default_impl: bool,
213    /// True when source metadata explicitly excludes this method from generated
214    /// polyglot binding surfaces (via `#[cfg_attr(alef, alef(skip))]` or `#[doc(hidden)]`).
215    #[serde(default)]
216    pub binding_excluded: bool,
217    /// Human-readable reason for `binding_excluded`, used in diagnostics.
218    #[serde(default)]
219    pub binding_exclusion_reason: Option<String>,
220}
221
222/// How `self` is received.
223#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
224pub enum ReceiverKind {
225    Ref,
226    RefMut,
227    Owned,
228}
229
230/// A free function exposed to bindings.
231#[derive(Debug, Clone, Serialize, Deserialize)]
232pub struct FunctionDef {
233    pub name: String,
234    pub rust_path: String,
235    #[serde(default)]
236    pub original_rust_path: String,
237    pub params: Vec<ParamDef>,
238    pub return_type: TypeRef,
239    pub is_async: bool,
240    pub error_type: Option<String>,
241    pub doc: String,
242    #[serde(default)]
243    pub cfg: Option<String>,
244    /// True if any param or return type was sanitized during unknown type resolution.
245    #[serde(default)]
246    pub sanitized: bool,
247    /// True if the return type was sanitized (Named replaced with String).  When true,
248    /// the binding-side return type is wider than the actual core return — codegen must
249    /// JSON-serialize the core value rather than treating it as the binding type.
250    #[serde(default)]
251    pub return_sanitized: bool,
252    /// True if the core function returns a reference (`&T`, `Option<&T>`, etc.).
253    /// Used by code generators to insert `.clone()` before type conversion.
254    #[serde(default)]
255    pub returns_ref: bool,
256    /// True if the core function returns `Cow<'_, T>` where T is a named type (not str/bytes).
257    /// Used by code generators to emit `.into_owned()` before type conversion.
258    #[serde(default)]
259    pub returns_cow: bool,
260    /// Full Rust path of the newtype wrapper that was resolved away for the return type.
261    /// When set, codegen must unwrap the returned newtype value (e.g. `result.0`).
262    #[serde(default)]
263    pub return_newtype_wrapper: Option<String>,
264    /// True when source metadata explicitly excludes this function from generated
265    /// polyglot binding surfaces (via `#[cfg_attr(alef, alef(skip))]` or `#[doc(hidden)]`).
266    #[serde(default)]
267    pub binding_excluded: bool,
268    /// Human-readable reason for `binding_excluded`, used in diagnostics.
269    #[serde(default)]
270    pub binding_exclusion_reason: Option<String>,
271}
272
273/// A function/method parameter.
274#[derive(Debug, Clone, Serialize, Deserialize)]
275pub struct ParamDef {
276    pub name: String,
277    pub ty: TypeRef,
278    pub optional: bool,
279    pub default: Option<String>,
280    /// True if this param's type was sanitized during unknown type resolution.
281    #[serde(default)]
282    pub sanitized: bool,
283    /// Typed default value for language-native default emission.
284    #[serde(default)]
285    pub typed_default: Option<DefaultValue>,
286    /// True if the original Rust parameter was a reference (`&T`).
287    /// Used by codegen to generate owned intermediates and pass refs.
288    #[serde(default)]
289    pub is_ref: bool,
290    /// True if the original Rust parameter was a mutable reference (`&mut T`).
291    /// Used by codegen to generate `&mut` refs when calling core functions.
292    #[serde(default)]
293    pub is_mut: bool,
294    /// Full Rust path of the newtype wrapper that was resolved away for this param,
295    /// e.g. `"my_crate::NodeIndex"` when `NodeIndex(u32)` was resolved to `u32`.
296    /// When set, codegen must wrap the raw value back into the newtype when calling core:
297    /// `my_crate::NodeIndex(param)` instead of just `param`.
298    #[serde(default)]
299    pub newtype_wrapper: Option<String>,
300    /// Original Rust type before sanitization, stored when param.sanitized=true.
301    /// Allows codegen to reconstruct proper deserialization logic.
302    /// E.g. `"Vec<(PathBuf, Option<FileExtractionConfig>)>"` when sanitized to `Vec<String>`.
303    #[serde(default)]
304    pub original_type: Option<String>,
305}
306
307/// A public enum.
308#[derive(Debug, Clone, Serialize, Deserialize)]
309pub struct EnumDef {
310    pub name: String,
311    pub rust_path: String,
312    #[serde(default)]
313    pub original_rust_path: String,
314    pub variants: Vec<EnumVariant>,
315    pub doc: String,
316    #[serde(default)]
317    pub cfg: Option<String>,
318    /// True if the enum derives `Copy`. Only unit-variant enums can derive Copy.
319    /// Used by FFI codegen to avoid emitting `.clone()` (which trips clippy::clone_on_copy).
320    #[serde(default)]
321    pub is_copy: bool,
322    /// True if the enum derives both `serde::Serialize` and `serde::Deserialize`.
323    /// Used by host-language emission (e.g. Swift `Codable`) to gate JSON-bridge conformance.
324    #[serde(default)]
325    pub has_serde: bool,
326    /// Serde tag property name for internally tagged enums (from `#[serde(tag = "...")]`)
327    #[serde(default, skip_serializing_if = "Option::is_none")]
328    pub serde_tag: Option<String>,
329    /// True when the enum has `#[serde(untagged)]`.
330    /// Absence of `serde_tag` does NOT imply untagged — it means externally-tagged (the serde
331    /// default). Only set this when the attribute is explicitly present on the Rust type.
332    #[serde(default)]
333    pub serde_untagged: bool,
334    /// Serde rename strategy for enum variants (from `#[serde(rename_all = "...")]`)
335    #[serde(default, skip_serializing_if = "Option::is_none")]
336    pub serde_rename_all: Option<String>,
337    /// True when source metadata explicitly excludes this enum from generated
338    /// polyglot binding surfaces (via `#[cfg_attr(alef, alef(skip))]` or `#[doc(hidden)]`).
339    #[serde(default)]
340    pub binding_excluded: bool,
341    /// Human-readable reason for `binding_excluded`, used in diagnostics.
342    #[serde(default)]
343    pub binding_exclusion_reason: Option<String>,
344}
345
346/// An enum variant.
347#[derive(Debug, Clone, Serialize, Deserialize)]
348pub struct EnumVariant {
349    pub name: String,
350    pub fields: Vec<FieldDef>,
351    pub doc: String,
352    /// True if this variant has `#[default]` attribute (used by `#[derive(Default)]`).
353    #[serde(default)]
354    pub is_default: bool,
355    /// Explicit serde rename for this variant (from `#[serde(rename = "...")]`).
356    #[serde(default, skip_serializing_if = "Option::is_none")]
357    pub serde_rename: Option<String>,
358    /// True if this is a tuple variant (unnamed fields like `Variant(T1, T2)`).
359    /// False for struct variants with named fields or unit variants.
360    #[serde(default)]
361    pub is_tuple: bool,
362}
363
364/// An error type (enum used in Result<T, E>).
365#[derive(Debug, Clone, Serialize, Deserialize)]
366pub struct ErrorDef {
367    pub name: String,
368    pub rust_path: String,
369    #[serde(default)]
370    pub original_rust_path: String,
371    pub variants: Vec<ErrorVariant>,
372    pub doc: String,
373    /// True when source metadata explicitly excludes this error type from generated
374    /// polyglot binding surfaces (via `#[cfg_attr(alef, alef(skip))]` or `#[doc(hidden)]`).
375    #[serde(default)]
376    pub binding_excluded: bool,
377    /// Human-readable reason for `binding_excluded`, used in diagnostics.
378    #[serde(default)]
379    pub binding_exclusion_reason: Option<String>,
380}
381
382/// An error variant.
383#[derive(Debug, Clone, Serialize, Deserialize)]
384pub struct ErrorVariant {
385    pub name: String,
386    /// The `#[error("...")]` message template string, e.g. `"I/O error: {0}"`.
387    pub message_template: Option<String>,
388    /// Fields on this variant (struct or tuple fields).
389    #[serde(default)]
390    pub fields: Vec<FieldDef>,
391    /// True if any field has `#[source]` or `#[from]`.
392    #[serde(default)]
393    pub has_source: bool,
394    /// True if any field has `#[from]` (auto From conversion).
395    #[serde(default)]
396    pub has_from: bool,
397    /// True if this is a unit variant (no fields).
398    #[serde(default)]
399    pub is_unit: bool,
400    pub doc: String,
401}
402
403/// Reference to a type, with enough info for codegen.
404#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
405pub enum TypeRef {
406    Primitive(PrimitiveType),
407    String,
408    /// Rust `char` — single Unicode character. Binding layer represents as single-char string.
409    Char,
410    Bytes,
411    Optional(Box<TypeRef>),
412    Vec(Box<TypeRef>),
413    Map(Box<TypeRef>, Box<TypeRef>),
414    Named(String),
415    Path,
416    Unit,
417    Json,
418    Duration,
419}
420
421impl TypeRef {
422    /// Returns true if this type reference contains `Named(name)` at any depth.
423    pub fn references_named(&self, name: &str) -> bool {
424        match self {
425            Self::Named(n) => n == name,
426            Self::Optional(inner) | Self::Vec(inner) => inner.references_named(name),
427            Self::Map(k, v) => k.references_named(name) || v.references_named(name),
428            _ => false,
429        }
430    }
431}
432
433/// Rust primitive types.
434#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
435pub enum PrimitiveType {
436    Bool,
437    U8,
438    U16,
439    U32,
440    U64,
441    I8,
442    I16,
443    I32,
444    I64,
445    F32,
446    F64,
447    Usize,
448    Isize,
449}