use core::ptr::NonNull;
use crate::function::RawProto;
use crate::function::{Closure, Proto};
use crate::handle::RawHandle;
use crate::handle::sealed::Sealed;
use crate::value::{RawTValue, TValueCursor};
#[repr(C)]
pub struct RawCallInfo {
pub base: *mut RawTValue,
pub function: *mut RawTValue,
pub top: *mut RawTValue,
pub proto: *mut RawProto,
pub saved: RawCallInfoSaved,
pub n_results: i32,
pub flags: u32,
}
#[repr(C)]
pub union RawCallInfoSaved {
pub saved_pc: *const u32,
pub errfunc: i32,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct CallInfo {
raw: NonNull<RawCallInfo>,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct CallInfoCursor(*mut RawCallInfo);
#[allow(
clippy::missing_safety_doc,
reason = "CallInfo's shared raw-view contract is documented on CallInfo"
)]
impl CallInfo {
pub const unsafe fn from_raw(raw: NonNull<RawCallInfo>) -> Self {
Self { raw }
}
pub fn base(&self) -> TValueCursor {
unsafe { TValueCursor::from_ptr(self.as_ptr().as_ref().unwrap_unchecked().base) }
}
pub fn function(&self) -> TValueCursor {
unsafe { TValueCursor::from_ptr(self.as_ptr().as_ref().unwrap_unchecked().function) }
}
pub fn top(&self) -> TValueCursor {
unsafe { TValueCursor::from_ptr(self.as_ptr().as_ref().unwrap_unchecked().top) }
}
pub fn set_base(&self, base: TValueCursor) {
unsafe {
self.as_ptr().as_mut().unwrap_unchecked().base = base.as_ptr();
}
}
pub fn set_function(&self, function: TValueCursor) {
unsafe {
self.as_ptr().as_mut().unwrap_unchecked().function = function.as_ptr();
}
}
pub fn set_top(&self, top: TValueCursor) {
unsafe {
self.as_ptr().as_mut().unwrap_unchecked().top = top.as_ptr();
}
}
pub fn proto(&self) -> Option<Proto> {
let proto = unsafe { self.as_ptr().as_ref().unwrap_unchecked().proto };
NonNull::new(proto).map(|raw| unsafe { Proto::from_raw(raw) })
}
pub fn set_proto(&self, proto: Option<Proto>) {
unsafe {
self.as_ptr().as_mut().unwrap_unchecked().proto =
proto.map_or(core::ptr::null_mut(), |proto| proto.as_ptr());
}
}
pub unsafe fn saved_pc(&self) -> *const u32 {
unsafe { self.as_ptr().as_ref().unwrap_unchecked().saved.saved_pc }
}
pub unsafe fn set_saved_pc(&self, saved_pc: *const u32) {
unsafe {
self.as_ptr().as_mut().unwrap_unchecked().saved.saved_pc = saved_pc;
}
}
pub unsafe fn errfunc(&self) -> i32 {
unsafe { self.as_ptr().as_ref().unwrap_unchecked().saved.errfunc }
}
pub unsafe fn set_errfunc(&self, errfunc: i32) {
unsafe {
self.as_ptr().as_mut().unwrap_unchecked().saved.errfunc = errfunc;
}
}
pub unsafe fn init_call(
&self,
function: TValueCursor,
top: TValueCursor,
n_results: i32,
proto: Option<Proto>,
) {
unsafe {
self.set_function(function);
self.set_base(function.add(1));
self.set_top(top);
self.set_proto(proto);
self.set_saved_pc(core::ptr::null());
self.as_ptr().as_mut().unwrap_unchecked().flags = 0;
self.as_ptr().as_mut().unwrap_unchecked().n_results = n_results;
}
}
pub unsafe fn rebase_stack(&self, old_stack: TValueCursor, new_stack: TValueCursor) {
unsafe {
self.set_top(new_stack.add(self.top().addr_offset_from(old_stack) as usize));
self.set_base(new_stack.add(self.base().addr_offset_from(old_stack) as usize));
self.set_function(new_stack.add(self.function().addr_offset_from(old_stack) as usize));
}
}
pub unsafe fn function_closure(&self) -> Closure {
unsafe { self.function().value_unchecked().closure_value() }
}
pub unsafe fn is_lua_function(&self) -> bool {
unsafe { self.function_closure().is_lua() }
}
pub unsafe fn is_lua(&self) -> bool {
unsafe { self.function().value_unchecked().is_function() && self.is_lua_function() }
}
}
#[allow(
clippy::missing_safety_doc,
reason = "CallInfoCursor's navigation contract is documented on CallInfoCursor"
)]
impl CallInfoCursor {
pub const fn as_ptr(&self) -> *mut RawCallInfo {
self.0
}
pub const fn from_ptr(raw: *mut RawCallInfo) -> Self {
Self(raw)
}
pub const fn is_null(&self) -> bool {
self.0.is_null()
}
pub unsafe fn call_info_unchecked(&self) -> CallInfo {
debug_assert!(!self.is_null());
unsafe { CallInfo::from_raw(NonNull::new_unchecked(self.0)) }
}
pub fn call_info(&self) -> Option<CallInfo> {
NonNull::new(self.0).map(|raw| unsafe { CallInfo::from_raw(raw) })
}
pub unsafe fn add(self, count: usize) -> Self {
unsafe { Self::from_ptr(self.0.add(count)) }
}
pub unsafe fn sub(self, count: usize) -> Self {
unsafe { Self::from_ptr(self.0.sub(count)) }
}
pub unsafe fn offset(self, count: isize) -> Self {
unsafe { Self::from_ptr(self.0.offset(count)) }
}
pub unsafe fn offset_from(self, other: Self) -> isize {
unsafe { self.0.offset_from(other.0) }
}
}
impl Sealed for CallInfo {}
impl RawHandle for CallInfo {
type Raw = RawCallInfo;
fn as_ptr(&self) -> *mut Self::Raw {
self.raw.as_ptr()
}
}
impl AsRef<CallInfo> for CallInfo {
fn as_ref(&self) -> &CallInfo {
self
}
}
impl AsRef<CallInfoCursor> for CallInfoCursor {
fn as_ref(&self) -> &CallInfoCursor {
self
}
}