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