use crate::{
convert::{Index, ToLua},
error::Error,
ffi::*,
state::State,
str::*,
};
use alloc::borrow::Cow;
use alloc::string::String;
use alloc::vec::Vec;
use core::ffi::{c_char, c_int, c_void};
use core::{mem, ptr, slice, str};
#[allow(non_camel_case_types)]
type size_t = usize;
#[extend::ext(pub, name = UnsafeLuaApi)]
impl State {
fn new() -> *mut lua_State {
unsafe { luaL_newstate() }
}
#[inline(always)]
fn as_ptr(&self) -> *mut lua_State {
self.state
}
fn open_libs(&self) {
unsafe {
luaL_openlibs(self.state);
}
}
#[inline(always)]
fn open_base(&self) -> c_int {
unsafe { luaopen_base(self.state) }
}
#[inline(always)]
fn open_coroutine(&self) -> c_int {
unsafe { luaopen_coroutine(self.state) }
}
#[inline(always)]
fn open_table(&self) -> c_int {
unsafe { luaopen_table(self.state) }
}
#[inline(always)]
fn open_io(&self) -> c_int {
unsafe { luaopen_io(self.state) }
}
#[inline(always)]
fn open_os(&self) -> c_int {
unsafe { luaopen_os(self.state) }
}
#[inline(always)]
fn open_string(&self) -> c_int {
unsafe { luaopen_string(self.state) }
}
#[inline(always)]
fn open_utf8(&self) -> c_int {
unsafe { luaopen_utf8(self.state) }
}
#[inline(always)]
fn open_math(&self) -> c_int {
unsafe { luaopen_math(self.state) }
}
#[inline(always)]
fn open_debug(&self) -> c_int {
unsafe { luaopen_debug(self.state) }
}
#[inline(always)]
fn open_package(&self) -> c_int {
unsafe { luaopen_package(self.state) }
}
fn do_file(&self, filename: &str) -> i32 {
let c_str = CString::new(filename).unwrap();
unsafe { luaL_dofile(self.state, c_str.as_ptr()) }
}
fn do_string(&self, s: &str) -> i32 {
let c_str = CString::new(s).unwrap();
unsafe { luaL_dostring(self.state, c_str.as_ptr()) }
}
#[inline(always)]
fn close(&self) {
unsafe {
lua_close(self.state);
}
}
#[inline(always)]
fn new_thread(&self) -> *mut lua_State {
unsafe { lua_newthread(self.state) }
}
#[inline(always)]
fn at_panic(&self, panicf: lua_CFunction) -> lua_CFunction {
unsafe { lua_atpanic(self.state, panicf) }
}
fn version(state: *mut lua_State) -> lua_Number {
unsafe { lua_version(state) }
}
#[inline(always)]
fn abs_index(&self, idx: Index) -> Index {
unsafe { lua_absindex(self.state, idx) }
}
#[inline(always)]
fn get_top(&self) -> Index {
unsafe { lua_gettop(self.state) }
}
#[inline(always)]
fn set_top(&self, index: Index) {
unsafe { lua_settop(self.state, index) }
}
#[inline(always)]
fn rotate(&self, idx: Index, n: c_int) {
unsafe { lua_rotate(self.state, idx, n) }
}
#[inline(always)]
fn copy(&self, from_idx: Index, to_idx: Index) {
unsafe { lua_copy(self.state, from_idx, to_idx) }
}
#[inline(always)]
fn check_stack(&self, extra: c_int) -> bool {
let result = unsafe { lua_checkstack(self.state, extra) };
result != 0
}
#[inline(always)]
fn xmove(&self, to: *mut lua_State, n: c_int) {
unsafe { lua_xmove(self.state, to, n) }
}
#[inline(always)]
fn is_number(&self, index: Index) -> bool {
unsafe { lua_isnumber(self.state, index) == 1 }
}
#[inline(always)]
fn is_string(&self, index: Index) -> bool {
unsafe { lua_isstring(self.state, index) == 1 }
}
#[inline(always)]
fn is_native_fn(&self, index: Index) -> bool {
unsafe { lua_iscfunction(self.state, index) == 1 }
}
#[inline(always)]
fn is_integer(&self, index: Index) -> bool {
unsafe { lua_isinteger(self.state, index) == 1 }
}
#[inline(always)]
fn is_userdata(&self, index: Index) -> bool {
unsafe { lua_isuserdata(self.state, index) == 1 }
}
#[inline(always)]
fn type_of(&self, index: Index) -> Type {
let result = unsafe { lua_type(self.state, index) };
Type::from_c_int(result)
}
#[inline(always)]
fn typename_of(&self, tp: Type) -> Cow<str> {
unsafe {
let ptr = lua_typename(self.state, tp as c_int);
let slice = CStr::from_ptr(ptr).to_bytes();
String::from_utf8_lossy(slice)
}
}
#[inline(always)]
fn to_bool(&self, index: Index) -> bool {
let result = unsafe { lua_toboolean(self.state, index) };
result != 0
}
#[inline(always)]
fn raw_len(&self, index: Index) -> size_t {
unsafe { lua_rawlen(self.state, index) as _ }
}
#[inline(always)]
fn to_native_fn(&self, index: Index) -> lua_CFunction {
let result = unsafe { lua_tocfunction(self.state, index) };
result
}
#[inline(always)]
fn to_userdata(&self, index: Index) -> *mut c_void {
unsafe { lua_touserdata(self.state, index) }
}
#[inline]
fn to_thread(&self, index: Index) -> Option<&mut lua_State> {
unsafe { lua_tothread(self.state, index).as_mut() }
}
#[inline(always)]
fn to_pointer(&self, index: Index) -> *const c_void {
unsafe { lua_topointer(self.state, index) }
}
#[inline(always)]
fn arith(&self, op: Arithmetic) {
unsafe { lua_arith(self.state, op as c_int) }
}
#[inline(always)]
fn raw_equal(&self, idx1: Index, idx2: Index) -> bool {
let result = unsafe { lua_rawequal(self.state, idx1, idx2) };
result != 0
}
#[inline(always)]
fn compare(&self, idx1: Index, idx2: Index, op: Comparison) -> bool {
let result = unsafe { lua_compare(self.state, idx1, idx2, op as c_int) };
result != 0
}
#[inline(always)]
fn push_nil(&self) {
unsafe { lua_pushnil(self.state) }
}
#[inline(always)]
fn push_number(&self, n: lua_Number) {
unsafe { lua_pushnumber(self.state, n) }
}
#[inline(always)]
fn push_integer(&self, i: lua_Integer) {
unsafe { lua_pushinteger(self.state, i) }
}
#[inline(always)]
fn push_string(&self, s: &str) {
unsafe { lua_pushlstring(self.state, s.as_ptr() as *const _, s.len() as size_t) };
}
#[inline(always)]
fn push_bytes(&self, s: &[u8]) {
unsafe { lua_pushlstring(self.state, s.as_ptr() as *const _, s.len() as size_t) };
}
#[inline(always)]
fn push_cclosure(&self, f: lua_CFunction, n: c_int) {
unsafe { lua_pushcclosure(self.state, f, n) }
}
#[inline(always)]
fn push_bool(&self, b: bool) {
unsafe { lua_pushboolean(self.state, b as c_int) }
}
#[inline(always)]
fn push_light_userdata<T>(&self, ud: *mut T) {
unsafe { lua_pushlightuserdata(self.state, mem::transmute(ud)) }
}
#[inline(always)]
fn push_thread(&self) -> bool {
let result = unsafe { lua_pushthread(self.state) };
result != 1
}
#[inline(always)]
fn push_value(&self, index: Index) {
unsafe { lua_pushvalue(self.state, index) }
}
#[inline(always)]
fn get_global(&self, name: &CStr) -> Type {
Type::from_c_int(unsafe { lua_getglobal(self.state, name.as_ptr()) })
}
#[inline(always)]
fn get_table(&self, index: Index) -> Type {
let ty = unsafe { lua_gettable(self.state, index) };
Type::from_c_int(ty)
}
#[inline(always)]
fn get_field(&self, index: Index, k: &CStr) -> Type {
Type::from_c_int(unsafe { lua_getfield(self.state, index, k.as_ptr()) })
}
#[inline(always)]
fn geti(&self, index: Index, i: lua_Integer) -> Type {
let ty = unsafe { lua_geti(self.state, index, i) };
Type::from_c_int(ty)
}
#[inline(always)]
fn raw_get(&self, index: Index) -> Type {
let ty = unsafe { lua_rawget(self.state, index) };
Type::from_c_int(ty)
}
#[inline(always)]
fn raw_geti(&self, index: Index, n: lua_Integer) -> Type {
let ty = unsafe { lua_rawgeti(self.state, index, n) };
Type::from_c_int(ty)
}
#[inline(always)]
fn raw_getp<T>(&self, index: Index, p: *const T) -> Type {
let ty = unsafe { lua_rawgetp(self.state, index, mem::transmute(p)) };
Type::from_c_int(ty)
}
#[inline(always)]
fn create_table(&self, narr: c_int, nrec: c_int) {
unsafe { lua_createtable(self.state, narr, nrec) }
}
#[inline(always)]
fn new_userdata(&self, sz: size_t) -> *mut c_void {
unsafe { lua_newuserdata(self.state, sz) }
}
#[inline(always)]
fn new_userdatauv(&self, sz: size_t, n: i32) -> *mut c_void {
unsafe { lua_newuserdatauv(self.state, sz, n) }
}
#[inline(always)]
fn get_metatable(&self, objindex: Index) -> bool {
let result = unsafe { lua_getmetatable(self.state, objindex) };
result != 0
}
#[inline(always)]
fn get_uservalue(&self, idx: Index) -> Type {
let result = unsafe { lua_getuservalue(self.state, idx) };
Type::from_c_int(result)
}
#[inline(always)]
fn get_iuservalue(&self, idx: Index, n: i32) -> Type {
let result = unsafe { lua_getiuservalue(self.state, idx, n) };
Type::from_c_int(result)
}
#[inline(always)]
fn set_global(&self, var: &CStr) {
unsafe { lua_setglobal(self.state, var.as_ptr()) }
}
#[inline(always)]
fn set_table(&self, idx: Index) {
unsafe { lua_settable(self.state, idx) }
}
#[inline(always)]
fn set_field(&self, idx: Index, k: &CStr) {
unsafe { lua_setfield(self.state, idx, k.as_ptr()) }
}
#[inline(always)]
fn seti(&self, idx: Index, n: lua_Integer) {
unsafe { lua_seti(self.state, idx, n) }
}
#[inline(always)]
fn raw_set(&self, idx: Index) {
unsafe { lua_rawset(self.state, idx) }
}
#[inline(always)]
fn raw_seti(&self, idx: Index, n: lua_Integer) {
unsafe { lua_rawseti(self.state, idx, n) }
}
#[inline(always)]
fn raw_setp<T>(&self, idx: Index, p: *const T) {
unsafe { lua_rawsetp(self.state, idx, mem::transmute(p)) }
}
#[inline(always)]
fn set_metatable(&self, objindex: Index) {
unsafe { lua_setmetatable(self.state, objindex) };
}
#[inline(always)]
fn set_uservalue(&self, idx: Index) {
unsafe {
lua_setuservalue(self.state, idx);
}
}
#[inline(always)]
fn set_iuservalue(&self, idx: Index, n: i32) {
unsafe {
lua_setiuservalue(self.state, idx, n);
}
}
#[inline(always)]
fn call(&self, n: c_int, r: c_int) {
unsafe { lua_call(self.state, n, r) }
}
fn tailcall(self, n: c_int, r: c_int) {
let state = self.state;
drop(self);
unsafe { lua_call(state, n, r) }
}
fn resume(&self, from: *mut lua_State, nargs: c_int, nresults: &mut c_int) -> ThreadStatus {
let result = unsafe { lua_resume(self.state, from, nargs, nresults) };
ThreadStatus::from_c_int(result)
}
#[inline(always)]
fn status(&self) -> ThreadStatus {
let result = unsafe { lua_status(self.state) };
ThreadStatus::from_c_int(result)
}
#[inline(always)]
fn is_yieldable(&self) -> bool {
let result = unsafe { lua_isyieldable(self.state) };
result != 0
}
#[inline(always)]
fn gc(&self, what: GcOption, data: c_int) -> c_int {
unsafe { lua_gc(self.state, what as c_int, data) }
}
#[inline(always)]
fn error(self) -> ! {
let state = self.state;
drop(self);
unsafe { lua_error(state) };
}
#[inline(always)]
fn next(&self, idx: Index) -> bool {
let result = unsafe { lua_next(self.state, idx) };
result != 0
}
#[inline(always)]
fn concat(&self, n: c_int) {
unsafe { lua_concat(self.state, n) }
}
#[inline(always)]
fn len(&self, idx: Index) {
unsafe { lua_len(self.state, idx) }
}
fn string_to_number(&self, s: &str) -> size_t {
let c_str = CString::new(s).unwrap();
unsafe { lua_stringtonumber(self.state, c_str.as_ptr()) }
}
#[inline(always)]
fn get_alloc_fn(&self) -> (lua_Alloc, *mut c_void) {
let mut slot = ptr::null_mut();
(unsafe { lua_getallocf(self.state, &mut slot) }, slot)
}
#[inline(always)]
fn set_alloc_fn(&self, f: lua_Alloc, ud: *mut c_void) {
unsafe { lua_setallocf(self.state, f, ud) }
}
#[inline(always)]
fn to_number(&self, index: Index) -> lua_Number {
unsafe { lua_tonumber(self.state, index) }
}
#[inline(always)]
fn to_numberx(&self, index: Index) -> Option<lua_Number> {
let mut suc = 0i32;
let r = unsafe { lua_tonumberx(self.state, index, &mut suc) };
if suc > 0 {
Some(r)
} else {
None
}
}
#[inline(always)]
fn to_integer(&self, index: Index) -> lua_Integer {
unsafe { lua_tointeger(self.state, index) }
}
#[inline(always)]
fn to_integerx(&self, index: Index) -> Option<lua_Integer> {
let mut isnum: c_int = 0;
let r = unsafe { lua_tointegerx(self.state, index, &mut isnum) };
if isnum == 0 {
None
} else {
Some(r)
}
}
#[inline(always)]
fn pop(&self, n: c_int) {
unsafe { lua_pop(self.state, n) }
}
#[inline(always)]
fn new_table(&self) {
unsafe { lua_newtable(self.state) }
}
#[inline(always)]
fn register(&self, n: &str, f: CFunction) {
let c_str = CString::new(n).unwrap();
unsafe { lua_register(self.state, c_str.as_ptr(), Some(f)) }
}
#[inline(always)]
fn push_fn(&self, f: lua_CFunction) {
unsafe { lua_pushcfunction(self.state, f) }
}
#[inline(always)]
fn is_function(&self, index: Index) -> bool {
unsafe { lua_isfunction(self.state, index) == 1 }
}
#[inline(always)]
fn is_table(&self, index: Index) -> bool {
unsafe { lua_istable(self.state, index) == 1 }
}
#[inline(always)]
fn is_light_userdata(&self, index: Index) -> bool {
unsafe { lua_islightuserdata(self.state, index) == 1 }
}
#[inline(always)]
fn is_nil(&self, index: Index) -> bool {
unsafe { lua_isnil(self.state, index) == 1 }
}
#[inline(always)]
fn is_bool(&self, index: Index) -> bool {
unsafe { lua_isboolean(self.state, index) == 1 }
}
#[inline(always)]
fn is_thread(&self, index: Index) -> bool {
unsafe { lua_isthread(self.state, index) == 1 }
}
#[inline(always)]
fn is_none(&self, index: Index) -> bool {
unsafe { lua_isnone(self.state, index) == 1 }
}
#[inline(always)]
fn is_none_or_nil(&self, index: Index) -> bool {
unsafe { lua_isnoneornil(self.state, index) == 1 }
}
#[inline(always)]
fn push_global_table(&self) {
unsafe { lua_pushglobaltable(self.state) };
}
#[inline(always)]
fn insert(&self, idx: Index) {
unsafe { lua_insert(self.state, idx) }
}
#[inline(always)]
fn remove(&self, idx: Index) {
unsafe { lua_remove(self.state, idx) }
}
#[inline(always)]
fn replace(&self, idx: Index) {
unsafe { lua_replace(self.state, idx) }
}
fn get_stack(&self, level: c_int) -> Option<lua_Debug> {
let mut ar: lua_Debug = unsafe { core::mem::zeroed() };
let result = unsafe { lua_getstack(self.state, level, &mut ar) };
if result == 1 {
Some(ar)
} else {
None
}
}
fn get_info(&self, what: &CStr, ar: &mut lua_Debug) -> i32 {
unsafe { lua_getinfo(self.state, what.as_ptr(), ar) }
}
fn get_local(&self, ar: &lua_Debug, n: c_int) -> Option<&str> {
let ptr = unsafe { lua_getlocal(self.state, ar, n) };
if ptr.is_null() {
None
} else {
let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
str::from_utf8(slice).ok()
}
}
fn set_local(&self, ar: &lua_Debug, n: c_int) -> Option<&str> {
let ptr = unsafe { lua_setlocal(self.state, ar, n) };
if ptr.is_null() {
None
} else {
let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
str::from_utf8(slice).ok()
}
}
fn get_upvalue(&self, funcindex: Index, n: c_int) -> Option<&str> {
let ptr = unsafe { lua_getupvalue(self.state, funcindex, n) };
if ptr.is_null() {
None
} else {
let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
str::from_utf8(slice).ok()
}
}
fn set_upvalue(&self, funcindex: Index, n: c_int) -> Option<&str> {
let ptr = unsafe { lua_setupvalue(self.state, funcindex, n) };
if ptr.is_null() {
None
} else {
let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
str::from_utf8(slice).ok()
}
}
fn upvalue_id(&self, funcindex: Index, n: c_int) -> *mut c_void {
unsafe { lua_upvalueid(self.state, funcindex, n) }
}
fn upvalue_join(&self, fidx1: Index, n1: c_int, fidx2: Index, n2: c_int) {
unsafe { lua_upvaluejoin(self.state, fidx1, n1, fidx2, n2) }
}
#[cfg(feature = "std")]
fn set_hook(&self, func: Option<lua_Hook>, mask: HookMask, count: c_int) {
unsafe { lua_sethook(self.state, func, mask.bits(), count) }
}
fn get_hook(&self) -> Option<lua_Hook> {
unsafe { lua_gethook(self.state) }
}
#[cfg(feature = "std")]
fn get_hook_mask(&self) -> HookMask {
let result = unsafe { lua_gethookmask(self.state) };
HookMask::from_bits_truncate(result)
}
fn get_hook_count(&self) -> c_int {
unsafe { lua_gethookcount(self.state) }
}
#[inline(always)]
fn get_metafield(&self, obj: Index, e: &CStr) -> bool {
let result = unsafe { luaL_getmetafield(self.state, obj, e.as_ptr()) };
result != 0
}
#[inline(always)]
fn call_meta(&self, obj: Index, e: &CStr) -> bool {
let result = unsafe { luaL_callmeta(self.state, obj, e.as_ptr()) };
result != 0
}
#[inline(always)]
fn to_string(&self, index: Index) -> *const c_char {
unsafe { lua_tolstring(self.state, index, ptr::null_mut()) }
}
#[inline(always)]
fn tolstring(&self, index: Index, size: &mut usize) -> *const c_char {
unsafe { lua_tolstring(self.state, index, size as *mut usize) }
}
#[inline(always)]
fn to_cfunction(&self, index: Index) -> lua_CFunction {
unsafe { lua_tocfunction(self.state, index) }
}
#[inline(always)]
fn cast_string(&self, index: Index) -> Option<&[u8]> {
let mut len = 0;
let ptr = unsafe { luaL_tolstring(self.state, index, &mut len) };
if ptr.is_null() {
None
} else {
Some(unsafe { slice::from_raw_parts(ptr as *const u8, len as usize) })
}
}
#[inline(always)]
fn to_str<'a>(&'a self, index: Index) -> Option<&'a str> {
self.to_bytes(index).and_then(|r| str::from_utf8(r).ok())
}
#[inline(always)]
fn to_string_lossy<'a>(&'a self, index: Index) -> Option<Cow<'a, str>> {
self.to_bytes(index).map(|r| String::from_utf8_lossy(r))
}
fn to_bytes(&self, index: Index) -> Option<&[u8]> {
let mut len = 0;
let ptr = unsafe { lua_tolstring(self.state, index, &mut len) };
if ptr.is_null() {
None
} else {
Some(unsafe { slice::from_raw_parts(ptr as *const u8, len as usize) })
}
}
fn arg_error(&self, arg: Index, extramsg: &CStr) -> ! {
unsafe { luaL_argerror(self.state, arg, extramsg.as_ptr()) };
unreachable!()
}
#[inline(always)]
fn check_number(&self, arg: Index) -> lua_Number {
unsafe { luaL_checknumber(self.state, arg) }
}
#[inline(always)]
fn opt_number(&self, arg: Index, def: lua_Number) -> lua_Number {
unsafe { luaL_optnumber(self.state, arg, def) }
}
#[inline(always)]
fn check_integer(&self, arg: Index) -> lua_Integer {
unsafe { luaL_checkinteger(self.state, arg) }
}
#[inline(always)]
fn opt_integer(&self, arg: Index, def: lua_Integer) -> lua_Integer {
unsafe { luaL_optinteger(self.state, arg, def) }
}
fn check_stack_msg(&self, sz: c_int, msg: &str) {
let c_str = CString::new(msg).unwrap();
unsafe { luaL_checkstack(self.state, sz, c_str.as_ptr()) }
}
#[inline(always)]
fn check_type(&self, arg: Index, t: Type) {
unsafe { luaL_checktype(self.state, arg, t as c_int) }
}
#[inline(always)]
fn check_any(&self, arg: Index) {
unsafe { luaL_checkany(self.state, arg) }
}
#[inline(always)]
fn new_metatable(&self, tname: &CStr) -> bool {
unsafe { luaL_newmetatable(self.state, tname.as_ptr()) != 0 }
}
#[inline(always)]
fn set_metatable_from_registry(&self, tname: &CStr) {
unsafe { luaL_setmetatable(self.state, tname.as_ptr()) }
}
#[inline(always)]
fn test_userdata(&self, arg: Index, tname: &CStr) -> *mut c_void {
unsafe { luaL_testudata(self.state, arg, tname.as_ptr()) }
}
#[inline(always)]
unsafe fn test_userdata_typed<'a, T>(
&'a mut self,
arg: Index,
tname: &CStr,
) -> Option<&'a mut T> {
mem::transmute(self.test_userdata(arg, tname))
}
#[inline(always)]
fn checkudata<'a, T>(&'a self, arg: Index, tname: &CStr) -> &'a mut T {
unsafe { mem::transmute(luaL_checkudata(self.state, arg, tname.as_ptr())) }
}
#[inline(always)]
fn location(&self, lvl: c_int) {
unsafe { luaL_where(self.state, lvl) }
}
fn check_option(&self, arg: Index, def: Option<&str>, lst: &[&str]) -> usize {
let mut vec: Vec<*const c_char> = Vec::with_capacity(lst.len() + 1);
let cstrs: Vec<CString> = lst.iter().map(|ent| CString::new(*ent).unwrap()).collect();
for ent in cstrs.iter() {
vec.push(ent.as_ptr());
}
vec.push(ptr::null());
let result = match def {
Some(def) => unsafe {
let c_str = CString::new(def).unwrap();
luaL_checkoption(self.state, arg, c_str.as_ptr(), vec.as_ptr())
},
None => unsafe { luaL_checkoption(self.state, arg, ptr::null(), vec.as_ptr()) },
};
result as usize
}
#[inline(always)]
fn reference(&self, t: Index) -> Reference {
let result = unsafe { luaL_ref(self.state, t) };
Reference(result)
}
#[inline(always)]
fn unreference(&self, t: Index, reference: Reference) {
unsafe { luaL_unref(self.state, t, reference.value()) }
}
fn load_filex(&self, filename: &str, mode: &str) -> i32 {
unsafe {
let filename_c_str = CString::new(filename).unwrap();
let mode_c_str = CString::new(mode).unwrap();
luaL_loadfilex(self.state, filename_c_str.as_ptr(), mode_c_str.as_ptr())
}
}
fn load_file(&self, filename: &str) -> i32 {
let c_str = CString::new(filename).unwrap();
unsafe { luaL_loadfile(self.state, c_str.as_ptr()) }
}
fn load_buffer<F: AsRef<[u8]>>(&self, source: F, chunk_name: Option<&str>) -> i32 {
let buffer = source.as_ref();
let chunk = chunk_name.and_then(|name| CString::new(name).ok());
unsafe {
luaL_loadbuffer(
self.state,
buffer.as_ptr() as *const c_char,
buffer.len(),
chunk.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()),
)
}
}
fn load_bufferx(&self, buff: &[u8], name: &str, mode: &str) -> i32 {
let name_c_str = CString::new(name).unwrap();
let mode_c_str = CString::new(mode).unwrap();
unsafe {
luaL_loadbufferx(
self.state,
buff.as_ptr() as *const _,
buff.len() as size_t,
name_c_str.as_ptr(),
mode_c_str.as_ptr(),
)
}
}
fn load_string(&self, source: &str) -> i32 {
let c_str = CString::new(source).unwrap();
unsafe { luaL_loadstring(self.state, c_str.as_ptr()) }
}
#[inline]
fn dump(&self, mut writer: impl FnMut(&[u8]), strip: bool) -> c_int {
use core::mem::transmute;
unsafe extern "C-unwind" fn dump_wrapper(
l: *mut lua_State,
p: *const c_void,
sz: usize,
ud: *mut c_void,
) -> c_int {
let callback = transmute::<_, &mut &mut dyn FnMut(&[u8])>(ud);
callback(core::slice::from_raw_parts(p as *const u8, sz));
0
}
let writer: &mut dyn FnMut(&[u8]) = &mut writer;
unsafe { lua_dump(self.state, dump_wrapper, transmute(&writer), strip as c_int) }
}
fn len_direct(&self, index: Index) -> lua_Integer {
unsafe { luaL_len(self.state, index) }
}
fn gsub(&self, s: &str, p: &str, r: &str) -> &str {
let s_c_str = CString::new(s).unwrap();
let p_c_str = CString::new(p).unwrap();
let r_c_str = CString::new(r).unwrap();
let ptr = unsafe {
luaL_gsub(
self.state,
s_c_str.as_ptr(),
p_c_str.as_ptr(),
r_c_str.as_ptr(),
)
};
let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
str::from_utf8(slice).unwrap()
}
fn set_fns(&self, l: &[(&str, lua_CFunction)], nup: c_int) {
let mut reg: Vec<luaL_Reg> = Vec::with_capacity(l.len() + 1);
let ents: Vec<(CString, lua_CFunction)> = l
.iter()
.map(|&(s, f)| (CString::new(s).unwrap(), f))
.collect();
for &(ref s, f) in ents.iter() {
reg.push(luaL_Reg {
name: s.as_ptr(),
func: f,
});
}
reg.push(luaL_Reg {
name: ptr::null(),
func: None,
});
unsafe { luaL_setfuncs(self.state, reg.as_ptr(), nup) }
}
#[inline(always)]
fn get_subtable(&self, idx: Index, fname: &CStr) -> bool {
unsafe { luaL_getsubtable(self.state, idx, fname.as_ptr()) != 0 }
}
#[inline(always)]
fn traceback(&self, state: *mut lua_State, msg: &CStr, level: c_int) {
unsafe { luaL_traceback(self.state, state, msg.as_ptr(), level) }
}
#[inline(always)]
fn requiref(&self, modname: &CStr, openf: CFunction, glb: bool) {
unsafe { luaL_requiref(self.state, modname.as_ptr(), Some(openf), glb as c_int) }
}
#[inline(always)]
fn arg_check(&self, cond: bool, arg: Index, extramsg: &str) {
let c_str = CString::new(extramsg).unwrap();
unsafe { luaL_argcheck(self.state, cond as c_int, arg, c_str.as_ptr()) }
}
fn check_string(&self, n: Index) -> &str {
let mut size = 0;
let ptr = unsafe { luaL_checklstring(self.state, n, &mut size) };
let slice = unsafe { slice::from_raw_parts(ptr as *const u8, size as usize) };
str::from_utf8(slice).unwrap()
}
fn opt_string<'a>(&'a mut self, n: Index, default: &'a str) -> &'a str {
let mut size = 0;
let c_str = CString::new(default).unwrap();
let ptr = unsafe { luaL_optlstring(self.state, n, c_str.as_ptr(), &mut size) };
if ptr == c_str.as_ptr() {
default
} else {
let slice = unsafe { slice::from_raw_parts(ptr as *const u8, size as usize) };
str::from_utf8(slice).unwrap()
}
}
#[inline(always)]
fn get_metatable_from_registry(&self, tname: &str) {
let c_str = CString::new(tname).unwrap();
unsafe { luaL_getmetatable(self.state, c_str.as_ptr()) }
}
#[inline(always)]
fn push<T: ToLua>(&self, value: T) -> Result<(), Error> {
match T::__PUSH {
Some(push) => {
#[cfg(debug_assertions)]
let top = self.get_top();
push(value, self)?;
#[cfg(debug_assertions)]
assert_eq!(top + 1, self.get_top(), "{}", core::any::type_name::<T>());
}
None => {
let top = self.get_top();
self.push_value(value.to_lua(self)?.index);
if !self.clear_with_keep_top_one(top) {
panic!(
"stack should be increased, top: {top} after: {}",
self.get_top()
);
}
}
}
Ok(())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Arithmetic {
Add = LUA_OPADD as isize,
Sub = LUA_OPSUB as isize,
Mul = LUA_OPMUL as isize,
Mod = LUA_OPMOD as isize,
Pow = LUA_OPPOW as isize,
Div = LUA_OPDIV as isize,
IDiv = LUA_OPIDIV as isize,
BAnd = LUA_OPBAND as isize,
BOr = LUA_OPBOR as isize,
BXor = LUA_OPBXOR as isize,
Shl = LUA_OPSHL as isize,
Shr = LUA_OPSHR as isize,
Unm = LUA_OPUNM as isize,
BNot = LUA_OPBNOT as isize,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Comparison {
Eq = LUA_OPEQ as isize,
Lt = LUA_OPLT as isize,
Le = LUA_OPLE as isize,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Type {
None = LUA_TNONE as isize,
Nil = LUA_TNIL as isize,
Boolean = LUA_TBOOLEAN as isize,
LightUserdata = LUA_TLIGHTUSERDATA as isize,
Number = LUA_TNUMBER as isize,
String = LUA_TSTRING as isize,
Table = LUA_TTABLE as isize,
Function = LUA_TFUNCTION as isize,
Userdata = LUA_TUSERDATA as isize,
Thread = LUA_TTHREAD as isize,
Invalid,
}
impl core::fmt::Display for Type {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Type::None => write!(f, "none"),
Type::Nil => write!(f, "nil"),
Type::Boolean => write!(f, "boolean"),
Type::LightUserdata => write!(f, "lightuserdata"),
Type::Number => write!(f, "number"),
Type::String => write!(f, "string"),
Type::Table => write!(f, "table"),
Type::Function => write!(f, "function"),
Type::Userdata => write!(f, "userdata"),
Type::Thread => write!(f, "thread"),
Type::Invalid => write!(f, "invalid"),
}
}
}
impl Type {
fn from_c_int(i: c_int) -> Type {
match i {
LUA_TNIL => Type::Nil,
LUA_TBOOLEAN => Type::Boolean,
LUA_TLIGHTUSERDATA => Type::LightUserdata,
LUA_TNUMBER => Type::Number,
LUA_TSTRING => Type::String,
LUA_TTABLE => Type::Table,
LUA_TFUNCTION => Type::Function,
LUA_TUSERDATA => Type::Userdata,
LUA_TTHREAD => Type::Thread,
_ => Type::Invalid,
}
}
pub fn is_none_or_nil(&self) -> bool {
matches!(*self, Type::None | Type::Nil)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GcOption {
Stop = LUA_GCSTOP as isize,
Restart = LUA_GCRESTART as isize,
Collect = LUA_GCCOLLECT as isize,
Count = LUA_GCCOUNT as isize,
CountBytes = LUA_GCCOUNTB as isize,
Step = LUA_GCSTEP as isize,
SetPause = LUA_GCSETPAUSE as isize,
SetStepMul = LUA_GCSETSTEPMUL as isize,
IsRunning = LUA_GCISRUNNING as isize,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GCMode {
Incremental,
Generational,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ThreadStatus {
Ok = LUA_OK as isize,
Yield = LUA_YIELD as isize,
RuntimeError = LUA_ERRRUN as isize,
SyntaxError = LUA_ERRSYNTAX as isize,
MemoryError = LUA_ERRMEM as isize,
MessageHandlerError = LUA_ERRERR as isize,
FileError = LUA_ERRFILE as isize,
}
impl ThreadStatus {
pub(crate) fn from_c_int(i: c_int) -> ThreadStatus {
match i {
LUA_OK => ThreadStatus::Ok,
LUA_YIELD => ThreadStatus::Yield,
LUA_ERRRUN => ThreadStatus::RuntimeError,
LUA_ERRSYNTAX => ThreadStatus::SyntaxError,
LUA_ERRMEM => ThreadStatus::MemoryError,
LUA_ERRERR => ThreadStatus::MessageHandlerError,
LUA_ERRFILE => ThreadStatus::FileError,
_ => panic!("Unknown Lua error code: {}", i),
}
}
pub fn is_ok(self) -> bool {
matches!(self, Self::Ok)
}
pub fn is_err(self) -> bool {
match self {
ThreadStatus::RuntimeError
| ThreadStatus::SyntaxError
| ThreadStatus::MemoryError
| ThreadStatus::MessageHandlerError
| ThreadStatus::FileError => true,
ThreadStatus::Ok | ThreadStatus::Yield => false,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Reference(pub c_int);
impl Default for Reference {
fn default() -> Self {
NOREF
}
}
pub const REFNIL: Reference = Reference(LUA_REFNIL);
pub const NOREF: Reference = Reference(LUA_REFNIL);
impl Reference {
pub fn is_nil_ref(self) -> bool {
self == REFNIL
}
pub fn is_no_ref(self) -> bool {
self == NOREF
}
pub fn value(self) -> c_int {
let Reference(value) = self;
value
}
}
impl From<c_int> for Reference {
fn from(i: c_int) -> Self {
Self(i)
}
}
#[cfg(feature = "std")]
bitflags::bitflags! {
pub struct HookMask: c_int {
const MASKCALL = LUA_MASKCALL;
const MASKRET = LUA_MASKRET;
const MASKLINE = LUA_MASKLINE;
const MASKCOUNT = LUA_MASKCOUNT;
}
}
impl lua_Debug {
pub fn source(&self) -> Option<Cow<str>> {
if self.source.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(self.source).to_string_lossy() })
}
}
pub fn short_src(&self) -> Cow<str> {
unsafe { CStr::from_ptr(self.short_src.as_ptr()).to_string_lossy() }
}
pub fn name(&self) -> Option<Cow<str>> {
if self.name.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(self.name).to_string_lossy() })
}
}
pub fn what(&self) -> Option<Cow<str>> {
if self.what.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(self.what).to_string_lossy() })
}
}
pub fn namewhat(&self) -> Option<Cow<str>> {
if self.namewhat.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(self.namewhat).to_string_lossy() })
}
}
}