#![allow(non_snake_case)]
use super::*;
use core::{
ffi::CStr,
fmt,
marker::PhantomData,
mem::{
MaybeUninit, size_of,
},
ptr::{
null, null_mut,
},
slice::{
from_raw_parts, from_raw_parts_mut,
},
};
pub const GLOBAL_TABLE: &CStr = c"_G";
pub const LOADED_TABLE: &CStr = c"_LOADED";
pub const PRELOAD_TABLE: &CStr = c"_PRELOAD";
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(C)]
pub struct Reg {
pub name: *const c_char,
pub func: Option<CFunction>
}
pub const NUM_SIZES: usize = size_of::<Integer>() * 16 + size_of::<Number>();
pub const NO_REF: c_int = -2;
pub const REF_NIL: c_int = -1;
#[cfg_attr(all(feature = "link-system", feature = "link-dynamic", target_os = "windows"), link(name = "lua54", kind = "raw-dylib"))]
#[cfg_attr(all(feature = "link-system", feature = "link-dynamic", not(target_os = "windows")), link(name = "lua5.4", kind = "dylib"))]
#[cfg_attr(all(feature = "link-system", not(feature = "link-dynamic"), target_os = "windows"), link(name = "lua54", kind = "static"))]
#[cfg_attr(all(feature = "link-system", not(feature = "link-dynamic"), not(target_os = "windows")), link(name = "lua5.4", kind = "static"))]
unsafe extern "C-unwind" {
pub fn luaL_newstate() -> *mut State;
pub fn luaL_prepbuffsize(buffer: *mut Buffer, size: usize) -> *mut c_char;
pub fn luaL_addlstring(buffer: *mut Buffer, str: *const c_char, len: usize);
pub fn luaL_addstring(buffer: *mut Buffer, str: *const c_char);
pub fn luaL_addvalue(buffer: *mut Buffer);
pub fn luaL_pushresult(buffer: *mut Buffer);
pub fn luaL_pushresultsize(buffer: *mut Buffer, size: usize);
lua_state_func! {
pub fn luaL_checkversion_(self, ver: Number, sz: usize);
pub fn luaL_getmetafield(
self, obj: c_int, e: *const c_char
) -> c_int;
pub fn luaL_callmeta(self, obj: c_int, e: *const c_char) -> c_int;
pub fn luaL_tolstring(
self, idx: c_int, len: *mut usize
) -> *const c_char;
pub fn luaL_argerror(self, arg: c_int, extra_msg: *const c_char) -> !;
pub fn luaL_typeerror(self, arg: c_int, type_name: *const c_char) -> !;
pub fn luaL_checklstring(
self, arg: c_int, len: *mut usize
) -> *const c_char;
pub fn luaL_optlstring(
self, arg: c_int, default: *const c_char, len: *mut usize
) -> *const c_char;
pub fn luaL_checknumber(self, arg: c_int) -> Number;
pub fn luaL_optnumber(self, arg: c_int, default: Number) -> Number;
pub fn luaL_checkinteger(self, arg: c_int) -> Integer;
pub fn luaL_optinteger(
self, arg: c_int, default: Integer
) -> Integer;
pub fn luaL_checkstack(self, sz: c_int, msg: *const c_char);
pub fn luaL_checktype(self, arg: c_int, type_tag: c_int);
pub fn luaL_checkany(self, arg: c_int);
pub fn luaL_newmetatable(self, type_name: *const c_char) -> c_int;
pub fn luaL_setmetatable(self, type_name: *const c_char);
pub fn luaL_testudata(
self, ud: c_int, type_name: *const c_char
) -> *mut c_void;
pub fn luaL_checkudata(
self, ud: c_int, type_name: *const c_char
) -> *mut c_void;
pub fn luaL_where(self, level: c_int);
pub fn luaL_error(self, fmt: *const c_char, ...) -> !;
pub fn luaL_checkoption(
self, arg: c_int, default: *const c_char,
list: *const *const c_char
) -> c_int;
pub fn luaL_fileresult(
self, status: c_int, file_name: *const c_char
) -> c_int;
pub fn luaL_execresult(self, status: c_int) -> c_int;
pub fn luaL_ref(self, table: c_int) -> c_int;
pub fn luaL_unref(self, table: c_int, ref_idx: c_int);
pub fn luaL_loadfilex(
self, file_name: *const c_char, mode: *const c_char
) -> c_int;
pub fn luaL_loadbufferx(
self,
buffer: *const c_char, buffer_sz: usize,
name: *const c_char,
mode: *const c_char
) -> c_int;
pub fn luaL_loadstring(self, code: *const c_char) -> c_int;
pub fn luaL_len(self, idx: c_int) -> Integer;
pub fn luaL_gsub(
self,
haystack: *const c_char,
needle: *const c_char, replacement: *const c_char
) -> *const c_char;
pub fn luaL_setfuncs(self, list: *const Reg, n_upvalues: c_int);
pub fn luaL_getsubtable(
self, idx: c_int, table_name: *const c_char
) -> c_int;
pub fn luaL_traceback(
self, of: *mut State,
message: *const c_char, level: c_int
);
pub fn luaL_requiref(
self, module_name: *const c_char,
open_fn: CFunction, into_global: c_int
);
pub fn luaL_buffinit(self, buffer: *mut Buffer);
pub fn luaL_buffinitsize(self, buffer: *mut Buffer, size: usize);
}
}
pub unsafe fn luaL_checkversion(l: *mut State) {
unsafe { luaL_checkversion_(l, VERSION_NUM, NUM_SIZES) }
}
pub unsafe fn luaL_loadfile(l: *mut State, file_name: *const c_char) -> c_int {
unsafe { luaL_loadfilex(l, file_name, null()) }
}
pub unsafe fn luaL_newlibtable(l: *mut State, lib: &[Reg]) {
unsafe { lua_createtable(l, 0, (lib.len() - 1) as _) }
}
pub unsafe fn luaL_newlib(l: *mut State, lib: &[Reg]) {
unsafe {
luaL_checkversion(l);
luaL_newlibtable(l, lib);
luaL_setfuncs(l, lib.as_ptr(), 0)
}
}
pub unsafe fn luaL_checkstring(l: *mut State, arg: c_int) -> *const c_char {
unsafe { luaL_checklstring(l, arg, null_mut()) }
}
pub unsafe fn luaL_optstring(l: *mut State, arg: c_int, default: *const c_char) -> *const c_char {
unsafe { luaL_optlstring(l, arg, default, null_mut()) }
}
pub unsafe fn luaL_typename(l: *mut State, idx: c_int) -> *const c_char {
unsafe { lua_typename(l, lua_type(l, idx)) }
}
pub unsafe fn luaL_dofile(l: *mut State, file_name: *const c_char) -> bool {
unsafe { luaL_loadfile(l, file_name) != 0 || lua_pcall(l, 0, MULT_RET, 0) != 0 }
}
pub unsafe fn luaL_dostring(l: *mut State, code: *const c_char) -> bool {
unsafe { luaL_loadstring(l, code) != 0 || lua_pcall(l, 0, MULT_RET, 0) != 0 }
}
pub unsafe fn luaL_getmetatable(l: *mut State, name: *const c_char) -> c_int {
unsafe { lua_getfield(l, REGISTRY_INDEX, name) }
}
pub unsafe fn luaL_loadbuffer(
l: *mut State,
buffer: *const c_char, buffer_sz: usize,
name: *const c_char
) -> c_int {
unsafe { luaL_loadbufferx(l, buffer, buffer_sz, name, null()) }
}
pub unsafe fn luaL_pushfail(l: *mut State) {
unsafe { lua_pushnil(l) }
}
pub const BUFFER_SIZE: usize =
16 * size_of::<*mut c_void>() * size_of::<Number>();
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
#[repr(C)]
pub struct Buffer<'l> {
buffer_ptr: *mut c_char,
capacity: usize,
len: usize,
l: *mut State,
pub buffer: [c_char; BUFFER_SIZE],
_life: PhantomData<&'l *mut State>
}
impl Buffer<'_> {
pub const fn zeroed() -> MaybeUninit<Self> {
MaybeUninit::new(Self {
buffer_ptr: null_mut(),
capacity: 0,
len: 0,
l: null_mut(),
buffer: [0; BUFFER_SIZE],
_life: PhantomData
})
}
pub unsafe fn new_in_raw(l: *mut State) -> Self {
let mut buffer = Self::zeroed();
unsafe {
luaL_buffinit(l, buffer.as_mut_ptr());
buffer.assume_init()
}
}
pub unsafe fn prep_with(
&mut self,
size: usize, func: impl FnOnce(&mut [c_char])
) {
let prep_space = unsafe { luaL_prepbuffsize(self as *mut _, size) };
func(unsafe { from_raw_parts_mut(prep_space, size) });
self.len += size
}
pub unsafe fn prep_default_with(&mut self, func: impl FnOnce(&mut [c_char])) {
unsafe { self.prep_with(BUFFER_SIZE, func) }
}
pub const fn len(&self) -> usize {
self.len
}
pub const fn is_empty(&self) -> bool {
self.len == 0
}
pub const fn capacity(&self) -> usize {
self.capacity
}
pub fn contents(&mut self) -> &mut [c_char] {
unsafe { from_raw_parts_mut(self.buffer_ptr, self.capacity) }
}
pub unsafe fn add_char(&mut self, ch: c_char) {
if self.len >= self.capacity {
unsafe { luaL_prepbuffsize(self as *mut _, 1) };
}
self.buffer[self.len] = ch;
self.len += 1;
}
pub fn remove(&mut self, delta: usize) {
self.len -= delta
}
pub unsafe fn add_chars(&mut self, data: &[c_char]) {
unsafe { luaL_addlstring(self as *mut _, data.as_ptr(), data.len()) }
}
pub unsafe fn add_string(&mut self, data: &CStr) {
unsafe { luaL_addstring(self as *mut _, data.as_ptr()) }
}
pub fn add_value(&mut self) {
unsafe { luaL_addvalue(self as *mut _) }
}
pub fn finish(mut self) {
debug_assert!(
self.len <= self.capacity,
"buffer length is bigger than its capacity"
);
unsafe { luaL_pushresult(&mut self as *mut _) }
}
}
const fn bytes_to_c_chars(b: &[u8]) -> &[c_char] {
unsafe { from_raw_parts(
b.as_ptr() as *const c_char,
b.len() * size_of::<u8>() / size_of::<c_char>(),
) }
}
impl fmt::Write for Buffer<'_> {
fn write_str(&mut self, s: &str) -> fmt::Result {
unsafe { self.add_chars(bytes_to_c_chars(s.as_bytes())) };
Ok(())
}
fn write_char(&mut self, c: char) -> fmt::Result {
let mut char_data = [0u8; 4];
c.encode_utf8(&mut char_data);
unsafe { self.add_chars(bytes_to_c_chars(&char_data as &[u8])) };
Ok(())
}
}