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}
142
143/// A method on a public struct.
144#[derive(Debug, Clone, Serialize, Deserialize)]
145pub struct MethodDef {
146 pub name: String,
147 pub params: Vec<ParamDef>,
148 pub return_type: TypeRef,
149 pub is_async: bool,
150 pub is_static: bool,
151 pub error_type: Option<String>,
152 pub doc: String,
153 pub receiver: Option<ReceiverKind>,
154 /// True if any param or return type was sanitized during unknown type resolution.
155 /// Methods with sanitized signatures cannot be auto-delegated.
156 #[serde(default)]
157 pub sanitized: bool,
158 /// Fully qualified trait path if this method comes from a trait impl
159 /// (e.g. "liter_llm::LlmClient"). None for inherent methods.
160 #[serde(default)]
161 pub trait_source: Option<String>,
162 /// True if the core function returns a reference (`&T`, `Option<&T>`, etc.).
163 /// Used by code generators to insert `.clone()` before type conversion.
164 #[serde(default)]
165 pub returns_ref: bool,
166 /// True if the core function returns `Cow<'_, T>` where T is a named type (not str/bytes).
167 /// Used by code generators to emit `.into_owned()` before type conversion.
168 #[serde(default)]
169 pub returns_cow: bool,
170 /// Full Rust path of the newtype wrapper that was resolved away for the return type,
171 /// e.g. `"my_crate::NodeIndex"` when the return type `NodeIndex(u32)` was resolved to `u32`.
172 /// When set, codegen must unwrap the returned newtype value (e.g. `result.0`) before returning.
173 #[serde(default)]
174 pub return_newtype_wrapper: Option<String>,
175 /// True if this method has a default implementation in the trait definition.
176 /// Methods with defaults can be optionally implemented by the foreign object
177 /// in trait bridge codegen.
178 #[serde(default)]
179 pub has_default_impl: bool,
180}
181
182/// How `self` is received.
183#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
184pub enum ReceiverKind {
185 Ref,
186 RefMut,
187 Owned,
188}
189
190/// A free function exposed to bindings.
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct FunctionDef {
193 pub name: String,
194 pub rust_path: String,
195 #[serde(default)]
196 pub original_rust_path: String,
197 pub params: Vec<ParamDef>,
198 pub return_type: TypeRef,
199 pub is_async: bool,
200 pub error_type: Option<String>,
201 pub doc: String,
202 #[serde(default)]
203 pub cfg: Option<String>,
204 /// True if any param or return type was sanitized during unknown type resolution.
205 #[serde(default)]
206 pub sanitized: bool,
207 /// True if the return type was sanitized (Named replaced with String). When true,
208 /// the binding-side return type is wider than the actual core return — codegen must
209 /// JSON-serialize the core value rather than treating it as the binding type.
210 #[serde(default)]
211 pub return_sanitized: bool,
212 /// True if the core function returns a reference (`&T`, `Option<&T>`, etc.).
213 /// Used by code generators to insert `.clone()` before type conversion.
214 #[serde(default)]
215 pub returns_ref: bool,
216 /// True if the core function returns `Cow<'_, T>` where T is a named type (not str/bytes).
217 /// Used by code generators to emit `.into_owned()` before type conversion.
218 #[serde(default)]
219 pub returns_cow: bool,
220 /// Full Rust path of the newtype wrapper that was resolved away for the return type.
221 /// When set, codegen must unwrap the returned newtype value (e.g. `result.0`).
222 #[serde(default)]
223 pub return_newtype_wrapper: Option<String>,
224}
225
226/// A function/method parameter.
227#[derive(Debug, Clone, Serialize, Deserialize)]
228pub struct ParamDef {
229 pub name: String,
230 pub ty: TypeRef,
231 pub optional: bool,
232 pub default: Option<String>,
233 /// True if this param's type was sanitized during unknown type resolution.
234 #[serde(default)]
235 pub sanitized: bool,
236 /// Typed default value for language-native default emission.
237 #[serde(default)]
238 pub typed_default: Option<DefaultValue>,
239 /// True if the original Rust parameter was a reference (`&T`).
240 /// Used by codegen to generate owned intermediates and pass refs.
241 #[serde(default)]
242 pub is_ref: bool,
243 /// True if the original Rust parameter was a mutable reference (`&mut T`).
244 /// Used by codegen to generate `&mut` refs when calling core functions.
245 #[serde(default)]
246 pub is_mut: bool,
247 /// Full Rust path of the newtype wrapper that was resolved away for this param,
248 /// e.g. `"my_crate::NodeIndex"` when `NodeIndex(u32)` was resolved to `u32`.
249 /// When set, codegen must wrap the raw value back into the newtype when calling core:
250 /// `my_crate::NodeIndex(param)` instead of just `param`.
251 #[serde(default)]
252 pub newtype_wrapper: Option<String>,
253 /// Original Rust type before sanitization, stored when param.sanitized=true.
254 /// Allows codegen to reconstruct proper deserialization logic.
255 /// E.g. `"Vec<(PathBuf, Option<FileExtractionConfig>)>"` when sanitized to `Vec<String>`.
256 #[serde(default)]
257 pub original_type: Option<String>,
258}
259
260/// A public enum.
261#[derive(Debug, Clone, Serialize, Deserialize)]
262pub struct EnumDef {
263 pub name: String,
264 pub rust_path: String,
265 #[serde(default)]
266 pub original_rust_path: String,
267 pub variants: Vec<EnumVariant>,
268 pub doc: String,
269 #[serde(default)]
270 pub cfg: Option<String>,
271 /// True if the enum derives `Copy`. Only unit-variant enums can derive Copy.
272 /// Used by FFI codegen to avoid emitting `.clone()` (which trips clippy::clone_on_copy).
273 #[serde(default)]
274 pub is_copy: bool,
275 /// True if the enum derives both `serde::Serialize` and `serde::Deserialize`.
276 /// Used by host-language emission (e.g. Swift `Codable`) to gate JSON-bridge conformance.
277 #[serde(default)]
278 pub has_serde: bool,
279 /// Serde tag property name for internally tagged enums (from `#[serde(tag = "...")]`)
280 #[serde(default, skip_serializing_if = "Option::is_none")]
281 pub serde_tag: Option<String>,
282 /// True when the enum has `#[serde(untagged)]`.
283 /// Absence of `serde_tag` does NOT imply untagged — it means externally-tagged (the serde
284 /// default). Only set this when the attribute is explicitly present on the Rust type.
285 #[serde(default)]
286 pub serde_untagged: bool,
287 /// Serde rename strategy for enum variants (from `#[serde(rename_all = "...")]`)
288 #[serde(default, skip_serializing_if = "Option::is_none")]
289 pub serde_rename_all: Option<String>,
290}
291
292/// An enum variant.
293#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct EnumVariant {
295 pub name: String,
296 pub fields: Vec<FieldDef>,
297 pub doc: String,
298 /// True if this variant has `#[default]` attribute (used by `#[derive(Default)]`).
299 #[serde(default)]
300 pub is_default: bool,
301 /// Explicit serde rename for this variant (from `#[serde(rename = "...")]`).
302 #[serde(default, skip_serializing_if = "Option::is_none")]
303 pub serde_rename: Option<String>,
304 /// True if this is a tuple variant (unnamed fields like `Variant(T1, T2)`).
305 /// False for struct variants with named fields or unit variants.
306 #[serde(default)]
307 pub is_tuple: bool,
308}
309
310/// An error type (enum used in Result<T, E>).
311#[derive(Debug, Clone, Serialize, Deserialize)]
312pub struct ErrorDef {
313 pub name: String,
314 pub rust_path: String,
315 #[serde(default)]
316 pub original_rust_path: String,
317 pub variants: Vec<ErrorVariant>,
318 pub doc: String,
319}
320
321/// An error variant.
322#[derive(Debug, Clone, Serialize, Deserialize)]
323pub struct ErrorVariant {
324 pub name: String,
325 /// The `#[error("...")]` message template string, e.g. `"I/O error: {0}"`.
326 pub message_template: Option<String>,
327 /// Fields on this variant (struct or tuple fields).
328 #[serde(default)]
329 pub fields: Vec<FieldDef>,
330 /// True if any field has `#[source]` or `#[from]`.
331 #[serde(default)]
332 pub has_source: bool,
333 /// True if any field has `#[from]` (auto From conversion).
334 #[serde(default)]
335 pub has_from: bool,
336 /// True if this is a unit variant (no fields).
337 #[serde(default)]
338 pub is_unit: bool,
339 pub doc: String,
340}
341
342/// Reference to a type, with enough info for codegen.
343#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
344pub enum TypeRef {
345 Primitive(PrimitiveType),
346 String,
347 /// Rust `char` — single Unicode character. Binding layer represents as single-char string.
348 Char,
349 Bytes,
350 Optional(Box<TypeRef>),
351 Vec(Box<TypeRef>),
352 Map(Box<TypeRef>, Box<TypeRef>),
353 Named(String),
354 Path,
355 Unit,
356 Json,
357 Duration,
358}
359
360impl TypeRef {
361 /// Returns true if this type reference contains `Named(name)` at any depth.
362 pub fn references_named(&self, name: &str) -> bool {
363 match self {
364 Self::Named(n) => n == name,
365 Self::Optional(inner) | Self::Vec(inner) => inner.references_named(name),
366 Self::Map(k, v) => k.references_named(name) || v.references_named(name),
367 _ => false,
368 }
369 }
370}
371
372/// Rust primitive types.
373#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
374pub enum PrimitiveType {
375 Bool,
376 U8,
377 U16,
378 U32,
379 U64,
380 I8,
381 I16,
382 I32,
383 I64,
384 F32,
385 F64,
386 Usize,
387 Isize,
388}