use core::{
ffi::{
CStr, c_int, c_void,
},
ops::{
Deref, DerefMut,
},
};
use crate::{
cdef::*,
Thread,
};
#[cfg(feature = "auxlib")]
use crate::cdef::auxlib::*;
pub unsafe extern "C-unwind" fn lua_panic_handler(l: *mut State) -> c_int {
let msg_ptr = unsafe { lua_tostring(l, -1) };
let msg = if !msg_ptr.is_null() {
let msg = unsafe { CStr::from_ptr(msg_ptr) };
msg.to_str().unwrap_or("error object does not contain valid UTF-8")
} else {
"error object is not a string"
};
panic!("unprotected error in call to Lua API ({msg})")
}
#[derive(Debug)]
#[repr(transparent)]
pub struct Lua {
thread: &'static mut Thread,
}
impl Drop for Lua {
fn drop(&mut self) {
unsafe { self.thread.close_as_main() }
}
}
impl AsRef<Thread> for Lua {
fn as_ref(&self) -> &Thread {
self.thread
}
}
impl AsMut<Thread> for Lua {
fn as_mut(&mut self) -> &mut Thread {
self.thread
}
}
impl Deref for Lua {
type Target = Thread;
fn deref(&self) -> &Self::Target {
self.thread
}
}
impl DerefMut for Lua {
fn deref_mut(&mut self) -> &mut Self::Target {
self.thread
}
}
impl Lua {
pub unsafe fn from_ptr(l: *mut State) -> Self {
let thread = unsafe { Thread::from_ptr_mut(l) };
Self {
thread
}
}
unsafe fn from_new_ptr(l: *mut State) -> Option<Self> {
if !l.is_null() {
let lua = Self {
thread: unsafe { Thread::from_ptr_mut(l) }
};
Some(lua)
} else {
None
}
}
#[cfg(feature = "auxlib")]
pub fn new_auxlib() -> Self {
match unsafe { Self::from_new_ptr(luaL_newstate()) } {
Some(lua) => lua,
_ => panic!("not enough memory to create Lua state using the `lauxlib.h` allocator"),
}
}
#[cfg(feature = "auxlib")]
pub fn try_new_auxlib() -> Option<Self> {
unsafe { Self::from_new_ptr(luaL_newstate()) }
}
pub unsafe fn new_with_alloc_fn(alloc_fn: Alloc, alloc_fn_data: *mut c_void) -> Self {
match unsafe { Self::from_new_ptr(lua_newstate(alloc_fn, alloc_fn_data)) } {
Some(lua) => lua,
_ => panic!("not enough memory to create Lua state using a custom allocator function"),
}
}
pub unsafe fn try_new_with_alloc_fn(alloc_fn: Alloc, alloc_fn_data: *mut c_void) -> Option<Self> {
unsafe { Self::from_new_ptr(lua_newstate(alloc_fn, alloc_fn_data)) }
}
pub fn new() -> Self {
match Self::try_new() {
Some(lua) => lua,
_ => panic!("not enough memory to create Lua state using the global Rust allocator"),
}
}
#[cfg(feature = "alloc")]
pub fn try_new() -> Option<Self> {
use alloc::alloc::{
Layout, alloc, realloc, dealloc,
};
use core::ptr::null_mut;
fn guess_layout(size: usize) -> Option<Layout> {
if let Ok(layout) = Layout::from_size_align(size, align_of::<MaxAlign>()) {
Some(layout)
} else {
None
}
}
unsafe extern "C-unwind" fn l_alloc(
_ud: *mut c_void,
ptr: *mut c_void, osize: usize,
nsize: usize
) -> *mut c_void {
let ptr = ptr as *mut u8;
if !ptr.is_null() {
if nsize == 0 {
let Some(layout) = guess_layout(osize) else {
return null_mut()
};
unsafe { dealloc(ptr, layout) };
null_mut()
} else {
let Some(old_layout) = guess_layout(osize) else {
return null_mut()
};
unsafe { realloc(ptr, old_layout, nsize) as *mut c_void }
}
} else if let Some(layout) = guess_layout(nsize) {
unsafe { alloc(layout) as *mut c_void }
} else {
null_mut()
}
}
unsafe { Self::from_new_ptr(lua_newstate(l_alloc, null_mut())) }
}
pub fn as_ptr(&self) -> *mut State {
self.thread.as_ptr()
}
}