#![allow(clippy::inline_always)]
use core::sync::atomic::{AtomicI32, Ordering};
use crate::consts::{
LEAN_ARRAY, LEAN_CLOSURE, LEAN_EXTERNAL, LEAN_MAX_CTOR_TAG, LEAN_MPZ, LEAN_PROMISE, LEAN_REF, LEAN_SCALAR_ARRAY,
LEAN_STRING, LEAN_TASK, LEAN_THUNK,
};
use crate::repr::LeanObjectRepr;
use crate::types::lean_object;
unsafe extern "C" {
pub fn lean_alloc_object(sz: usize) -> *mut lean_object;
pub fn lean_free_object(o: *mut lean_object);
pub fn lean_object_byte_size(o: *mut lean_object) -> usize;
pub fn lean_object_data_byte_size(o: *mut lean_object) -> usize;
}
#[inline(always)]
pub unsafe fn lean_is_scalar(o: *mut lean_object) -> bool {
(o as usize) & 1 == 1
}
#[inline(always)]
pub unsafe fn lean_box(n: usize) -> *mut lean_object {
((n << 1) | 1) as *mut lean_object
}
#[inline(always)]
pub unsafe fn lean_unbox(o: *mut lean_object) -> usize {
(o as usize) >> 1
}
#[inline(always)]
unsafe fn header<'a>(o: *mut lean_object) -> &'a LeanObjectRepr {
unsafe { &*o.cast::<LeanObjectRepr>() }
}
#[inline(always)]
unsafe fn load_rc(o: *mut lean_object) -> i32 {
unsafe {
let repr = o.cast::<LeanObjectRepr>();
AtomicI32::from_ptr(&raw mut (*repr).m_rc).load(Ordering::Relaxed)
}
}
#[inline(always)]
pub unsafe fn lean_ptr_tag(o: *mut lean_object) -> u8 {
unsafe { header(o).m_tag }
}
#[inline(always)]
pub unsafe fn lean_ptr_other(o: *mut lean_object) -> u8 {
unsafe { header(o).m_other }
}
macro_rules! is_tag {
($name:ident, $tag:expr, $doc:expr) => {
#[doc = $doc]
#[inline(always)]
pub unsafe fn $name(o: *mut lean_object) -> bool {
unsafe { lean_ptr_tag(o) == $tag }
}
};
}
#[inline(always)]
pub unsafe fn lean_is_ctor(o: *mut lean_object) -> bool {
unsafe { lean_ptr_tag(o) <= LEAN_MAX_CTOR_TAG }
}
is_tag!(
lean_is_closure,
LEAN_CLOSURE,
"True if `o` is a closure object (`lean.h:566`)."
);
is_tag!(
lean_is_array,
LEAN_ARRAY,
"True if `o` is an object array (`lean.h:567`)."
);
is_tag!(
lean_is_sarray,
LEAN_SCALAR_ARRAY,
"True if `o` is a scalar array (`lean.h:568`)."
);
is_tag!(lean_is_string, LEAN_STRING, "True if `o` is a string (`lean.h:569`).");
is_tag!(
lean_is_mpz,
LEAN_MPZ,
"True if `o` is an MPZ (big integer) object (`lean.h:570`)."
);
is_tag!(
lean_is_thunk,
LEAN_THUNK,
"True if `o` is a thunk object (`lean.h:571`)."
);
is_tag!(lean_is_task, LEAN_TASK, "True if `o` is a task object (`lean.h:572`).");
is_tag!(
lean_is_promise,
LEAN_PROMISE,
"True if `o` is a promise object (`lean.h:573`)."
);
is_tag!(
lean_is_external,
LEAN_EXTERNAL,
"True if `o` is an external object (`lean.h:574`)."
);
is_tag!(
lean_is_ref,
LEAN_REF,
"True if `o` is a Lean `Ref` object (`lean.h:575`)."
);
#[inline(always)]
pub unsafe fn lean_obj_tag(o: *mut lean_object) -> u32 {
unsafe {
if lean_is_scalar(o) {
lean_unbox(o) as u32
} else {
u32::from(lean_ptr_tag(o))
}
}
}
#[inline(always)]
pub unsafe fn lean_is_st(o: *mut lean_object) -> bool {
unsafe { load_rc(o) > 0 }
}
#[inline(always)]
pub unsafe fn lean_is_mt(o: *mut lean_object) -> bool {
unsafe { load_rc(o) < 0 }
}
#[inline(always)]
pub unsafe fn lean_is_persistent(o: *mut lean_object) -> bool {
unsafe { load_rc(o) == 0 }
}
#[inline(always)]
pub unsafe fn lean_is_exclusive(o: *mut lean_object) -> bool {
unsafe { load_rc(o) == 1 }
}
#[inline(always)]
pub unsafe fn lean_is_shared(o: *mut lean_object) -> bool {
unsafe { load_rc(o) > 1 }
}