Skip to main content

oxilean_codegen/ffi_bridge/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::lcnf::*;
6use std::collections::{BTreeMap, HashMap};
7
8use super::functions::*;
9use std::collections::{HashSet, VecDeque};
10
11/// FFI platform target
12#[allow(dead_code)]
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum FfiPlatformTarget {
15    Linux,
16    Windows,
17    MacOS,
18    FreeBSD,
19    Wasm32,
20    Wasm64,
21    Android,
22    Ios,
23    Universal,
24}
25/// FFI header builder
26#[allow(dead_code)]
27#[derive(Debug, Default)]
28pub struct FfiHeaderBuilder {
29    pub guard: Option<String>,
30    pub includes: Vec<String>,
31    pub typedefs: Vec<FfiTypedef>,
32    pub structs: Vec<FfiStructDef>,
33    pub enums: Vec<FfiEnumDef>,
34    pub functions: Vec<FfiFuncSignature>,
35    pub constants: Vec<FfiConst>,
36    pub callbacks: Vec<FfiCallbackType>,
37}
38#[allow(dead_code)]
39impl FfiHeaderBuilder {
40    pub fn new() -> Self {
41        Self::default()
42    }
43    pub fn with_guard(mut self, guard: &str) -> Self {
44        self.guard = Some(guard.to_string());
45        self
46    }
47    pub fn add_include(&mut self, inc: &str) {
48        self.includes.push(inc.to_string());
49    }
50    pub fn add_typedef(&mut self, td: FfiTypedef) {
51        self.typedefs.push(td);
52    }
53    pub fn add_struct(&mut self, s: FfiStructDef) {
54        self.structs.push(s);
55    }
56    pub fn add_enum(&mut self, e: FfiEnumDef) {
57        self.enums.push(e);
58    }
59    pub fn add_function(&mut self, f: FfiFuncSignature) {
60        self.functions.push(f);
61    }
62    pub fn add_const(&mut self, c: FfiConst) {
63        self.constants.push(c);
64    }
65    pub fn add_callback(&mut self, cb: FfiCallbackType) {
66        self.callbacks.push(cb);
67    }
68    pub fn build(&self) -> String {
69        let mut out = String::new();
70        if let Some(guard) = &self.guard {
71            out.push_str(&format!("#ifndef {}\n#define {}\n\n", guard, guard));
72        }
73        for inc in &self.includes {
74            if inc.starts_with('<') {
75                out.push_str(&format!("#include {}\n", inc));
76            } else {
77                out.push_str(&format!("#include \"{}\"\n", inc));
78            }
79        }
80        if !self.includes.is_empty() {
81            out.push('\n');
82        }
83        for td in &self.typedefs {
84            out.push_str(&format!("{}\n", td));
85        }
86        for s in &self.structs {
87            out.push_str(&format!("{}\n\n", s));
88        }
89        for e in &self.enums {
90            out.push_str(&format!("{}\n\n", e));
91        }
92        for cb in &self.callbacks {
93            out.push_str(&format!("{};\n", cb));
94        }
95        if !self.callbacks.is_empty() {
96            out.push('\n');
97        }
98        for c in &self.constants {
99            out.push_str(&format!("{}\n", c));
100        }
101        if !self.constants.is_empty() {
102            out.push('\n');
103        }
104        for func in &self.functions {
105            out.push_str(&format!("{};\n", func));
106        }
107        if let Some(guard) = &self.guard {
108            out.push_str(&format!("\n#endif /* {} */\n", guard));
109        }
110        out
111    }
112}
113/// A diagnostic message from a FfiExt pass.
114#[derive(Debug, Clone)]
115pub struct FfiExtDiagMsg {
116    pub severity: FfiExtDiagSeverity,
117    pub pass: String,
118    pub message: String,
119}
120impl FfiExtDiagMsg {
121    pub fn error(pass: impl Into<String>, msg: impl Into<String>) -> Self {
122        FfiExtDiagMsg {
123            severity: FfiExtDiagSeverity::Error,
124            pass: pass.into(),
125            message: msg.into(),
126        }
127    }
128    pub fn warning(pass: impl Into<String>, msg: impl Into<String>) -> Self {
129        FfiExtDiagMsg {
130            severity: FfiExtDiagSeverity::Warning,
131            pass: pass.into(),
132            message: msg.into(),
133        }
134    }
135    pub fn note(pass: impl Into<String>, msg: impl Into<String>) -> Self {
136        FfiExtDiagMsg {
137            severity: FfiExtDiagSeverity::Note,
138            pass: pass.into(),
139            message: msg.into(),
140        }
141    }
142}
143/// A version tag for FfiExt output artifacts.
144#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
145pub struct FfiExtVersion {
146    pub major: u32,
147    pub minor: u32,
148    pub patch: u32,
149    pub pre: Option<String>,
150}
151impl FfiExtVersion {
152    pub fn new(major: u32, minor: u32, patch: u32) -> Self {
153        FfiExtVersion {
154            major,
155            minor,
156            patch,
157            pre: None,
158        }
159    }
160    pub fn with_pre(mut self, pre: impl Into<String>) -> Self {
161        self.pre = Some(pre.into());
162        self
163    }
164    pub fn is_stable(&self) -> bool {
165        self.pre.is_none()
166    }
167    pub fn is_compatible_with(&self, other: &FfiExtVersion) -> bool {
168        self.major == other.major && self.minor >= other.minor
169    }
170}
171/// A monotonically increasing ID generator for FfiExt.
172#[derive(Debug, Default)]
173pub struct FfiExtIdGen {
174    pub(super) next: u32,
175}
176impl FfiExtIdGen {
177    pub fn new() -> Self {
178        FfiExtIdGen::default()
179    }
180    pub fn next_id(&mut self) -> u32 {
181        let id = self.next;
182        self.next += 1;
183        id
184    }
185    pub fn peek_next(&self) -> u32 {
186        self.next
187    }
188    pub fn reset(&mut self) {
189        self.next = 0;
190    }
191    pub fn skip(&mut self, n: u32) {
192        self.next += n;
193    }
194}
195#[allow(dead_code)]
196#[derive(Debug, Clone, Default)]
197pub struct FFIPassStats {
198    pub total_runs: u32,
199    pub successful_runs: u32,
200    pub total_changes: u64,
201    pub time_ms: u64,
202    pub iterations_used: u32,
203}
204impl FFIPassStats {
205    #[allow(dead_code)]
206    pub fn new() -> Self {
207        Self::default()
208    }
209    #[allow(dead_code)]
210    pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
211        self.total_runs += 1;
212        self.successful_runs += 1;
213        self.total_changes += changes;
214        self.time_ms += time_ms;
215        self.iterations_used = iterations;
216    }
217    #[allow(dead_code)]
218    pub fn average_changes_per_run(&self) -> f64 {
219        if self.total_runs == 0 {
220            return 0.0;
221        }
222        self.total_changes as f64 / self.total_runs as f64
223    }
224    #[allow(dead_code)]
225    pub fn success_rate(&self) -> f64 {
226        if self.total_runs == 0 {
227            return 0.0;
228        }
229        self.successful_runs as f64 / self.total_runs as f64
230    }
231    #[allow(dead_code)]
232    pub fn format_summary(&self) -> String {
233        format!(
234            "Runs: {}/{}, Changes: {}, Time: {}ms",
235            self.successful_runs, self.total_runs, self.total_changes, self.time_ms
236        )
237    }
238}
239/// FFI verification result
240#[allow(dead_code)]
241#[derive(Debug, Clone)]
242pub struct FfiVerifyResult {
243    pub ok: bool,
244    pub errors: Vec<String>,
245    pub warnings: Vec<String>,
246}
247/// An FFI function declaration.
248#[derive(Debug, Clone)]
249pub struct FfiDecl {
250    /// The OxiLean/LCNF name of the function.
251    pub name: String,
252    /// The external (C) name of the function.
253    pub extern_name: String,
254    /// Parameter types.
255    pub params: Vec<(String, FfiNativeType)>,
256    /// Return type.
257    pub ret_type: FfiNativeType,
258    /// Calling convention.
259    pub calling_conv: CallingConvention,
260    /// Whether the function is unsafe.
261    pub is_unsafe: bool,
262}
263/// FFI Python CFFI binding
264#[allow(dead_code)]
265#[derive(Debug, Default)]
266pub struct FfiPythonCffi {
267    pub ffi_defs: Vec<String>,
268    pub lib_name: String,
269    pub header_file: String,
270}
271#[allow(dead_code)]
272impl FfiPythonCffi {
273    pub fn new(lib: &str, header: &str) -> Self {
274        Self {
275            ffi_defs: Vec::new(),
276            lib_name: lib.to_string(),
277            header_file: header.to_string(),
278        }
279    }
280    pub fn add_def(&mut self, def: &str) {
281        self.ffi_defs.push(def.to_string());
282    }
283    pub fn emit(&self) -> String {
284        let defs = self.ffi_defs.join("\n");
285        format!(
286            "from cffi import FFI\nffi = FFI()\nffi.cdef(\"\"\"\n{}\n\"\"\")\nlib = ffi.dlopen(\"lib{}.so\")\n",
287            defs, self.lib_name
288        )
289    }
290}
291#[allow(dead_code)]
292pub struct FFIPassRegistry {
293    pub(super) configs: Vec<FFIPassConfig>,
294    pub(super) stats: std::collections::HashMap<String, FFIPassStats>,
295}
296impl FFIPassRegistry {
297    #[allow(dead_code)]
298    pub fn new() -> Self {
299        FFIPassRegistry {
300            configs: Vec::new(),
301            stats: std::collections::HashMap::new(),
302        }
303    }
304    #[allow(dead_code)]
305    pub fn register(&mut self, config: FFIPassConfig) {
306        self.stats
307            .insert(config.pass_name.clone(), FFIPassStats::new());
308        self.configs.push(config);
309    }
310    #[allow(dead_code)]
311    pub fn enabled_passes(&self) -> Vec<&FFIPassConfig> {
312        self.configs.iter().filter(|c| c.enabled).collect()
313    }
314    #[allow(dead_code)]
315    pub fn get_stats(&self, name: &str) -> Option<&FFIPassStats> {
316        self.stats.get(name)
317    }
318    #[allow(dead_code)]
319    pub fn total_passes(&self) -> usize {
320        self.configs.len()
321    }
322    #[allow(dead_code)]
323    pub fn enabled_count(&self) -> usize {
324        self.enabled_passes().len()
325    }
326    #[allow(dead_code)]
327    pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
328        if let Some(stats) = self.stats.get_mut(name) {
329            stats.record_run(changes, time_ms, iter);
330        }
331    }
332}
333/// FFI parameter attribute
334#[allow(dead_code)]
335#[derive(Debug, Clone, PartialEq, Eq)]
336pub enum FfiParamAttr {
337    In,
338    Out,
339    InOut,
340    Const,
341    Volatile,
342    Restrict,
343    NullTerminated,
344    Nonnull,
345    Nullable,
346    Retain,
347    Escaping,
348}
349#[allow(dead_code)]
350#[derive(Debug, Clone, PartialEq, Eq)]
351pub enum FfiRustBindingKind {
352    Function,
353    Struct,
354    Enum,
355    Type,
356    Const,
357}
358/// FFI Zig binding
359#[allow(dead_code)]
360#[derive(Debug, Default)]
361pub struct FfiZigBinding {
362    pub pub_fns: Vec<String>,
363    pub types: Vec<String>,
364    pub lib_path: String,
365}
366#[allow(dead_code)]
367impl FfiZigBinding {
368    pub fn new(lib_path: &str) -> Self {
369        Self {
370            pub_fns: Vec::new(),
371            types: Vec::new(),
372            lib_path: lib_path.to_string(),
373        }
374    }
375    pub fn add_fn(&mut self, f: &str) {
376        self.pub_fns.push(f.to_string());
377    }
378    pub fn add_type(&mut self, t: &str) {
379        self.types.push(t.to_string());
380    }
381    pub fn emit(&self) -> String {
382        let mut out = format!("const c = @cImport(@cInclude(\"{}\"));\n\n", self.lib_path);
383        for t in &self.types {
384            out.push_str(&format!("pub const {} = c.{};\n", t, t));
385        }
386        for f in &self.pub_fns {
387            out.push_str(&format!("pub const {} = c.{};\n", f, f));
388        }
389        out
390    }
391}
392/// The generated FFI binding output.
393#[derive(Debug, Clone)]
394pub struct FfiOutput {
395    /// Generated Rust `extern "C"` bindings.
396    pub rust_bindings: String,
397    /// Generated C header declarations.
398    pub c_header: String,
399    /// Generated C wrapper functions.
400    pub wrapper_fns: Vec<String>,
401}
402impl FfiOutput {
403    pub(super) fn new() -> Self {
404        FfiOutput {
405            rust_bindings: String::new(),
406            c_header: String::new(),
407            wrapper_fns: Vec::new(),
408        }
409    }
410}
411#[allow(dead_code)]
412#[derive(Debug, Clone)]
413pub struct FFICacheEntry {
414    pub key: String,
415    pub data: Vec<u8>,
416    pub timestamp: u64,
417    pub valid: bool,
418}
419/// A feature flag set for FfiExt capabilities.
420#[derive(Debug, Clone, Default)]
421pub struct FfiExtFeatures {
422    pub(super) flags: std::collections::HashSet<String>,
423}
424impl FfiExtFeatures {
425    pub fn new() -> Self {
426        FfiExtFeatures::default()
427    }
428    pub fn enable(&mut self, flag: impl Into<String>) {
429        self.flags.insert(flag.into());
430    }
431    pub fn disable(&mut self, flag: &str) {
432        self.flags.remove(flag);
433    }
434    pub fn is_enabled(&self, flag: &str) -> bool {
435        self.flags.contains(flag)
436    }
437    pub fn len(&self) -> usize {
438        self.flags.len()
439    }
440    pub fn is_empty(&self) -> bool {
441        self.flags.is_empty()
442    }
443    pub fn union(&self, other: &FfiExtFeatures) -> FfiExtFeatures {
444        FfiExtFeatures {
445            flags: self.flags.union(&other.flags).cloned().collect(),
446        }
447    }
448    pub fn intersection(&self, other: &FfiExtFeatures) -> FfiExtFeatures {
449        FfiExtFeatures {
450            flags: self.flags.intersection(&other.flags).cloned().collect(),
451        }
452    }
453}
454/// Native C type for FFI boundaries.
455#[derive(Debug, Clone, PartialEq, Eq, Hash)]
456pub enum FfiNativeType {
457    /// `void`
458    Void,
459    /// `int8_t`
460    I8,
461    /// `int16_t`
462    I16,
463    /// `int32_t`
464    I32,
465    /// `int64_t`
466    I64,
467    /// `uint8_t`
468    U8,
469    /// `uint16_t`
470    U16,
471    /// `uint32_t`
472    U32,
473    /// `uint64_t`
474    U64,
475    /// `float`
476    F32,
477    /// `double`
478    F64,
479    /// `bool` (C99 _Bool)
480    Bool,
481    /// `size_t`
482    SizeT,
483    /// `char*` (C string)
484    CStr,
485    /// Generic pointer `T*`
486    Ptr(Box<FfiNativeType>),
487    /// Opaque pointer `void*`
488    OpaquePtr,
489    /// `lean_object*`
490    LeanObject,
491    /// Struct with named fields.
492    Struct(String, Vec<(String, FfiNativeType)>),
493    /// Function pointer.
494    FnPtr(Vec<FfiNativeType>, Box<FfiNativeType>),
495}
496impl FfiNativeType {
497    /// Convert to a Rust type string.
498    pub(super) fn to_rust_type(&self) -> String {
499        match self {
500            FfiNativeType::Void => "()".to_string(),
501            FfiNativeType::I8 => "i8".to_string(),
502            FfiNativeType::I16 => "i16".to_string(),
503            FfiNativeType::I32 => "i32".to_string(),
504            FfiNativeType::I64 => "i64".to_string(),
505            FfiNativeType::U8 => "u8".to_string(),
506            FfiNativeType::U16 => "u16".to_string(),
507            FfiNativeType::U32 => "u32".to_string(),
508            FfiNativeType::U64 => "u64".to_string(),
509            FfiNativeType::F32 => "f32".to_string(),
510            FfiNativeType::F64 => "f64".to_string(),
511            FfiNativeType::Bool => "bool".to_string(),
512            FfiNativeType::SizeT => "usize".to_string(),
513            FfiNativeType::CStr => "*const std::os::raw::c_char".to_string(),
514            FfiNativeType::Ptr(inner) => format!("*mut {}", inner.to_rust_type()),
515            FfiNativeType::OpaquePtr => "*mut std::os::raw::c_void".to_string(),
516            FfiNativeType::LeanObject => "*mut LeanObject".to_string(),
517            FfiNativeType::Struct(name, _) => name.clone(),
518            FfiNativeType::FnPtr(params, ret) => {
519                let param_strs: Vec<String> = params.iter().map(|p| p.to_rust_type()).collect();
520                format!(
521                    "Option<unsafe extern \"C\" fn({}) -> {}>",
522                    param_strs.join(", "),
523                    ret.to_rust_type()
524                )
525            }
526        }
527    }
528    /// Size in bytes (approximate, for validation).
529    pub(super) fn size_bytes(&self) -> usize {
530        match self {
531            FfiNativeType::Void => 0,
532            FfiNativeType::I8 | FfiNativeType::U8 | FfiNativeType::Bool => 1,
533            FfiNativeType::I16 | FfiNativeType::U16 => 2,
534            FfiNativeType::I32 | FfiNativeType::U32 | FfiNativeType::F32 => 4,
535            FfiNativeType::I64
536            | FfiNativeType::U64
537            | FfiNativeType::F64
538            | FfiNativeType::SizeT
539            | FfiNativeType::CStr
540            | FfiNativeType::Ptr(_)
541            | FfiNativeType::OpaquePtr
542            | FfiNativeType::LeanObject
543            | FfiNativeType::FnPtr(_, _) => 8,
544            FfiNativeType::Struct(_, fields) => fields.iter().map(|(_, ty)| ty.size_bytes()).sum(),
545        }
546    }
547}
548/// Tracks declared names for FfiExt scope analysis.
549#[derive(Debug, Default)]
550pub struct FfiExtNameScope {
551    pub(super) declared: std::collections::HashSet<String>,
552    pub(super) depth: usize,
553    pub(super) parent: Option<Box<FfiExtNameScope>>,
554}
555impl FfiExtNameScope {
556    pub fn new() -> Self {
557        FfiExtNameScope::default()
558    }
559    pub fn declare(&mut self, name: impl Into<String>) -> bool {
560        self.declared.insert(name.into())
561    }
562    pub fn is_declared(&self, name: &str) -> bool {
563        self.declared.contains(name)
564    }
565    pub fn push_scope(self) -> Self {
566        FfiExtNameScope {
567            declared: std::collections::HashSet::new(),
568            depth: self.depth + 1,
569            parent: Some(Box::new(self)),
570        }
571    }
572    pub fn pop_scope(self) -> Self {
573        *self.parent.unwrap_or_default()
574    }
575    pub fn depth(&self) -> usize {
576        self.depth
577    }
578    pub fn len(&self) -> usize {
579        self.declared.len()
580    }
581}
582/// FFI bridge statistics v2
583#[allow(dead_code)]
584#[derive(Debug, Default, Clone)]
585pub struct FfiBridgeStatsV2 {
586    pub functions_bridged: usize,
587    pub structs_bridged: usize,
588    pub enums_bridged: usize,
589    pub typedefs_emitted: usize,
590    pub callbacks_emitted: usize,
591    pub constants_emitted: usize,
592    pub headers_generated: usize,
593    pub bytes_total: usize,
594}
595#[allow(dead_code)]
596#[derive(Debug, Clone, PartialEq)]
597pub enum FFIPassPhase {
598    Analysis,
599    Transformation,
600    Verification,
601    Cleanup,
602}
603impl FFIPassPhase {
604    #[allow(dead_code)]
605    pub fn name(&self) -> &str {
606        match self {
607            FFIPassPhase::Analysis => "analysis",
608            FFIPassPhase::Transformation => "transformation",
609            FFIPassPhase::Verification => "verification",
610            FFIPassPhase::Cleanup => "cleanup",
611        }
612    }
613    #[allow(dead_code)]
614    pub fn is_modifying(&self) -> bool {
615        matches!(self, FFIPassPhase::Transformation | FFIPassPhase::Cleanup)
616    }
617}
618/// FFI null termination policy
619#[allow(dead_code)]
620#[derive(Debug, Clone, PartialEq, Eq)]
621pub enum FfiNullTermPolicy {
622    Always,
623    Never,
624    WhenNonNull,
625}
626/// FFI buffer parameter (slice/buffer with size)
627#[allow(dead_code)]
628#[derive(Debug, Clone)]
629pub struct FfiBufferParam {
630    pub data: FfiFuncParam,
631    pub size: FfiSizeHint,
632    pub null_term: FfiNullTermPolicy,
633}
634/// Information about how to marshal a type across the FFI boundary.
635#[derive(Debug, Clone)]
636pub struct FfiMarshalInfo {
637    /// The native (C) type to use at the FFI boundary.
638    pub native_type: FfiNativeType,
639    /// Code to convert from LCNF/Lean object to native type.
640    pub to_native: String,
641    /// Code to convert from native type to LCNF/Lean object.
642    pub from_native: String,
643    /// Whether the conversion is trivial (no-op).
644    pub is_trivial: bool,
645    /// Whether the native type needs to be freed after use.
646    pub needs_free: bool,
647}
648impl FfiMarshalInfo {
649    /// Create a trivial (identity) marshalling.
650    pub(super) fn trivial(native_type: FfiNativeType) -> Self {
651        FfiMarshalInfo {
652            native_type,
653            to_native: String::new(),
654            from_native: String::new(),
655            is_trivial: true,
656            needs_free: false,
657        }
658    }
659    /// Create a marshalling with conversion functions.
660    pub(super) fn with_conversion(
661        native_type: FfiNativeType,
662        to_native: &str,
663        from_native: &str,
664    ) -> Self {
665        FfiMarshalInfo {
666            native_type,
667            to_native: to_native.to_string(),
668            from_native: from_native.to_string(),
669            is_trivial: false,
670            needs_free: false,
671        }
672    }
673}
674/// FFI calling convention
675#[allow(dead_code)]
676#[derive(Debug, Clone, PartialEq, Eq)]
677pub enum FfiCallingConv {
678    C,
679    StdCall,
680    FastCall,
681    ThisCall,
682    VectorCall,
683    Win64,
684    SysV64,
685    Swift,
686    Rust,
687    Custom(String),
688}
689/// FFI profiler v2
690#[allow(dead_code)]
691#[derive(Debug, Default)]
692pub struct FfiExtProfilerV2 {
693    pub timings: Vec<(String, u64)>,
694}
695#[allow(dead_code)]
696impl FfiExtProfilerV2 {
697    pub fn new() -> Self {
698        Self::default()
699    }
700    pub fn record(&mut self, pass: &str, us: u64) {
701        self.timings.push((pass.to_string(), us));
702    }
703    pub fn total_us(&self) -> u64 {
704        self.timings.iter().map(|(_, t)| *t).sum()
705    }
706}
707#[allow(dead_code)]
708#[derive(Debug, Clone)]
709pub struct FFIDominatorTree {
710    pub idom: Vec<Option<u32>>,
711    pub dom_children: Vec<Vec<u32>>,
712    pub dom_depth: Vec<u32>,
713}
714impl FFIDominatorTree {
715    #[allow(dead_code)]
716    pub fn new(size: usize) -> Self {
717        FFIDominatorTree {
718            idom: vec![None; size],
719            dom_children: vec![Vec::new(); size],
720            dom_depth: vec![0; size],
721        }
722    }
723    #[allow(dead_code)]
724    pub fn set_idom(&mut self, node: usize, idom: u32) {
725        self.idom[node] = Some(idom);
726    }
727    #[allow(dead_code)]
728    pub fn dominates(&self, a: usize, b: usize) -> bool {
729        if a == b {
730            return true;
731        }
732        let mut cur = b;
733        loop {
734            match self.idom[cur] {
735                Some(parent) if parent as usize == a => return true,
736                Some(parent) if parent as usize == cur => return false,
737                Some(parent) => cur = parent as usize,
738                None => return false,
739            }
740        }
741    }
742    #[allow(dead_code)]
743    pub fn depth(&self, node: usize) -> u32 {
744        self.dom_depth.get(node).copied().unwrap_or(0)
745    }
746}
747/// FFI error table
748#[allow(dead_code)]
749#[derive(Debug, Default)]
750pub struct FfiErrorTable {
751    pub codes: Vec<FfiErrorCode>,
752}
753#[allow(dead_code)]
754impl FfiErrorTable {
755    pub fn new() -> Self {
756        Self::default()
757    }
758    pub fn add(&mut self, code: FfiErrorCode) {
759        self.codes.push(code);
760    }
761    pub fn lookup(&self, value: i32) -> Option<&FfiErrorCode> {
762        self.codes.iter().find(|c| c.value == value)
763    }
764    pub fn emit_enum(&self, name: &str) -> String {
765        let mut out = format!("enum {} {{\n", name);
766        for c in &self.codes {
767            out.push_str(&format!("    {} = {},\n", c.name, c.value));
768        }
769        out.push_str("};\n");
770        out
771    }
772}
773#[allow(dead_code)]
774#[derive(Debug, Clone)]
775pub struct FFIPassConfig {
776    pub phase: FFIPassPhase,
777    pub enabled: bool,
778    pub max_iterations: u32,
779    pub debug_output: bool,
780    pub pass_name: String,
781}
782impl FFIPassConfig {
783    #[allow(dead_code)]
784    pub fn new(name: impl Into<String>, phase: FFIPassPhase) -> Self {
785        FFIPassConfig {
786            phase,
787            enabled: true,
788            max_iterations: 10,
789            debug_output: false,
790            pass_name: name.into(),
791        }
792    }
793    #[allow(dead_code)]
794    pub fn disabled(mut self) -> Self {
795        self.enabled = false;
796        self
797    }
798    #[allow(dead_code)]
799    pub fn with_debug(mut self) -> Self {
800        self.debug_output = true;
801        self
802    }
803    #[allow(dead_code)]
804    pub fn max_iter(mut self, n: u32) -> Self {
805        self.max_iterations = n;
806        self
807    }
808}
809/// FFI enum definition
810#[allow(dead_code)]
811#[derive(Debug, Clone)]
812pub struct FfiEnumDef {
813    pub name: String,
814    pub variants: Vec<(String, Option<i64>)>,
815    pub underlying_type: Option<String>,
816}
817/// Collects FfiExt diagnostics.
818#[derive(Debug, Default)]
819pub struct FfiExtDiagCollector {
820    pub(super) msgs: Vec<FfiExtDiagMsg>,
821}
822impl FfiExtDiagCollector {
823    pub fn new() -> Self {
824        FfiExtDiagCollector::default()
825    }
826    pub fn emit(&mut self, d: FfiExtDiagMsg) {
827        self.msgs.push(d);
828    }
829    pub fn has_errors(&self) -> bool {
830        self.msgs
831            .iter()
832            .any(|d| d.severity == FfiExtDiagSeverity::Error)
833    }
834    pub fn errors(&self) -> Vec<&FfiExtDiagMsg> {
835        self.msgs
836            .iter()
837            .filter(|d| d.severity == FfiExtDiagSeverity::Error)
838            .collect()
839    }
840    pub fn warnings(&self) -> Vec<&FfiExtDiagMsg> {
841        self.msgs
842            .iter()
843            .filter(|d| d.severity == FfiExtDiagSeverity::Warning)
844            .collect()
845    }
846    pub fn len(&self) -> usize {
847        self.msgs.len()
848    }
849    pub fn is_empty(&self) -> bool {
850        self.msgs.is_empty()
851    }
852    pub fn clear(&mut self) {
853        self.msgs.clear();
854    }
855}
856/// A fixed-capacity ring buffer of strings (for recent-event logging in FfiExt).
857#[derive(Debug)]
858pub struct FfiExtEventLog {
859    pub(super) entries: std::collections::VecDeque<String>,
860    pub(super) capacity: usize,
861}
862impl FfiExtEventLog {
863    pub fn new(capacity: usize) -> Self {
864        FfiExtEventLog {
865            entries: std::collections::VecDeque::with_capacity(capacity),
866            capacity,
867        }
868    }
869    pub fn push(&mut self, event: impl Into<String>) {
870        if self.entries.len() >= self.capacity {
871            self.entries.pop_front();
872        }
873        self.entries.push_back(event.into());
874    }
875    pub fn iter(&self) -> impl Iterator<Item = &String> {
876        self.entries.iter()
877    }
878    pub fn len(&self) -> usize {
879        self.entries.len()
880    }
881    pub fn is_empty(&self) -> bool {
882        self.entries.is_empty()
883    }
884    pub fn capacity(&self) -> usize {
885        self.capacity
886    }
887    pub fn clear(&mut self) {
888        self.entries.clear();
889    }
890}
891/// Pass-timing record for FfiExt profiler.
892#[derive(Debug, Clone)]
893pub struct FfiExtPassTiming {
894    pub pass_name: String,
895    pub elapsed_us: u64,
896    pub items_processed: usize,
897    pub bytes_before: usize,
898    pub bytes_after: usize,
899}
900impl FfiExtPassTiming {
901    pub fn new(
902        pass_name: impl Into<String>,
903        elapsed_us: u64,
904        items: usize,
905        before: usize,
906        after: usize,
907    ) -> Self {
908        FfiExtPassTiming {
909            pass_name: pass_name.into(),
910            elapsed_us,
911            items_processed: items,
912            bytes_before: before,
913            bytes_after: after,
914        }
915    }
916    pub fn throughput_mps(&self) -> f64 {
917        if self.elapsed_us == 0 {
918            0.0
919        } else {
920            self.items_processed as f64 / (self.elapsed_us as f64 / 1_000_000.0)
921        }
922    }
923    pub fn size_ratio(&self) -> f64 {
924        if self.bytes_before == 0 {
925            1.0
926        } else {
927            self.bytes_after as f64 / self.bytes_before as f64
928        }
929    }
930    pub fn is_profitable(&self) -> bool {
931        self.size_ratio() <= 1.05
932    }
933}
934/// Bidirectional mapping between LCNF types and C types.
935#[derive(Debug, Clone, Default)]
936pub struct FfiTypeMap {
937    /// LCNF type name -> FFI native type.
938    pub(super) lcnf_to_native: HashMap<String, FfiNativeType>,
939    /// FFI native type name -> LCNF type.
940    pub(super) native_to_lcnf: HashMap<String, LcnfType>,
941    /// Custom marshalling rules.
942    pub(super) custom_marshal: HashMap<String, FfiMarshalInfo>,
943}
944impl FfiTypeMap {
945    /// Create a new type map with default entries.
946    pub fn new() -> Self {
947        let mut map = FfiTypeMap::default();
948        map.register("Nat", FfiNativeType::U64, LcnfType::Nat);
949        map.register("String", FfiNativeType::CStr, LcnfType::LcnfString);
950        map.register("Unit", FfiNativeType::Void, LcnfType::Unit);
951        map.register("UInt8", FfiNativeType::U8, LcnfType::Nat);
952        map.register("UInt16", FfiNativeType::U16, LcnfType::Nat);
953        map.register("UInt32", FfiNativeType::U32, LcnfType::Nat);
954        map.register("UInt64", FfiNativeType::U64, LcnfType::Nat);
955        map.register("Int8", FfiNativeType::I8, LcnfType::Nat);
956        map.register("Int16", FfiNativeType::I16, LcnfType::Nat);
957        map.register("Int32", FfiNativeType::I32, LcnfType::Nat);
958        map.register("Int64", FfiNativeType::I64, LcnfType::Nat);
959        map.register("Float", FfiNativeType::F64, LcnfType::Nat);
960        map.register("Bool", FfiNativeType::Bool, LcnfType::Nat);
961        map
962    }
963    /// Register a bidirectional type mapping.
964    pub fn register(&mut self, name: &str, native: FfiNativeType, lcnf: LcnfType) {
965        self.lcnf_to_native.insert(name.to_string(), native.clone());
966        self.native_to_lcnf.insert(native.to_string(), lcnf);
967    }
968    /// Register a custom marshalling rule.
969    pub fn register_marshal(&mut self, name: &str, info: FfiMarshalInfo) {
970        self.custom_marshal.insert(name.to_string(), info);
971    }
972    /// Look up the native type for an LCNF type name.
973    pub fn to_native(&self, name: &str) -> Option<&FfiNativeType> {
974        self.lcnf_to_native.get(name)
975    }
976    /// Look up the LCNF type for a native type.
977    pub fn to_lcnf(&self, native_name: &str) -> Option<&LcnfType> {
978        self.native_to_lcnf.get(native_name)
979    }
980    /// Get custom marshalling for a type, if registered.
981    pub fn get_marshal(&self, name: &str) -> Option<&FfiMarshalInfo> {
982        self.custom_marshal.get(name)
983    }
984}
985/// FFI callback type
986#[allow(dead_code)]
987#[derive(Debug, Clone)]
988pub struct FfiCallbackType {
989    pub name: String,
990    pub ret_type: String,
991    pub params: Vec<FfiFuncParam>,
992    pub calling_conv: FfiCallingConv,
993}
994#[allow(dead_code)]
995#[derive(Debug, Clone)]
996pub struct FFIWorklist {
997    pub(super) items: std::collections::VecDeque<u32>,
998    pub(super) in_worklist: std::collections::HashSet<u32>,
999}
1000impl FFIWorklist {
1001    #[allow(dead_code)]
1002    pub fn new() -> Self {
1003        FFIWorklist {
1004            items: std::collections::VecDeque::new(),
1005            in_worklist: std::collections::HashSet::new(),
1006        }
1007    }
1008    #[allow(dead_code)]
1009    pub fn push(&mut self, item: u32) -> bool {
1010        if self.in_worklist.insert(item) {
1011            self.items.push_back(item);
1012            true
1013        } else {
1014            false
1015        }
1016    }
1017    #[allow(dead_code)]
1018    pub fn pop(&mut self) -> Option<u32> {
1019        let item = self.items.pop_front()?;
1020        self.in_worklist.remove(&item);
1021        Some(item)
1022    }
1023    #[allow(dead_code)]
1024    pub fn is_empty(&self) -> bool {
1025        self.items.is_empty()
1026    }
1027    #[allow(dead_code)]
1028    pub fn len(&self) -> usize {
1029        self.items.len()
1030    }
1031    #[allow(dead_code)]
1032    pub fn contains(&self, item: u32) -> bool {
1033        self.in_worklist.contains(&item)
1034    }
1035}
1036#[allow(dead_code)]
1037#[derive(Debug, Clone)]
1038pub struct FFIDepGraph {
1039    pub(super) nodes: Vec<u32>,
1040    pub(super) edges: Vec<(u32, u32)>,
1041}
1042impl FFIDepGraph {
1043    #[allow(dead_code)]
1044    pub fn new() -> Self {
1045        FFIDepGraph {
1046            nodes: Vec::new(),
1047            edges: Vec::new(),
1048        }
1049    }
1050    #[allow(dead_code)]
1051    pub fn add_node(&mut self, id: u32) {
1052        if !self.nodes.contains(&id) {
1053            self.nodes.push(id);
1054        }
1055    }
1056    #[allow(dead_code)]
1057    pub fn add_dep(&mut self, dep: u32, dependent: u32) {
1058        self.add_node(dep);
1059        self.add_node(dependent);
1060        self.edges.push((dep, dependent));
1061    }
1062    #[allow(dead_code)]
1063    pub fn dependents_of(&self, node: u32) -> Vec<u32> {
1064        self.edges
1065            .iter()
1066            .filter(|(d, _)| *d == node)
1067            .map(|(_, dep)| *dep)
1068            .collect()
1069    }
1070    #[allow(dead_code)]
1071    pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
1072        self.edges
1073            .iter()
1074            .filter(|(_, dep)| *dep == node)
1075            .map(|(d, _)| *d)
1076            .collect()
1077    }
1078    #[allow(dead_code)]
1079    pub fn topological_sort(&self) -> Vec<u32> {
1080        let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
1081        for &n in &self.nodes {
1082            in_degree.insert(n, 0);
1083        }
1084        for (_, dep) in &self.edges {
1085            *in_degree.entry(*dep).or_insert(0) += 1;
1086        }
1087        let mut queue: std::collections::VecDeque<u32> = self
1088            .nodes
1089            .iter()
1090            .filter(|&&n| in_degree[&n] == 0)
1091            .copied()
1092            .collect();
1093        let mut result = Vec::new();
1094        while let Some(node) = queue.pop_front() {
1095            result.push(node);
1096            for dep in self.dependents_of(node) {
1097                let cnt = in_degree.entry(dep).or_insert(0);
1098                *cnt = cnt.saturating_sub(1);
1099                if *cnt == 0 {
1100                    queue.push_back(dep);
1101                }
1102            }
1103        }
1104        result
1105    }
1106    #[allow(dead_code)]
1107    pub fn has_cycle(&self) -> bool {
1108        self.topological_sort().len() < self.nodes.len()
1109    }
1110}
1111/// FFI error code description
1112#[allow(dead_code)]
1113#[derive(Debug, Clone)]
1114pub struct FfiErrorCode {
1115    pub value: i32,
1116    pub name: String,
1117    pub description: String,
1118}
1119/// FFI code stats
1120#[allow(dead_code)]
1121#[derive(Debug, Default, Clone)]
1122pub struct FfiCodeStats {
1123    pub functions: usize,
1124    pub structs: usize,
1125    pub enums: usize,
1126    pub typedefs: usize,
1127    pub constants: usize,
1128    pub callbacks: usize,
1129    pub total_bytes: usize,
1130}
1131/// FFI rust bindings file
1132#[allow(dead_code)]
1133#[derive(Debug, Default)]
1134pub struct FfiRustBindingsFile {
1135    pub preamble: String,
1136    pub extern_c: Vec<FfiRustBinding>,
1137    pub types: Vec<FfiRustBinding>,
1138    pub constants: Vec<FfiRustBinding>,
1139}
1140#[allow(dead_code)]
1141impl FfiRustBindingsFile {
1142    pub fn new() -> Self {
1143        Self::default()
1144    }
1145    pub fn add_extern(&mut self, b: FfiRustBinding) {
1146        self.extern_c.push(b);
1147    }
1148    pub fn add_type(&mut self, b: FfiRustBinding) {
1149        self.types.push(b);
1150    }
1151    pub fn add_const(&mut self, b: FfiRustBinding) {
1152        self.constants.push(b);
1153    }
1154    pub fn emit(&self) -> String {
1155        let mut out = self.preamble.clone();
1156        if !self.types.is_empty() {
1157            out.push_str("\n// --- Types ---\n");
1158            for t in &self.types {
1159                out.push_str(&format!("{}\n", t.source));
1160            }
1161        }
1162        if !self.constants.is_empty() {
1163            out.push_str("\n// --- Constants ---\n");
1164            for c in &self.constants {
1165                out.push_str(&format!("{}\n", c.source));
1166            }
1167        }
1168        if !self.extern_c.is_empty() {
1169            out.push_str("\nextern \"C\" {\n");
1170            for e in &self.extern_c {
1171                out.push_str(&format!("    {}\n", e.source));
1172            }
1173            out.push_str("}\n");
1174        }
1175        out
1176    }
1177}
1178/// FFI typedef
1179#[allow(dead_code)]
1180#[derive(Debug, Clone)]
1181pub struct FfiTypedef {
1182    pub name: String,
1183    pub base_type: String,
1184}
1185/// FFI validation errors.
1186#[derive(Debug, Clone)]
1187pub enum FfiError {
1188    /// Unsupported type at FFI boundary.
1189    UnsupportedType(String),
1190    /// Invalid calling convention for the target.
1191    InvalidCallingConvention(CallingConvention, String),
1192    /// Parameter count mismatch.
1193    ParamCountMismatch { expected: usize, found: usize },
1194    /// Type mismatch at a parameter.
1195    TypeMismatch {
1196        param: String,
1197        expected: String,
1198        found: String,
1199    },
1200    /// Struct too large to pass by value.
1201    StructTooLarge { name: String, size: usize },
1202    /// Recursive type at FFI boundary.
1203    RecursiveType(String),
1204    /// Generic error message.
1205    Other(String),
1206}
1207/// The FFI bridge generator.
1208///
1209/// Produces Rust extern blocks, C headers, and wrapper functions
1210/// for interoperating between OxiLean and C code.
1211pub struct FfiBridge {
1212    /// Type mapping.
1213    pub(super) type_map: FfiTypeMap,
1214    /// Generated declarations.
1215    pub(super) declarations: Vec<FfiDecl>,
1216}
1217impl FfiBridge {
1218    /// Create a new FFI bridge with default type mappings.
1219    pub fn new() -> Self {
1220        FfiBridge {
1221            type_map: FfiTypeMap::new(),
1222            declarations: Vec::new(),
1223        }
1224    }
1225    /// Create an FFI bridge with a custom type map.
1226    pub fn with_type_map(type_map: FfiTypeMap) -> Self {
1227        FfiBridge {
1228            type_map,
1229            declarations: Vec::new(),
1230        }
1231    }
1232    /// Generate all FFI bindings for the given declarations.
1233    pub fn generate_bindings(&self, decls: &[FfiDecl]) -> FfiOutput {
1234        let mut output = FfiOutput::new();
1235        output.rust_bindings = self.generate_extern_block(decls);
1236        output.c_header = self.generate_c_header(decls);
1237        for decl in decls {
1238            let wrapper = self.generate_c_wrapper(decl);
1239            output.wrapper_fns.push(wrapper);
1240        }
1241        output
1242    }
1243    /// Generate a Rust `extern "C"` block for the given declarations.
1244    pub fn generate_extern_block(&self, decls: &[FfiDecl]) -> String {
1245        let mut code = String::new();
1246        code.push_str("// Auto-generated FFI bindings for OxiLean\n\n");
1247        let mut by_cc: BTreeMap<String, Vec<&FfiDecl>> = BTreeMap::new();
1248        for decl in decls {
1249            let cc = match decl.calling_conv {
1250                CallingConvention::C => "C",
1251                CallingConvention::Rust => "Rust",
1252                CallingConvention::System => "system",
1253                CallingConvention::Fastcall => "fastcall",
1254            };
1255            by_cc.entry(cc.to_string()).or_default().push(decl);
1256        }
1257        for (cc, cc_decls) in &by_cc {
1258            code.push_str(&format!("extern \"{}\" {{\n", cc));
1259            for decl in cc_decls {
1260                code.push_str("    ");
1261                if decl.is_unsafe {
1262                    code.push_str("// unsafe\n    ");
1263                }
1264                code.push_str(&format!("fn {}(", decl.extern_name));
1265                for (i, (pname, pty)) in decl.params.iter().enumerate() {
1266                    if i > 0 {
1267                        code.push_str(", ");
1268                    }
1269                    code.push_str(&format!("{}: {}", pname, pty.to_rust_type()));
1270                }
1271                let ret_str = decl.ret_type.to_rust_type();
1272                if ret_str == "()" {
1273                    code.push_str(");\n");
1274                } else {
1275                    code.push_str(&format!(") -> {};\n", ret_str));
1276                }
1277            }
1278            code.push_str("}\n\n");
1279        }
1280        code
1281    }
1282    /// Generate a C header with function prototypes.
1283    pub(super) fn generate_c_header(&self, decls: &[FfiDecl]) -> String {
1284        let mut code = String::new();
1285        code.push_str("/* Auto-generated C header for OxiLean FFI */\n\n");
1286        code.push_str("#ifndef OXILEAN_FFI_H\n");
1287        code.push_str("#define OXILEAN_FFI_H\n\n");
1288        code.push_str("#include <stdint.h>\n");
1289        code.push_str("#include <stddef.h>\n");
1290        code.push_str("#include <stdbool.h>\n");
1291        code.push_str("#include \"lean_runtime.h\"\n\n");
1292        code.push_str("#ifdef __cplusplus\n");
1293        code.push_str("extern \"C\" {\n");
1294        code.push_str("#endif\n\n");
1295        for decl in decls {
1296            code.push_str(&format!("/* {} */\n", decl.name));
1297            code.push_str(&format!("{} {}(", decl.ret_type, decl.extern_name));
1298            for (i, (pname, pty)) in decl.params.iter().enumerate() {
1299                if i > 0 {
1300                    code.push_str(", ");
1301                }
1302                code.push_str(&format!("{} {}", pty, pname));
1303            }
1304            if decl.params.is_empty() {
1305                code.push_str("void");
1306            }
1307            code.push_str(");\n\n");
1308        }
1309        code.push_str("#ifdef __cplusplus\n");
1310        code.push_str("}\n");
1311        code.push_str("#endif\n\n");
1312        code.push_str("#endif /* OXILEAN_FFI_H */\n");
1313        code
1314    }
1315    /// Generate a C wrapper function that calls an OxiLean function
1316    /// via the Lean runtime.
1317    pub fn generate_c_wrapper(&self, decl: &FfiDecl) -> String {
1318        let mut code = String::new();
1319        code.push_str(&format!("/* Wrapper for {} */\n", decl.name));
1320        code.push_str(&format!("{} {}_wrapper(", decl.ret_type, decl.extern_name));
1321        for (i, (pname, pty)) in decl.params.iter().enumerate() {
1322            if i > 0 {
1323                code.push_str(", ");
1324            }
1325            code.push_str(&format!("{} {}", pty, pname));
1326        }
1327        if decl.params.is_empty() {
1328            code.push_str("void");
1329        }
1330        code.push_str(") {\n");
1331        let mut lean_args = Vec::new();
1332        for (pname, pty) in &decl.params {
1333            let marshal = marshal_native_to_lean(pty, pname);
1334            if marshal.is_trivial {
1335                lean_args.push(pname.clone());
1336            } else {
1337                let lean_var = format!("_lean_{}", pname);
1338                code.push_str(&format!(
1339                    "  lean_object* {} = {};\n",
1340                    lean_var,
1341                    marshal.to_native.replace("${arg}", pname),
1342                ));
1343                lean_args.push(lean_var);
1344            }
1345        }
1346        let mangled_name = mangle_lean_name(&decl.name);
1347        if decl.ret_type == FfiNativeType::Void {
1348            code.push_str(&format!("  {}(", mangled_name));
1349            code.push_str(&lean_args.join(", "));
1350            code.push_str(");\n");
1351        } else {
1352            code.push_str(&format!("  lean_object* _result = {}(", mangled_name));
1353            code.push_str(&lean_args.join(", "));
1354            code.push_str(");\n");
1355            let ret_marshal = marshal_lean_to_native(&decl.ret_type, "_result");
1356            if ret_marshal.is_trivial {
1357                code.push_str("  return _result;\n");
1358            } else {
1359                code.push_str(&format!(
1360                    "  {} _native_result = {};\n",
1361                    decl.ret_type,
1362                    ret_marshal.from_native.replace("${result}", "_result"),
1363                ));
1364                code.push_str("  lean_dec_ref(_result);\n");
1365                code.push_str("  return _native_result;\n");
1366            }
1367        }
1368        code.push_str("}\n");
1369        code
1370    }
1371    /// Get the type map.
1372    pub fn type_map(&self) -> &FfiTypeMap {
1373        &self.type_map
1374    }
1375    /// Get a mutable reference to the type map.
1376    pub fn type_map_mut(&mut self) -> &mut FfiTypeMap {
1377        &mut self.type_map
1378    }
1379}
1380/// Pipeline profiler for FfiExt.
1381#[derive(Debug, Default)]
1382pub struct FfiExtProfiler {
1383    pub(super) timings: Vec<FfiExtPassTiming>,
1384}
1385impl FfiExtProfiler {
1386    pub fn new() -> Self {
1387        FfiExtProfiler::default()
1388    }
1389    pub fn record(&mut self, t: FfiExtPassTiming) {
1390        self.timings.push(t);
1391    }
1392    pub fn total_elapsed_us(&self) -> u64 {
1393        self.timings.iter().map(|t| t.elapsed_us).sum()
1394    }
1395    pub fn slowest_pass(&self) -> Option<&FfiExtPassTiming> {
1396        self.timings.iter().max_by_key(|t| t.elapsed_us)
1397    }
1398    pub fn num_passes(&self) -> usize {
1399        self.timings.len()
1400    }
1401    pub fn profitable_passes(&self) -> Vec<&FfiExtPassTiming> {
1402        self.timings.iter().filter(|t| t.is_profitable()).collect()
1403    }
1404}
1405/// FFI size hint
1406#[allow(dead_code)]
1407#[derive(Debug, Clone)]
1408pub enum FfiSizeHint {
1409    Fixed(u64),
1410    Param(String),
1411    Dynamic,
1412}
1413/// FFI rust-side generated binding
1414#[allow(dead_code)]
1415#[derive(Debug, Clone)]
1416pub struct FfiRustBinding {
1417    pub name: String,
1418    pub kind: FfiRustBindingKind,
1419    pub source: String,
1420}
1421/// FFI pass summary
1422#[allow(dead_code)]
1423#[derive(Debug, Default, Clone)]
1424pub struct FfiPassSummary {
1425    pub pass_name: String,
1426    pub symbols_bridged: usize,
1427    pub headers_emitted: usize,
1428    pub rust_bindings_emitted: usize,
1429    pub duration_us: u64,
1430}
1431/// Calling convention for FFI functions.
1432#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1433pub enum CallingConvention {
1434    /// Standard C calling convention.
1435    C,
1436    /// Rust calling convention (default for Rust functions).
1437    Rust,
1438    /// System calling convention (stdcall on Windows, C on other platforms).
1439    System,
1440    /// Fastcall (register-based for first N arguments).
1441    Fastcall,
1442}
1443/// FFI return value wrapper
1444#[allow(dead_code)]
1445#[derive(Debug, Clone)]
1446pub enum FfiReturnWrap {
1447    Direct(String),
1448    ErrorCode(String, String),
1449    OutParam(String),
1450    Bool(String),
1451}
1452/// FFI object descriptor
1453#[allow(dead_code)]
1454#[derive(Debug, Clone)]
1455pub struct FfiObjectDesc {
1456    pub c_type: String,
1457    pub rust_type: String,
1458    pub lifetime: FfiLifetime,
1459    pub destroy_fn: Option<String>,
1460    pub clone_fn: Option<String>,
1461}
1462/// FFI extended config
1463#[allow(dead_code)]
1464#[derive(Debug, Clone)]
1465pub struct FfiExtConfigV2 {
1466    pub platform: FfiPlatformTarget,
1467    pub emit_c_header: bool,
1468    pub emit_rust_bindings: bool,
1469    pub emit_python_cffi: bool,
1470    pub emit_zig_bindings: bool,
1471    pub header_guard_prefix: String,
1472    pub lib_name: String,
1473    pub calling_conv_default: FfiCallingConv,
1474    pub enable_null_checks: bool,
1475    pub enable_bounds_checks: bool,
1476}
1477/// FFI feature flags
1478#[allow(dead_code)]
1479#[derive(Debug, Clone, Default)]
1480pub struct FfiFeatureFlags {
1481    pub support_varargs: bool,
1482    pub support_callbacks: bool,
1483    pub support_bitfields: bool,
1484    pub support_anonymous: bool,
1485    pub support_packed: bool,
1486    pub support_aligned: bool,
1487}
1488/// Heuristic freshness key for FfiExt incremental compilation.
1489#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1490pub struct FfiExtIncrKey {
1491    pub content_hash: u64,
1492    pub config_hash: u64,
1493}
1494impl FfiExtIncrKey {
1495    pub fn new(content: u64, config: u64) -> Self {
1496        FfiExtIncrKey {
1497            content_hash: content,
1498            config_hash: config,
1499        }
1500    }
1501    pub fn combined_hash(&self) -> u64 {
1502        self.content_hash.wrapping_mul(0x9e3779b97f4a7c15) ^ self.config_hash
1503    }
1504    pub fn matches(&self, other: &FfiExtIncrKey) -> bool {
1505        self.content_hash == other.content_hash && self.config_hash == other.config_hash
1506    }
1507}
1508/// A generic key-value configuration store for FfiExt.
1509#[derive(Debug, Clone, Default)]
1510pub struct FfiExtConfig {
1511    pub(super) entries: std::collections::HashMap<String, String>,
1512}
1513impl FfiExtConfig {
1514    pub fn new() -> Self {
1515        FfiExtConfig::default()
1516    }
1517    pub fn set(&mut self, key: impl Into<String>, value: impl Into<String>) {
1518        self.entries.insert(key.into(), value.into());
1519    }
1520    pub fn get(&self, key: &str) -> Option<&str> {
1521        self.entries.get(key).map(|s| s.as_str())
1522    }
1523    pub fn get_bool(&self, key: &str) -> bool {
1524        matches!(self.get(key), Some("true") | Some("1") | Some("yes"))
1525    }
1526    pub fn get_int(&self, key: &str) -> Option<i64> {
1527        self.get(key)?.parse().ok()
1528    }
1529    pub fn len(&self) -> usize {
1530        self.entries.len()
1531    }
1532    pub fn is_empty(&self) -> bool {
1533        self.entries.is_empty()
1534    }
1535}
1536/// FFI bridge summary v2
1537#[allow(dead_code)]
1538#[derive(Debug, Default)]
1539pub struct FfiBridgeSummaryV2 {
1540    pub lib_name: String,
1541    pub platform: String,
1542    pub funcs: usize,
1543    pub structs: usize,
1544    pub enums: usize,
1545    pub bytes: usize,
1546}
1547#[allow(dead_code)]
1548pub struct FFIConstantFoldingHelper;
1549impl FFIConstantFoldingHelper {
1550    #[allow(dead_code)]
1551    pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
1552        a.checked_add(b)
1553    }
1554    #[allow(dead_code)]
1555    pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
1556        a.checked_sub(b)
1557    }
1558    #[allow(dead_code)]
1559    pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
1560        a.checked_mul(b)
1561    }
1562    #[allow(dead_code)]
1563    pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
1564        if b == 0 {
1565            None
1566        } else {
1567            a.checked_div(b)
1568        }
1569    }
1570    #[allow(dead_code)]
1571    pub fn fold_add_f64(a: f64, b: f64) -> f64 {
1572        a + b
1573    }
1574    #[allow(dead_code)]
1575    pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
1576        a * b
1577    }
1578    #[allow(dead_code)]
1579    pub fn fold_neg_i64(a: i64) -> Option<i64> {
1580        a.checked_neg()
1581    }
1582    #[allow(dead_code)]
1583    pub fn fold_not_bool(a: bool) -> bool {
1584        !a
1585    }
1586    #[allow(dead_code)]
1587    pub fn fold_and_bool(a: bool, b: bool) -> bool {
1588        a && b
1589    }
1590    #[allow(dead_code)]
1591    pub fn fold_or_bool(a: bool, b: bool) -> bool {
1592        a || b
1593    }
1594    #[allow(dead_code)]
1595    pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
1596        a.checked_shl(b)
1597    }
1598    #[allow(dead_code)]
1599    pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
1600        a.checked_shr(b)
1601    }
1602    #[allow(dead_code)]
1603    pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
1604        if b == 0 {
1605            None
1606        } else {
1607            Some(a % b)
1608        }
1609    }
1610    #[allow(dead_code)]
1611    pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
1612        a & b
1613    }
1614    #[allow(dead_code)]
1615    pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
1616        a | b
1617    }
1618    #[allow(dead_code)]
1619    pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
1620        a ^ b
1621    }
1622    #[allow(dead_code)]
1623    pub fn fold_bitnot_i64(a: i64) -> i64 {
1624        !a
1625    }
1626}
1627#[allow(dead_code)]
1628#[derive(Debug, Clone)]
1629pub struct FFIAnalysisCache {
1630    pub(super) entries: std::collections::HashMap<String, FFICacheEntry>,
1631    pub(super) max_size: usize,
1632    pub(super) hits: u64,
1633    pub(super) misses: u64,
1634}
1635impl FFIAnalysisCache {
1636    #[allow(dead_code)]
1637    pub fn new(max_size: usize) -> Self {
1638        FFIAnalysisCache {
1639            entries: std::collections::HashMap::new(),
1640            max_size,
1641            hits: 0,
1642            misses: 0,
1643        }
1644    }
1645    #[allow(dead_code)]
1646    pub fn get(&mut self, key: &str) -> Option<&FFICacheEntry> {
1647        if self.entries.contains_key(key) {
1648            self.hits += 1;
1649            self.entries.get(key)
1650        } else {
1651            self.misses += 1;
1652            None
1653        }
1654    }
1655    #[allow(dead_code)]
1656    pub fn insert(&mut self, key: String, data: Vec<u8>) {
1657        if self.entries.len() >= self.max_size {
1658            if let Some(oldest) = self.entries.keys().next().cloned() {
1659                self.entries.remove(&oldest);
1660            }
1661        }
1662        self.entries.insert(
1663            key.clone(),
1664            FFICacheEntry {
1665                key,
1666                data,
1667                timestamp: 0,
1668                valid: true,
1669            },
1670        );
1671    }
1672    #[allow(dead_code)]
1673    pub fn invalidate(&mut self, key: &str) {
1674        if let Some(entry) = self.entries.get_mut(key) {
1675            entry.valid = false;
1676        }
1677    }
1678    #[allow(dead_code)]
1679    pub fn clear(&mut self) {
1680        self.entries.clear();
1681    }
1682    #[allow(dead_code)]
1683    pub fn hit_rate(&self) -> f64 {
1684        let total = self.hits + self.misses;
1685        if total == 0 {
1686            return 0.0;
1687        }
1688        self.hits as f64 / total as f64
1689    }
1690    #[allow(dead_code)]
1691    pub fn size(&self) -> usize {
1692        self.entries.len()
1693    }
1694}
1695/// FFI struct field
1696#[allow(dead_code)]
1697#[derive(Debug, Clone)]
1698pub struct FfiStructField {
1699    pub name: String,
1700    pub field_type: String,
1701    pub bit_width: Option<u8>,
1702    pub offset_bytes: Option<u64>,
1703    pub attrs: Vec<String>,
1704}
1705#[allow(dead_code)]
1706#[derive(Debug, Clone)]
1707pub struct FFILivenessInfo {
1708    pub live_in: Vec<std::collections::HashSet<u32>>,
1709    pub live_out: Vec<std::collections::HashSet<u32>>,
1710    pub defs: Vec<std::collections::HashSet<u32>>,
1711    pub uses: Vec<std::collections::HashSet<u32>>,
1712}
1713impl FFILivenessInfo {
1714    #[allow(dead_code)]
1715    pub fn new(block_count: usize) -> Self {
1716        FFILivenessInfo {
1717            live_in: vec![std::collections::HashSet::new(); block_count],
1718            live_out: vec![std::collections::HashSet::new(); block_count],
1719            defs: vec![std::collections::HashSet::new(); block_count],
1720            uses: vec![std::collections::HashSet::new(); block_count],
1721        }
1722    }
1723    #[allow(dead_code)]
1724    pub fn add_def(&mut self, block: usize, var: u32) {
1725        if block < self.defs.len() {
1726            self.defs[block].insert(var);
1727        }
1728    }
1729    #[allow(dead_code)]
1730    pub fn add_use(&mut self, block: usize, var: u32) {
1731        if block < self.uses.len() {
1732            self.uses[block].insert(var);
1733        }
1734    }
1735    #[allow(dead_code)]
1736    pub fn is_live_in(&self, block: usize, var: u32) -> bool {
1737        self.live_in
1738            .get(block)
1739            .map(|s| s.contains(&var))
1740            .unwrap_or(false)
1741    }
1742    #[allow(dead_code)]
1743    pub fn is_live_out(&self, block: usize, var: u32) -> bool {
1744        self.live_out
1745            .get(block)
1746            .map(|s| s.contains(&var))
1747            .unwrap_or(false)
1748    }
1749}
1750/// FFI object lifetime kind
1751#[allow(dead_code)]
1752#[derive(Debug, Clone, PartialEq, Eq)]
1753pub enum FfiLifetime {
1754    Static,
1755    ScopedToCall,
1756    CallerManaged,
1757    LibraryManaged,
1758    RefCounted,
1759}
1760/// FFI struct definition
1761#[allow(dead_code)]
1762#[derive(Debug, Clone)]
1763pub struct FfiStructDef {
1764    pub name: String,
1765    pub fields: Vec<FfiStructField>,
1766    pub alignment: Option<u64>,
1767    pub is_packed: bool,
1768    pub is_union: bool,
1769}
1770/// Severity of a FfiExt diagnostic.
1771#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1772pub enum FfiExtDiagSeverity {
1773    Note,
1774    Warning,
1775    Error,
1776}
1777/// FFI function signature
1778#[allow(dead_code)]
1779#[derive(Debug, Clone)]
1780pub struct FfiFuncSignature {
1781    pub name: String,
1782    pub params: Vec<FfiFuncParam>,
1783    pub ret_type: String,
1784    pub calling_conv: FfiCallingConv,
1785    pub is_async: bool,
1786    pub is_noexcept: bool,
1787    pub is_nothrow: bool,
1788}
1789/// A text buffer for building FfiExt output source code.
1790#[derive(Debug, Default)]
1791pub struct FfiExtSourceBuffer {
1792    pub(super) buf: String,
1793    pub(super) indent_level: usize,
1794    pub(super) indent_str: String,
1795}
1796impl FfiExtSourceBuffer {
1797    pub fn new() -> Self {
1798        FfiExtSourceBuffer {
1799            buf: String::new(),
1800            indent_level: 0,
1801            indent_str: "    ".to_string(),
1802        }
1803    }
1804    pub fn with_indent(mut self, indent: impl Into<String>) -> Self {
1805        self.indent_str = indent.into();
1806        self
1807    }
1808    pub fn push_line(&mut self, line: &str) {
1809        for _ in 0..self.indent_level {
1810            self.buf.push_str(&self.indent_str);
1811        }
1812        self.buf.push_str(line);
1813        self.buf.push('\n');
1814    }
1815    pub fn push_raw(&mut self, s: &str) {
1816        self.buf.push_str(s);
1817    }
1818    pub fn indent(&mut self) {
1819        self.indent_level += 1;
1820    }
1821    pub fn dedent(&mut self) {
1822        self.indent_level = self.indent_level.saturating_sub(1);
1823    }
1824    pub fn as_str(&self) -> &str {
1825        &self.buf
1826    }
1827    pub fn len(&self) -> usize {
1828        self.buf.len()
1829    }
1830    pub fn is_empty(&self) -> bool {
1831        self.buf.is_empty()
1832    }
1833    pub fn line_count(&self) -> usize {
1834        self.buf.lines().count()
1835    }
1836    pub fn into_string(self) -> String {
1837        self.buf
1838    }
1839    pub fn reset(&mut self) {
1840        self.buf.clear();
1841        self.indent_level = 0;
1842    }
1843}
1844/// FFI function parameter
1845#[allow(dead_code)]
1846#[derive(Debug, Clone)]
1847pub struct FfiFuncParam {
1848    pub name: String,
1849    pub ffi_type: String,
1850    pub attrs: Vec<FfiParamAttr>,
1851    pub is_vararg: bool,
1852}
1853/// Emission statistics for FfiExt.
1854#[derive(Debug, Clone, Default)]
1855pub struct FfiExtEmitStats {
1856    pub bytes_emitted: usize,
1857    pub items_emitted: usize,
1858    pub errors: usize,
1859    pub warnings: usize,
1860    pub elapsed_ms: u64,
1861}
1862impl FfiExtEmitStats {
1863    pub fn new() -> Self {
1864        FfiExtEmitStats::default()
1865    }
1866    pub fn throughput_bps(&self) -> f64 {
1867        if self.elapsed_ms == 0 {
1868            0.0
1869        } else {
1870            self.bytes_emitted as f64 / (self.elapsed_ms as f64 / 1000.0)
1871        }
1872    }
1873    pub fn is_clean(&self) -> bool {
1874        self.errors == 0
1875    }
1876}
1877/// FFI constant
1878#[allow(dead_code)]
1879#[derive(Debug, Clone)]
1880pub struct FfiConst {
1881    pub name: String,
1882    pub const_type: String,
1883    pub value: String,
1884}