1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
//! Conversion traits for first-order Lean values.
//!
//! Three sealed traits with distinct roles:
//!
//! - [`IntoLean`] / [`TryFromLean`] (`pub(crate)`) — convert between Rust
//! values and polymorphic-boxed [`Obj`]. Used for container elements,
//! structure fields, and any Lean position where the value lives behind
//! a `lean_object*`. The classic encoding/decoding direction.
//! - [`LeanAbi`] (`pub`, sealed) — convert between Rust values and the
//! *C-ABI representation* Lake emits for a top-level Lean export
//! parameter or return. The C representation varies: `uint8_t` for
//! `Bool`, `uint32_t` for `Char`, `double` for `Float`, scalar primitive
//! for `UIntN`/`UIntN`, and `lean_object*` for everything boxed. This
//! trait drives [`crate::module::LeanExported`]'s typed function-pointer
//! cast.
//!
//! Per `RD-2026-05-17-007`, `LeanAbi` is the third (and final) conversion
//! trait. It coexists with `IntoLean`/`TryFromLean` because they encode
//! different conventions for the same Rust type — `u8 as IntoLean`
//! produces a polymorphic-boxed `lean_box(u8 as usize)`, while
//! `u8 as LeanAbi` produces an unboxed `uint8_t` matching Lake's emitted
//! signature.
//!
//! Borrowed conversions do not introduce a new trait. Where a Rust
//! borrowed type appears in a Lean export's argument tuple, the per-type
//! module adds an `impl LeanAbi for &T` rather than a new
//! `BorrowedLeanAbi` trait. The `&str` impl in `super::string` is the
//! earned case: `LeanSession::elaborate`, `kernel_check`, `elaborate_bulk`,
//! and `make_name` each accepted `&str` from callers and previously paid
//! a `String::to_owned()` only to reach `LeanAbi<'lean> for String`.
//! Borrowed-only reads (`borrow_str`) stay as free functions because they
//! are zero-copy *return*-direction helpers and never need to satisfy the
//! `LeanAbi` arg-tuple bound.
use lean_object;
use crate;
use crate;
use crateLeanRuntime;
use crateObj;
/// Move a Rust value into a freshly owned Lean object.
///
/// The returned [`Obj`] carries exactly one Lean reference count and is
/// anchored to the `&'lean LeanRuntime` borrow that witnessed the call.
/// Decode an owned Lean object into a Rust value.
///
/// Consumes the [`Obj`] — even on failure, the refcount is released by
/// `obj`'s `Drop`. The function signature returns the error type without
/// the Obj because the cases where the caller wants to recover the
/// original `Obj` are rare; if they arise, we will add a `try_from_lean_ref`
/// variant against an `ObjRef` rather than complicating this trait.
/// Build a `LeanError::Host { stage: Conversion, .. }` carrying a uniform
/// diagnostic.
///
/// Centralised so per-type ABI impls share the wording and so a future
/// log/sink can hook one site instead of N.
// -- Sealing for LeanAbi -----------------------------------------------
/// Supertrait that seals [`LeanAbi`] against external implementations.
///
/// The module is `pub` (not `pub(crate)`) because Cargo has no "friend
/// crate" visibility and the sibling [`lean-rs-host`](https://docs.rs/lean-rs-host)
/// crate genuinely needs to implement `LeanAbi` for its own
/// host-defined types (`LeanEvidence` etc.) — that's exactly what the
/// L1 → L2 seam is for. The pattern that holds is:
///
/// - **External crates** (anyone other than `lean-rs-host`) cannot
/// implement `LeanAbi` for their own types: the orphan rule blocks
/// `impl LeanAbi for MyType` directly, and writing
/// `impl SealedAbi for MyType` is a transparent intent-to-bypass
/// that any honest reviewer should reject — combined with the
/// `#[doc(hidden)]` module marker on the parent module's seam
/// re-exports, the signal is unambiguous.
/// - **The sibling `lean-rs-host` crate** reaches `SealedAbi` directly
/// and implements both `SealedAbi` and `LeanAbi` for its host types.
/// This is intentional; the sealing is against accidental external
/// impls, not the same-team L2 stack.
/// Per-type C-ABI representation used by [`crate::module::LeanExported`].
///
/// Lake emits unboxed C primitives for `UIntN`/`IntN`/`USize`/`ISize`/
/// `Bool`/`Char`/`Float` exports; boxed `lean_object*` for everything else
/// (`String`, `ByteArray`, `Nat`, `Int`, structures, IO results, …). The
/// per-type [`CRepr`](LeanAbi::CRepr) records which convention applies.
///
/// `into_c` / `from_c` are paired: a type's `CRepr` is invariant between
/// the encode and decode directions, so they live on one trait (Ousterhout
/// ch 9 — combining concerns that share information).
///
/// Sealed via [`sealed::SealedAbi`]. External crates cannot implement
/// this trait for their own types (orphan rule + sealed supertrait
/// rejection). The sibling `lean-rs-host` crate reaches the seam
/// intentionally and implements `LeanAbi` for its host-defined
/// types — that's the documented L1 → L2 extension point, not a
/// stability violation.
// -- LeanAbi for Obj<'lean> -------------------------------------------
//
// The identity impl: `Obj<'lean>` already IS the boxed C ABI shape.
// Lets `LeanExported<(Obj,), Obj>` work for tests that pass Lean values
// constructed via per-type helpers (`nat::from_u64`, `string::from_str`,
// …) directly without re-typing.
// `Obj<'lean>: TryFromLean<'lean>` is the identity decoder. It lets a
// caller write `LeanIo<Obj<'lean>>` as the typed handle's return type to
// get the raw IO payload back as an `Obj`, then decode through a
// per-type helper (`nat::try_to_u64`, `ctor_tag`, …) when the value
// shape doesn't fit a polymorphic-boxing `TryFromLean` impl.
//
// `Obj<'lean>` deliberately does NOT implement `IntoLean<'lean>` —
// passing an `Obj` as an argument goes through `LeanAbi::into_c`
// (identity), not through the polymorphic-boxing path.