Skip to main content

lean_rs_sys/
array.rs

1//! Object and scalar arrays — externs and inline accessors from
2//! `lean.h:815–1028`.
3
4#![allow(clippy::inline_always)]
5// `lean_alloc_sarray` takes `elem_size: u32` to mirror the C `unsigned`
6// signature but stores the value in `m_other` (u8). The truncation is
7// gated by a documented caller precondition (`elem_size <= u8::MAX`).
8#![allow(clippy::cast_possible_truncation)]
9
10use core::mem::size_of;
11
12use crate::consts::{LEAN_ARRAY, LEAN_SCALAR_ARRAY};
13use crate::object::lean_alloc_object;
14use crate::repr::{LeanArrayObjectRepr, LeanObjectRepr, LeanSArrayObjectRepr};
15use crate::types::{b_lean_obj_arg, lean_obj_arg, lean_obj_res, lean_object};
16
17unsafe extern "C" {
18    pub fn lean_array_mk(l: lean_obj_arg) -> *mut lean_object;
19    pub fn lean_array_to_list(a: lean_obj_arg) -> *mut lean_object;
20    pub fn lean_array_get_panic(def_val: lean_obj_arg) -> lean_obj_res;
21    pub fn lean_array_set_panic(a: lean_obj_arg, v: lean_obj_arg) -> lean_obj_res;
22    pub fn lean_array_push(a: lean_obj_arg, v: lean_obj_arg) -> *mut lean_object;
23    pub fn lean_mk_array(n: lean_obj_arg, v: lean_obj_arg) -> *mut lean_object;
24}
25
26/// Allocate a freshly initialised object array (`lean.h:816–822`).
27///
28/// Returns a `LeanArray`-tagged object with `m_size = size`,
29/// `m_capacity = capacity`, and `capacity` uninitialised `*mut lean_object`
30/// slots. The caller installs each slot via [`lean_array_set_core`] before
31/// the array escapes; the first `size` slots become the visible elements.
32///
33/// # Safety
34///
35/// * `size <= capacity`.
36/// * `size_of::<LeanArrayObjectRepr>() + size_of::<*mut lean_object>() * capacity`
37///   must not overflow `usize`; the helper checks this with `strict_*`
38///   arithmetic and panics on overflow.
39/// * Every one of the first `size` element slots must be initialised with a
40///   live owned `*mut lean_object` (matching the C convention that
41///   `lean_dec` on the array recursively decrements each visible element)
42///   before the array is observed by any other Lean code.
43#[inline(always)]
44pub unsafe fn lean_alloc_array(size: usize, capacity: usize) -> lean_obj_res {
45    let total = size_of::<LeanArrayObjectRepr>().strict_add(size_of::<*mut lean_object>().strict_mul(capacity));
46    // SAFETY: `lean_alloc_object` returns a non-null pointer to `total` bytes
47    // of uninitialised Lean-managed memory; we install the object-array
48    // header before returning so the object is immediately well-formed for
49    // every existing predicate (`lean_is_array`, `lean_array_*`). Element
50    // slots remain uninitialised — the caller's obligation per the docs
51    // above.
52    unsafe {
53        let o = lean_alloc_object(total);
54        let header = o.cast::<LeanObjectRepr>();
55        (*header).m_rc = 1;
56        (*header).m_tag = LEAN_ARRAY;
57        (*header).m_other = 0;
58        let array = o.cast::<LeanArrayObjectRepr>();
59        (*array).size = size;
60        (*array).capacity = capacity;
61        o
62    }
63}
64
65/// Allocate a freshly initialised scalar-array (`lean.h:1004–1010`).
66///
67/// Returns a `LeanScalarArray`-tagged object with `m_size = size`,
68/// `m_capacity = capacity`, and `elem_size` bytes per element. The
69/// payload bytes are uninitialised; the caller must write to
70/// [`lean_sarray_cptr`] before the array escapes.
71///
72/// # Safety
73///
74/// * `elem_size` must fit a `u8` (Lean stores it in `m_other`) and must be
75///   one of `{1, 2, 4, 8}` for the existing scalar-array consumers
76///   (`ByteArray` uses `1`).
77/// * `size <= capacity`.
78/// * `size_of::<LeanSArrayObjectRepr>() + elem_size * capacity` must not
79///   overflow `usize`; the helper checks this with `strict_*` arithmetic
80///   and panics on overflow (mirroring `lean_alloc_sarray_would_overflow`).
81#[inline(always)]
82pub unsafe fn lean_alloc_sarray(elem_size: u32, size: usize, capacity: usize) -> lean_obj_res {
83    let elem_size_usize = elem_size as usize;
84    let total = size_of::<LeanSArrayObjectRepr>().strict_add(elem_size_usize.strict_mul(capacity));
85    // SAFETY: `lean_alloc_object` returns a non-null pointer to `total` bytes
86    // of uninitialised Lean-managed memory; we install the scalar-array
87    // header before returning so the object is immediately well-formed for
88    // every existing predicate (`lean_is_sarray`, `lean_sarray_*`).
89    unsafe {
90        let o = lean_alloc_object(total);
91        let header = o.cast::<LeanObjectRepr>();
92        (*header).m_rc = 1;
93        (*header).m_tag = LEAN_SCALAR_ARRAY;
94        // `elem_size` is asserted by the caller to fit a `u8`; cast loss
95        // is impossible inside the documented contract.
96        (*header).m_other = elem_size as u8;
97        let sarray = o.cast::<LeanSArrayObjectRepr>();
98        (*sarray).size = size;
99        (*sarray).capacity = capacity;
100        o
101    }
102}
103
104#[inline(always)]
105unsafe fn as_array<'a>(o: *mut lean_object) -> &'a LeanArrayObjectRepr {
106    // SAFETY: caller asserts `o` is a Lean array object.
107    unsafe { &*o.cast::<LeanArrayObjectRepr>() }
108}
109
110#[inline(always)]
111unsafe fn as_sarray<'a>(o: *mut lean_object) -> &'a LeanSArrayObjectRepr {
112    // SAFETY: caller asserts `o` is a Lean scalar-array object.
113    unsafe { &*o.cast::<LeanSArrayObjectRepr>() }
114}
115
116/// `m_size` of an object array (`lean.h:823`).
117///
118/// # Safety
119///
120/// `o` must be a borrowed Lean array object.
121#[inline(always)]
122pub unsafe fn lean_array_size(o: b_lean_obj_arg) -> usize {
123    // SAFETY: precondition above.
124    unsafe { as_array(o).size }
125}
126
127/// `m_capacity` of an object array (`lean.h:824`).
128///
129/// # Safety
130///
131/// Same as [`lean_array_size`].
132#[inline(always)]
133pub unsafe fn lean_array_capacity(o: b_lean_obj_arg) -> usize {
134    // SAFETY: precondition above.
135    unsafe { as_array(o).capacity }
136}
137
138/// Pointer to the array's element storage (`lean.h:831`).
139///
140/// # Safety
141///
142/// Same as [`lean_array_size`]. The returned pointer is valid for
143/// `lean_array_capacity(o)` elements.
144#[inline(always)]
145pub unsafe fn lean_array_cptr(o: *mut lean_object) -> *mut *mut lean_object {
146    // SAFETY: precondition above; flexible-array member offset is fixed.
147    // `&raw mut` keeps us in pointer-land so there is no constness laundering.
148    unsafe { (&raw mut (*o.cast::<LeanArrayObjectRepr>()).data).cast::<*mut lean_object>() }
149}
150
151/// Borrow element `i` of an object array (`lean.h:838–841`).
152///
153/// # Safety
154///
155/// `o` must be a borrowed Lean array object and `i < lean_array_size(o)`.
156#[inline(always)]
157pub unsafe fn lean_array_get_core(o: b_lean_obj_arg, i: usize) -> *mut lean_object {
158    // SAFETY: precondition above.
159    unsafe { *lean_array_cptr(o).add(i) }
160}
161
162/// Write element `i` of an object array (`lean.h:842–848`).
163///
164/// # Safety
165///
166/// `o` must be a unique (exclusive) Lean array object and `i <
167/// lean_array_size(o)`. The caller transfers ownership of `v`.
168#[inline(always)]
169pub unsafe fn lean_array_set_core(o: *mut lean_object, i: usize, v: lean_obj_arg) {
170    // SAFETY: precondition above.
171    unsafe { *lean_array_cptr(o).add(i) = v }
172}
173
174/// Element size of a scalar array (`lean.h:1011–1014`).
175///
176/// # Safety
177///
178/// `o` must be a borrowed Lean scalar-array object.
179#[inline(always)]
180pub unsafe fn lean_sarray_elem_size(o: *mut lean_object) -> u8 {
181    // SAFETY: stored in m_other; layout pinned by build digest.
182    unsafe { crate::object::lean_ptr_other(o) }
183}
184
185/// `m_size` of a scalar array (`lean.h:1019`).
186///
187/// # Safety
188///
189/// `o` must be a borrowed Lean scalar-array object.
190#[inline(always)]
191pub unsafe fn lean_sarray_size(o: b_lean_obj_arg) -> usize {
192    // SAFETY: precondition above.
193    unsafe { as_sarray(o).size }
194}
195
196/// `m_capacity` of a scalar array (`lean.h:1015`).
197///
198/// # Safety
199///
200/// Same as [`lean_sarray_size`].
201#[inline(always)]
202pub unsafe fn lean_sarray_capacity(o: *mut lean_object) -> usize {
203    // SAFETY: precondition above.
204    unsafe { as_sarray(o).capacity }
205}
206
207/// Pointer to the scalar array's byte storage (`lean.h:1028`).
208///
209/// # Safety
210///
211/// Same as [`lean_sarray_size`]. The returned pointer is valid for
212/// `lean_sarray_capacity(o) * lean_sarray_elem_size(o)` bytes.
213#[inline(always)]
214pub unsafe fn lean_sarray_cptr(o: *mut lean_object) -> *mut u8 {
215    // SAFETY: precondition above; flexible-array member offset is fixed.
216    unsafe { (&raw mut (*o.cast::<LeanSArrayObjectRepr>()).data).cast::<u8>() }
217}