#![allow(unsafe_code)]
use core::ptr;
use core::slice;
use lean_rs_sys::array::{lean_alloc_sarray, lean_sarray_cptr, lean_sarray_elem_size, lean_sarray_size};
use lean_rs_sys::object::{lean_is_sarray, lean_is_scalar, lean_obj_tag};
use crate::abi::traits::conversion_error;
use crate::error::{LeanError, LeanResult};
use crate::runtime::LeanRuntime;
use crate::runtime::obj::{Obj, ObjRef};
#[must_use]
pub(crate) fn from_bytes<'lean>(runtime: &'lean LeanRuntime, bytes: &[u8]) -> Obj<'lean> {
unsafe {
let raw = lean_alloc_sarray(1, bytes.len(), bytes.len());
if !bytes.is_empty() {
ptr::copy_nonoverlapping(bytes.as_ptr(), lean_sarray_cptr(raw), bytes.len());
}
Obj::from_owned_raw(runtime, raw)
}
}
#[allow(
clippy::needless_pass_by_value,
reason = "Obj is consumed by Drop on return; that releases the refcount"
)]
pub(crate) fn to_vec(obj: Obj<'_>) -> LeanResult<Vec<u8>> {
require_byte_array(&obj)?;
let owned = unsafe {
let ptr = obj.as_raw_borrowed();
let len = lean_sarray_size(ptr);
let data = lean_sarray_cptr(ptr);
let slice = slice::from_raw_parts(data, len);
slice.to_vec()
};
tracing::trace!(
target: "lean_rs",
shape = "bytes",
len = owned.len(),
"lean_rs.abi.decode",
);
Ok(owned)
}
pub(crate) fn borrow_bytes<'a>(obj: &'a ObjRef<'_, '_>) -> LeanResult<&'a [u8]> {
let ptr = obj.as_raw_borrowed();
if unsafe { lean_is_scalar(ptr) } {
return Err(wrong_kind_scalar());
}
if !unsafe { lean_is_sarray(ptr) } || unsafe { lean_sarray_elem_size(ptr) } != 1 {
let found_tag = unsafe { lean_obj_tag(ptr) };
return Err(wrong_kind_heap(found_tag));
}
let view = unsafe {
let len = lean_sarray_size(ptr);
let data = lean_sarray_cptr(ptr);
slice::from_raw_parts(data, len)
};
Ok(view)
}
fn require_byte_array(obj: &Obj<'_>) -> LeanResult<()> {
let ptr = obj.as_raw_borrowed();
if unsafe { lean_is_scalar(ptr) } {
return Err(wrong_kind_scalar());
}
if unsafe { lean_is_sarray(ptr) } && unsafe { lean_sarray_elem_size(ptr) } == 1 {
Ok(())
} else {
let found_tag = unsafe { lean_obj_tag(ptr) };
Err(wrong_kind_heap(found_tag))
}
}
fn wrong_kind_scalar() -> LeanError {
conversion_error("expected Lean ByteArray, found scalar-tagged object")
}
fn wrong_kind_heap(found_tag: u32) -> LeanError {
conversion_error(format!("expected Lean ByteArray, found object with tag {found_tag}"))
}