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