#![allow(clippy::inline_always)]
use core::mem::size_of;
use crate::object::lean_alloc_object;
use crate::repr::{LeanCtorObjectRepr, LeanObjectRepr};
use crate::types::{b_lean_obj_arg, lean_obj_res, lean_object};
#[inline(always)]
unsafe fn set_st_header(o: *mut lean_object, tag: u8, other: u8) {
unsafe {
let repr = o.cast::<LeanObjectRepr>();
(*repr).m_rc = 1;
(*repr).m_tag = tag;
(*repr).m_other = other;
}
}
#[inline(always)]
pub unsafe fn lean_ctor_num_objs(o: b_lean_obj_arg) -> u8 {
unsafe { crate::object::lean_ptr_other(o) }
}
#[inline(always)]
pub unsafe fn lean_ctor_obj_cptr(o: *mut lean_object) -> *mut *mut lean_object {
unsafe { (&raw mut (*o.cast::<LeanCtorObjectRepr>()).objs).cast::<*mut lean_object>() }
}
#[inline(always)]
pub unsafe fn lean_ctor_scalar_cptr(o: *mut lean_object) -> *mut u8 {
unsafe {
let num_objs = lean_ctor_num_objs(o) as usize;
lean_ctor_obj_cptr(o).add(num_objs).cast::<u8>()
}
}
#[inline(always)]
pub unsafe fn lean_alloc_ctor(tag: u8, num_objs: u8, scalar_sz: usize) -> lean_obj_res {
let sz = size_of::<LeanObjectRepr>()
.strict_add(size_of::<*mut lean_object>().strict_mul(num_objs as usize))
.strict_add(scalar_sz);
unsafe {
let o = lean_alloc_object(sz);
set_st_header(o, tag, num_objs);
o
}
}
#[inline(always)]
pub unsafe fn lean_box_uint32(v: u32) -> lean_obj_res {
unsafe {
let o = lean_alloc_ctor(0, 0, size_of::<u32>());
lean_ctor_set_uint32(o, 0, v);
o
}
}
#[inline(always)]
pub unsafe fn lean_unbox_uint32(o: b_lean_obj_arg) -> u32 {
unsafe { lean_ctor_get_uint32(o, 0) }
}
#[inline(always)]
pub unsafe fn lean_box_uint64(v: u64) -> lean_obj_res {
unsafe {
let o = lean_alloc_ctor(0, 0, size_of::<u64>());
lean_ctor_set_uint64(o, 0, v);
o
}
}
#[inline(always)]
pub unsafe fn lean_unbox_uint64(o: b_lean_obj_arg) -> u64 {
unsafe { lean_ctor_get_uint64(o, 0) }
}
#[inline(always)]
pub unsafe fn lean_box_usize(v: usize) -> lean_obj_res {
unsafe {
let o = lean_alloc_ctor(0, 0, size_of::<usize>());
lean_ctor_set_usize(o, 0, v);
o
}
}
#[inline(always)]
pub unsafe fn lean_unbox_usize(o: b_lean_obj_arg) -> usize {
unsafe { lean_ctor_get_usize(o, 0) }
}
#[inline(always)]
pub unsafe fn lean_box_float(v: f64) -> lean_obj_res {
unsafe {
let o = lean_alloc_ctor(0, 0, size_of::<f64>());
lean_ctor_set_float(o, 0, v);
o
}
}
#[inline(always)]
pub unsafe fn lean_unbox_float(o: b_lean_obj_arg) -> f64 {
unsafe { lean_ctor_get_float(o, 0) }
}
#[inline(always)]
pub unsafe fn lean_ctor_get_usize(o: b_lean_obj_arg, i: u8) -> usize {
unsafe { lean_ctor_obj_cptr(o).add(i as usize).cast::<usize>().read_unaligned() }
}
#[inline(always)]
pub unsafe fn lean_ctor_get_uint8(o: b_lean_obj_arg, offset: u32) -> u8 {
unsafe { *lean_ctor_scalar_cptr(o).add(offset as usize) }
}
#[inline(always)]
pub unsafe fn lean_ctor_get_uint16(o: b_lean_obj_arg, offset: u32) -> u16 {
unsafe {
lean_ctor_scalar_cptr(o)
.add(offset as usize)
.cast::<u16>()
.read_unaligned()
}
}
#[inline(always)]
pub unsafe fn lean_ctor_get_uint32(o: b_lean_obj_arg, offset: u32) -> u32 {
unsafe {
lean_ctor_scalar_cptr(o)
.add(offset as usize)
.cast::<u32>()
.read_unaligned()
}
}
#[inline(always)]
pub unsafe fn lean_ctor_get_uint64(o: b_lean_obj_arg, offset: u32) -> u64 {
unsafe {
lean_ctor_scalar_cptr(o)
.add(offset as usize)
.cast::<u64>()
.read_unaligned()
}
}
#[inline(always)]
pub unsafe fn lean_ctor_get_float(o: b_lean_obj_arg, offset: u32) -> f64 {
unsafe {
lean_ctor_scalar_cptr(o)
.add(offset as usize)
.cast::<f64>()
.read_unaligned()
}
}
#[inline(always)]
pub unsafe fn lean_ctor_set_usize(o: b_lean_obj_arg, i: u8, v: usize) {
unsafe { lean_ctor_obj_cptr(o).add(i as usize).cast::<usize>().write_unaligned(v) }
}
#[inline(always)]
pub unsafe fn lean_ctor_set_uint8(o: b_lean_obj_arg, offset: u32, v: u8) {
unsafe { *lean_ctor_scalar_cptr(o).add(offset as usize) = v }
}
#[inline(always)]
pub unsafe fn lean_ctor_set_uint16(o: b_lean_obj_arg, offset: u32, v: u16) {
unsafe {
lean_ctor_scalar_cptr(o)
.add(offset as usize)
.cast::<u16>()
.write_unaligned(v);
}
}
#[inline(always)]
pub unsafe fn lean_ctor_set_uint32(o: b_lean_obj_arg, offset: u32, v: u32) {
unsafe {
lean_ctor_scalar_cptr(o)
.add(offset as usize)
.cast::<u32>()
.write_unaligned(v);
}
}
#[inline(always)]
pub unsafe fn lean_ctor_set_uint64(o: b_lean_obj_arg, offset: u32, v: u64) {
unsafe {
lean_ctor_scalar_cptr(o)
.add(offset as usize)
.cast::<u64>()
.write_unaligned(v);
}
}
#[inline(always)]
pub unsafe fn lean_ctor_set_float(o: b_lean_obj_arg, offset: u32, v: f64) {
unsafe {
lean_ctor_scalar_cptr(o)
.add(offset as usize)
.cast::<f64>()
.write_unaligned(v);
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used, clippy::float_cmp)]
use super::{lean_box_float, lean_box_uint32, lean_box_uint64, lean_box_usize};
use super::{lean_unbox_float, lean_unbox_uint32, lean_unbox_uint64, lean_unbox_usize};
use crate::init::{lean_initialize, lean_initialize_runtime_module};
use crate::io::lean_io_mark_end_initialization;
use crate::object::lean_box;
use crate::refcount::lean_dec;
fn ensure_runtime() {
use std::sync::OnceLock;
static INIT: OnceLock<()> = OnceLock::new();
INIT.get_or_init(|| {
unsafe {
lean_initialize_runtime_module();
lean_initialize();
lean_io_mark_end_initialization();
}
});
}
#[test]
fn box_unbox_uint64_round_trips() {
ensure_runtime();
for v in [0_u64, 1, u64::from(u32::MAX), u64::MAX] {
unsafe {
let o = lean_box_uint64(v);
assert_eq!(lean_unbox_uint64(o), v);
lean_dec(o);
}
}
}
#[test]
fn box_unbox_usize_round_trips() {
ensure_runtime();
for v in [0_usize, 1, usize::MAX] {
unsafe {
let o = lean_box_usize(v);
assert_eq!(lean_unbox_usize(o), v);
lean_dec(o);
}
}
}
#[test]
fn box_unbox_uint32_round_trips() {
ensure_runtime();
for v in [0_u32, 1, u32::MAX] {
unsafe {
let o = lean_box_uint32(v);
assert_eq!(lean_unbox_uint32(o), v);
lean_dec(o);
}
}
}
#[test]
fn box_unbox_float_round_trips() {
ensure_runtime();
for v in [0.0_f64, -1.5, core::f64::consts::PI, f64::INFINITY] {
unsafe {
let o = lean_box_float(v);
assert_eq!(lean_unbox_float(o), v);
lean_dec(o);
}
}
unsafe {
let o = lean_box_float(f64::NAN);
assert!(lean_unbox_float(o).is_nan());
lean_dec(o);
}
}
#[test]
fn alloc_sarray_round_trips_payload_bytes() {
ensure_runtime();
use crate::array::{
lean_alloc_sarray, lean_sarray_capacity, lean_sarray_cptr, lean_sarray_elem_size, lean_sarray_size,
};
let bytes: &[u8] = b"hello\0world";
unsafe {
let o = lean_alloc_sarray(1, bytes.len(), bytes.len());
core::ptr::copy_nonoverlapping(bytes.as_ptr(), lean_sarray_cptr(o), bytes.len());
assert_eq!(lean_sarray_elem_size(o), 1);
assert_eq!(lean_sarray_size(o), bytes.len());
assert_eq!(lean_sarray_capacity(o), bytes.len());
let view = core::slice::from_raw_parts(lean_sarray_cptr(o), lean_sarray_size(o));
assert_eq!(view, bytes);
lean_dec(o);
}
}
#[test]
fn alloc_sarray_empty_is_valid() {
ensure_runtime();
use crate::array::{lean_alloc_sarray, lean_sarray_size};
unsafe {
let o = lean_alloc_sarray(1, 0, 0);
assert_eq!(lean_sarray_size(o), 0);
lean_dec(o);
}
}
#[test]
fn alloc_array_round_trips_object_slots() {
ensure_runtime();
use crate::array::{
lean_alloc_array, lean_array_capacity, lean_array_get_core, lean_array_set_core, lean_array_size,
};
use crate::object::{lean_box, lean_is_array, lean_unbox};
unsafe {
let o = lean_alloc_array(3, 3);
assert!(lean_is_array(o));
assert_eq!(lean_array_size(o), 3);
assert_eq!(lean_array_capacity(o), 3);
lean_array_set_core(o, 0, lean_box(10));
lean_array_set_core(o, 1, lean_box(20));
lean_array_set_core(o, 2, lean_box(30));
assert_eq!(lean_unbox(lean_array_get_core(o, 0)), 10);
assert_eq!(lean_unbox(lean_array_get_core(o, 1)), 20);
assert_eq!(lean_unbox(lean_array_get_core(o, 2)), 30);
lean_dec(o);
}
}
#[test]
fn alloc_array_empty_is_valid() {
ensure_runtime();
use crate::array::{lean_alloc_array, lean_array_capacity, lean_array_size};
use crate::object::lean_is_array;
unsafe {
let o = lean_alloc_array(0, 0);
assert!(lean_is_array(o));
assert_eq!(lean_array_size(o), 0);
assert_eq!(lean_array_capacity(o), 0);
lean_dec(o);
}
}
#[test]
fn scalar_box_unbox_remains_inline_for_small_nat() {
unsafe {
let o = lean_box(42);
assert_eq!(crate::object::lean_unbox(o), 42);
lean_dec(o);
}
}
}