More performance optimization (userdata part)

This commit is contained in:
Alex Orlenko 2022-06-06 21:42:55 +01:00
parent f9f32bffce
commit 93d36b9068
No known key found for this signature in database
GPG Key ID: 4C150C250863B96D
4 changed files with 124 additions and 99 deletions

View File

@ -538,7 +538,7 @@ impl Lua {
#[cfg(feature = "async")] #[cfg(feature = "async")]
let ref_waker_idx = { let ref_waker_idx = {
mlua_expect!( mlua_expect!(
push_gc_userdata::<Option<Waker>>(ref_thread, None), push_gc_userdata::<Option<Waker>>(ref_thread, None, true),
"Error while creating Waker slot" "Error while creating Waker slot"
); );
ffi::lua_gettop(ref_thread) ffi::lua_gettop(ref_thread)
@ -578,7 +578,7 @@ impl Lua {
mlua_expect!( mlua_expect!(
(|state| { (|state| {
push_gc_userdata(state, Arc::clone(&extra))?; push_gc_userdata(state, Arc::clone(&extra), true)?;
protect_lua!(state, 1, 0, fn(state) { protect_lua!(state, 1, 0, fn(state) {
let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void; let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void;
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, extra_key); ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, extra_key);
@ -1408,29 +1408,15 @@ impl Lua {
let _sg = StackGuard::new(self.state); let _sg = StackGuard::new(self.state);
check_stack(self.state, 3)?; check_stack(self.state, 3)?;
if self.unlikely_memory_error() { let protect = !self.unlikely_memory_error();
let s = s.as_ref(); push_string(self.state, s, protect)?;
ffi::lua_pushlstring(self.state, s.as_ptr() as *const c_char, s.len());
} else {
push_string(self.state, s)?;
}
Ok(String(self.pop_ref())) Ok(String(self.pop_ref()))
} }
} }
/// Creates and returns a new empty table. /// Creates and returns a new empty table.
pub fn create_table(&self) -> Result<Table> { pub fn create_table(&self) -> Result<Table> {
unsafe { self.create_table_with_capacity(0, 0)
let _sg = StackGuard::new(self.state);
check_stack(self.state, 2)?;
if self.unlikely_memory_error() {
ffi::lua_newtable(self.state);
} else {
protect_lua!(self.state, 0, 1, fn(state) ffi::lua_newtable(state))?;
}
Ok(Table(self.pop_ref()))
}
} }
/// Creates and returns a new empty table, with the specified capacity. /// Creates and returns a new empty table, with the specified capacity.
@ -1442,12 +1428,8 @@ impl Lua {
let _sg = StackGuard::new(self.state); let _sg = StackGuard::new(self.state);
check_stack(self.state, 3)?; check_stack(self.state, 3)?;
if self.unlikely_memory_error() { let protect = !self.unlikely_memory_error();
ffi::lua_createtable(self.state, narr, nrec); push_table(self.state, narr, nrec, protect)?;
} else {
push_table(self.state, narr, nrec)?;
}
Ok(Table(self.pop_ref())) Ok(Table(self.pop_ref()))
} }
} }
@ -1465,20 +1447,15 @@ impl Lua {
let iter = iter.into_iter(); let iter = iter.into_iter();
let lower_bound = iter.size_hint().0; let lower_bound = iter.size_hint().0;
let protect = !self.unlikely_memory_error();
if self.unlikely_memory_error() { push_table(self.state, 0, lower_bound as c_int, protect)?;
ffi::lua_createtable(self.state, 0, lower_bound as c_int);
for (k, v) in iter {
self.push_value(k.to_lua(self)?)?;
self.push_value(v.to_lua(self)?)?;
ffi::lua_rawset(self.state, -3);
}
} else {
push_table(self.state, 0, lower_bound as c_int)?;
for (k, v) in iter { for (k, v) in iter {
self.push_value(k.to_lua(self)?)?; self.push_value(k.to_lua(self)?)?;
self.push_value(v.to_lua(self)?)?; self.push_value(v.to_lua(self)?)?;
if protect {
protect_lua!(self.state, 3, 1, fn(state) ffi::lua_rawset(state, -3))?; protect_lua!(self.state, 3, 1, fn(state) ffi::lua_rawset(state, -3))?;
} else {
ffi::lua_rawset(self.state, -3);
} }
} }
@ -1498,20 +1475,16 @@ impl Lua {
let iter = iter.into_iter(); let iter = iter.into_iter();
let lower_bound = iter.size_hint().0; let lower_bound = iter.size_hint().0;
let protect = !self.unlikely_memory_error();
if self.unlikely_memory_error() { push_table(self.state, lower_bound as c_int, 0, protect)?;
ffi::lua_createtable(self.state, lower_bound as c_int, 0);
for (i, v) in iter.enumerate() {
self.push_value(v.to_lua(self)?)?;
ffi::lua_rawseti(self.state, -2, (i + 1) as Integer);
}
} else {
push_table(self.state, lower_bound as c_int, 0)?;
for (i, v) in iter.enumerate() { for (i, v) in iter.enumerate() {
self.push_value(v.to_lua(self)?)?; self.push_value(v.to_lua(self)?)?;
if protect {
protect_lua!(self.state, 2, 1, |state| { protect_lua!(self.state, 2, 1, |state| {
ffi::lua_rawseti(state, -2, (i + 1) as Integer); ffi::lua_rawseti(state, -2, (i + 1) as Integer);
})?; })?;
} else {
ffi::lua_rawseti(self.state, -2, (i + 1) as Integer);
} }
} }
@ -1972,7 +1945,8 @@ impl Lua {
let _sg = StackGuard::new(self.state); let _sg = StackGuard::new(self.state);
check_stack(self.state, 3)?; check_stack(self.state, 3)?;
push_string(self.state, name)?; let protect = !self.unlikely_memory_error();
push_string(self.state, name, protect)?;
ffi::lua_rawget(self.state, ffi::LUA_REGISTRYINDEX); ffi::lua_rawget(self.state, ffi::LUA_REGISTRYINDEX);
self.pop_value() self.pop_value()
@ -2260,7 +2234,8 @@ impl Lua {
} }
Value::Error(err) => { Value::Error(err) => {
push_gc_userdata(self.state, WrappedFailure::Error(err))?; let protect = !self.unlikely_memory_error();
push_gc_userdata(self.state, WrappedFailure::Error(err), protect)?;
} }
} }
@ -2445,7 +2420,7 @@ impl Lua {
let metatable_nrec = methods.meta_methods.len() + fields.meta_fields.len(); let metatable_nrec = methods.meta_methods.len() + fields.meta_fields.len();
#[cfg(feature = "async")] #[cfg(feature = "async")]
let metatable_nrec = metatable_nrec + methods.async_meta_methods.len(); let metatable_nrec = metatable_nrec + methods.async_meta_methods.len();
push_table(self.state, 0, metatable_nrec as c_int)?; push_table(self.state, 0, metatable_nrec as c_int, true)?;
for (k, m) in methods.meta_methods { for (k, m) in methods.meta_methods {
self.push_value(Value::Function(self.create_callback(m)?))?; self.push_value(Value::Function(self.create_callback(m)?))?;
rawset_field(self.state, -2, k.validate()?.name())?; rawset_field(self.state, -2, k.validate()?.name())?;
@ -2466,7 +2441,7 @@ impl Lua {
let mut field_getters_index = None; let mut field_getters_index = None;
let field_getters_nrec = fields.field_getters.len(); let field_getters_nrec = fields.field_getters.len();
if field_getters_nrec > 0 { if field_getters_nrec > 0 {
push_table(self.state, 0, field_getters_nrec as c_int)?; push_table(self.state, 0, field_getters_nrec as c_int, true)?;
for (k, m) in fields.field_getters { for (k, m) in fields.field_getters {
self.push_value(Value::Function(self.create_callback(m)?))?; self.push_value(Value::Function(self.create_callback(m)?))?;
rawset_field(self.state, -2, &k)?; rawset_field(self.state, -2, &k)?;
@ -2478,7 +2453,7 @@ impl Lua {
let mut field_setters_index = None; let mut field_setters_index = None;
let field_setters_nrec = fields.field_setters.len(); let field_setters_nrec = fields.field_setters.len();
if field_setters_nrec > 0 { if field_setters_nrec > 0 {
push_table(self.state, 0, field_setters_nrec as c_int)?; push_table(self.state, 0, field_setters_nrec as c_int, true)?;
for (k, m) in fields.field_setters { for (k, m) in fields.field_setters {
self.push_value(Value::Function(self.create_callback(m)?))?; self.push_value(Value::Function(self.create_callback(m)?))?;
rawset_field(self.state, -2, &k)?; rawset_field(self.state, -2, &k)?;
@ -2492,7 +2467,7 @@ impl Lua {
#[cfg(feature = "async")] #[cfg(feature = "async")]
let methods_nrec = methods_nrec + methods.async_methods.len(); let methods_nrec = methods_nrec + methods.async_methods.len();
if methods_nrec > 0 { if methods_nrec > 0 {
push_table(self.state, 0, methods_nrec as c_int)?; push_table(self.state, 0, methods_nrec as c_int, true)?;
for (k, m) in methods.methods { for (k, m) in methods.methods {
self.push_value(Value::Function(self.create_callback(m)?))?; self.push_value(Value::Function(self.create_callback(m)?))?;
rawset_field(self.state, -2, &k)?; rawset_field(self.state, -2, &k)?;
@ -2623,13 +2598,14 @@ impl Lua {
let func = mem::transmute(func); let func = mem::transmute(func);
let extra = Arc::clone(&self.extra); let extra = Arc::clone(&self.extra);
push_gc_userdata(self.state, CallbackUpvalue { data: func, extra })?; let protect = !self.unlikely_memory_error();
if self.unlikely_memory_error() { push_gc_userdata(self.state, CallbackUpvalue { data: func, extra }, protect)?;
ffi::lua_pushcclosure(self.state, call_callback, 1); if protect {
} else {
protect_lua!(self.state, 1, 1, fn(state) { protect_lua!(self.state, 1, 1, fn(state) {
ffi::lua_pushcclosure(state, call_callback, 1); ffi::lua_pushcclosure(state, call_callback, 1);
})?; })?;
} else {
ffi::lua_pushcclosure(self.state, call_callback, 1);
} }
Ok(Function(self.pop_ref())) Ok(Function(self.pop_ref()))
@ -2686,13 +2662,14 @@ impl Lua {
let func = &*(*upvalue).data; let func = &*(*upvalue).data;
let fut = func(lua, args); let fut = func(lua, args);
let extra = Arc::clone(&(*upvalue).extra); let extra = Arc::clone(&(*upvalue).extra);
push_gc_userdata(state, AsyncPollUpvalue { data: fut, extra })?; let protect = !lua.unlikely_memory_error();
if lua.unlikely_memory_error() { push_gc_userdata(state, AsyncPollUpvalue { data: fut, extra }, protect)?;
ffi::lua_pushcclosure(state, poll_future, 1); if protect {
} else {
protect_lua!(state, 1, 1, fn(state) { protect_lua!(state, 1, 1, fn(state) {
ffi::lua_pushcclosure(state, poll_future, 1); ffi::lua_pushcclosure(state, poll_future, 1);
})?; })?;
} else {
ffi::lua_pushcclosure(state, poll_future, 1);
} }
Ok(1) Ok(1)
@ -2752,13 +2729,15 @@ impl Lua {
let func = mem::transmute(func); let func = mem::transmute(func);
let extra = Arc::clone(&self.extra); let extra = Arc::clone(&self.extra);
push_gc_userdata(self.state, AsyncCallbackUpvalue { data: func, extra })?; let protect = !self.unlikely_memory_error();
if self.unlikely_memory_error() { let upvalue = AsyncCallbackUpvalue { data: func, extra };
ffi::lua_pushcclosure(self.state, call_callback, 1); push_gc_userdata(self.state, upvalue, protect)?;
} else { if protect {
protect_lua!(self.state, 1, 1, fn(state) { protect_lua!(self.state, 1, 1, fn(state) {
ffi::lua_pushcclosure(state, call_callback, 1); ffi::lua_pushcclosure(state, call_callback, 1);
})?; })?;
} else {
ffi::lua_pushcclosure(self.state, call_callback, 1);
} }
Function(self.pop_ref()) Function(self.pop_ref())
@ -2833,10 +2812,11 @@ impl Lua {
// We push metatable first to ensure having correct metatable with `__gc` method // We push metatable first to ensure having correct metatable with `__gc` method
ffi::lua_pushnil(self.state); ffi::lua_pushnil(self.state);
self.push_userdata_metatable::<T>()?; self.push_userdata_metatable::<T>()?;
let protect = !self.unlikely_memory_error();
#[cfg(not(feature = "lua54"))] #[cfg(not(feature = "lua54"))]
push_userdata(self.state, data)?; push_userdata(self.state, data, protect)?;
#[cfg(feature = "lua54")] #[cfg(feature = "lua54")]
push_userdata_uv(self.state, data, USER_VALUE_MAXSLOT as c_int)?; push_userdata_uv(self.state, data, USER_VALUE_MAXSLOT as c_int, protect)?;
ffi::lua_replace(self.state, -3); ffi::lua_replace(self.state, -3);
ffi::lua_setmetatable(self.state, -2); ffi::lua_setmetatable(self.state, -2);

View File

@ -355,13 +355,14 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
crate::util::push_userdata::<UserDataCell<Rc<RefCell<T>>>>( crate::util::push_userdata::<UserDataCell<Rc<RefCell<T>>>>(
lua.state, lua.state,
UserDataCell::new(data.clone()), UserDataCell::new(data.clone()),
true,
)?; )?;
ffi::lua_touserdata(lua.state, -1) ffi::lua_touserdata(lua.state, -1)
}; };
// Prepare metatable, add meta methods first and then meta fields // Prepare metatable, add meta methods first and then meta fields
let meta_methods_nrec = ud_methods.meta_methods.len() + ud_fields.meta_fields.len() + 1; let meta_methods_nrec = ud_methods.meta_methods.len() + ud_fields.meta_fields.len() + 1;
push_table(lua.state, 0, meta_methods_nrec as c_int)?; push_table(lua.state, 0, meta_methods_nrec as c_int, true)?;
for (k, m) in ud_methods.meta_methods { for (k, m) in ud_methods.meta_methods {
let data = data.clone(); let data = data.clone();
@ -377,7 +378,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
let mut field_getters_index = None; let mut field_getters_index = None;
let field_getters_nrec = ud_fields.field_getters.len(); let field_getters_nrec = ud_fields.field_getters.len();
if field_getters_nrec > 0 { if field_getters_nrec > 0 {
push_table(lua.state, 0, field_getters_nrec as c_int)?; push_table(lua.state, 0, field_getters_nrec as c_int, true)?;
for (k, m) in ud_fields.field_getters { for (k, m) in ud_fields.field_getters {
let data = data.clone(); let data = data.clone();
lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?; lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
@ -389,7 +390,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
let mut field_setters_index = None; let mut field_setters_index = None;
let field_setters_nrec = ud_fields.field_setters.len(); let field_setters_nrec = ud_fields.field_setters.len();
if field_setters_nrec > 0 { if field_setters_nrec > 0 {
push_table(lua.state, 0, field_setters_nrec as c_int)?; push_table(lua.state, 0, field_setters_nrec as c_int, true)?;
for (k, m) in ud_fields.field_setters { for (k, m) in ud_fields.field_setters {
let data = data.clone(); let data = data.clone();
lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?; lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;
@ -402,7 +403,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
let methods_nrec = ud_methods.methods.len(); let methods_nrec = ud_methods.methods.len();
if methods_nrec > 0 { if methods_nrec > 0 {
// Create table used for methods lookup // Create table used for methods lookup
push_table(lua.state, 0, methods_nrec as c_int)?; push_table(lua.state, 0, methods_nrec as c_int, true)?;
for (k, m) in ud_methods.methods { for (k, m) in ud_methods.methods {
let data = data.clone(); let data = data.clone();
lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?; lua.push_value(Value::Function(wrap_method(self, data, ud_ptr, m)?))?;

View File

@ -327,12 +327,19 @@ impl<'lua> ser::SerializeSeq for SerializeVec<'lua> {
lua.push_ref(&self.table.0); lua.push_ref(&self.table.0);
lua.push_value(value)?; lua.push_value(value)?;
if lua.unlikely_memory_error() {
let len = ffi::lua_rawlen(lua.state, -2) as Integer;
ffi::lua_rawseti(lua.state, -2, len + 1);
ffi::lua_pop(lua.state, 1);
Ok(())
} else {
protect_lua!(lua.state, 2, 0, fn(state) { protect_lua!(lua.state, 2, 0, fn(state) {
let len = ffi::lua_rawlen(state, -2) as Integer; let len = ffi::lua_rawlen(state, -2) as Integer;
ffi::lua_rawseti(state, -2, len + 1); ffi::lua_rawseti(state, -2, len + 1);
}) })
} }
} }
}
fn end(self) -> Result<Value<'lua>> { fn end(self) -> Result<Value<'lua>> {
Ok(Value::Table(self.table)) Ok(Value::Table(self.table))

View File

@ -251,17 +251,33 @@ pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
pub unsafe fn push_string<S: AsRef<[u8]> + ?Sized>( pub unsafe fn push_string<S: AsRef<[u8]> + ?Sized>(
state: *mut ffi::lua_State, state: *mut ffi::lua_State,
s: &S, s: &S,
protect: bool,
) -> Result<()> { ) -> Result<()> {
let s = s.as_ref(); let s = s.as_ref();
if protect {
protect_lua!(state, 0, 1, |state| { protect_lua!(state, 0, 1, |state| {
ffi::lua_pushlstring(state, s.as_ptr() as *const c_char, s.len()); ffi::lua_pushlstring(state, s.as_ptr() as *const c_char, s.len());
}) })
} else {
ffi::lua_pushlstring(state, s.as_ptr() as *const c_char, s.len());
Ok(())
}
} }
// Uses 3 stack spaces, does not call checkstack. // Uses 3 stack spaces, does not call checkstack.
#[inline] #[inline]
pub unsafe fn push_table(state: *mut ffi::lua_State, narr: c_int, nrec: c_int) -> Result<()> { pub unsafe fn push_table(
state: *mut ffi::lua_State,
narr: c_int,
nrec: c_int,
protect: bool,
) -> Result<()> {
if protect {
protect_lua!(state, 0, 1, |state| ffi::lua_createtable(state, narr, nrec)) protect_lua!(state, 0, 1, |state| ffi::lua_createtable(state, narr, nrec))
} else {
ffi::lua_createtable(state, narr, nrec);
Ok(())
}
} }
// Uses 4 stack spaces, does not call checkstack. // Uses 4 stack spaces, does not call checkstack.
@ -281,10 +297,14 @@ where
// Internally uses 3 stack spaces, does not call checkstack. // Internally uses 3 stack spaces, does not call checkstack.
#[cfg(not(feature = "luau"))] #[cfg(not(feature = "luau"))]
#[inline] #[inline]
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> { pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool) -> Result<()> {
let ud = protect_lua!(state, 0, 1, |state| { let ud = if protect {
protect_lua!(state, 0, 1, |state| {
ffi::lua_newuserdata(state, mem::size_of::<T>()) as *mut T ffi::lua_newuserdata(state, mem::size_of::<T>()) as *mut T
})?; })?
} else {
ffi::lua_newuserdata(state, mem::size_of::<T>()) as *mut T
};
ptr::write(ud, t); ptr::write(ud, t);
Ok(()) Ok(())
} }
@ -292,7 +312,7 @@ pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
// Internally uses 3 stack spaces, does not call checkstack. // Internally uses 3 stack spaces, does not call checkstack.
#[cfg(feature = "luau")] #[cfg(feature = "luau")]
#[inline] #[inline]
pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> { pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T, protect: bool) -> Result<()> {
unsafe extern "C" fn destructor<T>(ud: *mut c_void) { unsafe extern "C" fn destructor<T>(ud: *mut c_void) {
let ud = ud as *mut T; let ud = ud as *mut T;
if *(ud.offset(1) as *mut u8) == 0 { if *(ud.offset(1) as *mut u8) == 0 {
@ -300,10 +320,14 @@ pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
} }
} }
let ud = protect_lua!(state, 0, 1, |state| {
let size = mem::size_of::<T>() + 1; let size = mem::size_of::<T>() + 1;
let ud = if protect {
protect_lua!(state, 0, 1, |state| {
ffi::lua_newuserdatadtor(state, size, destructor::<T>) as *mut T ffi::lua_newuserdatadtor(state, size, destructor::<T>) as *mut T
})?; })?
} else {
ffi::lua_newuserdatadtor(state, size, destructor::<T>) as *mut T
};
ptr::write(ud, t); ptr::write(ud, t);
*(ud.offset(1) as *mut u8) = 0; // Mark as not destructed *(ud.offset(1) as *mut u8) = 0; // Mark as not destructed
@ -313,10 +337,19 @@ pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
// Internally uses 3 stack spaces, does not call checkstack. // Internally uses 3 stack spaces, does not call checkstack.
#[cfg(feature = "lua54")] #[cfg(feature = "lua54")]
#[inline] #[inline]
pub unsafe fn push_userdata_uv<T>(state: *mut ffi::lua_State, t: T, nuvalue: c_int) -> Result<()> { pub unsafe fn push_userdata_uv<T>(
let ud = protect_lua!(state, 0, 1, |state| { state: *mut ffi::lua_State,
t: T,
nuvalue: c_int,
protect: bool,
) -> Result<()> {
let ud = if protect {
protect_lua!(state, 0, 1, |state| {
ffi::lua_newuserdatauv(state, mem::size_of::<T>(), nuvalue) as *mut T ffi::lua_newuserdatauv(state, mem::size_of::<T>(), nuvalue) as *mut T
})?; })?
} else {
ffi::lua_newuserdatauv(state, mem::size_of::<T>(), nuvalue) as *mut T
};
ptr::write(ud, t); ptr::write(ud, t);
Ok(()) Ok(())
} }
@ -349,8 +382,12 @@ pub unsafe fn take_userdata<T>(state: *mut ffi::lua_State) -> T {
// Pushes the userdata and attaches a metatable with __gc method. // Pushes the userdata and attaches a metatable with __gc method.
// Internally uses 3 stack spaces, does not call checkstack. // Internally uses 3 stack spaces, does not call checkstack.
pub unsafe fn push_gc_userdata<T: Any>(state: *mut ffi::lua_State, t: T) -> Result<()> { pub unsafe fn push_gc_userdata<T: Any>(
push_userdata(state, t)?; state: *mut ffi::lua_State,
t: T,
protect: bool,
) -> Result<()> {
push_userdata(state, t, protect)?;
get_gc_metatable::<T>(state); get_gc_metatable::<T>(state);
ffi::lua_setmetatable(state, -2); ffi::lua_setmetatable(state, -2);
Ok(()) Ok(())
@ -505,7 +542,7 @@ pub unsafe fn init_userdata_metatable<T>(
// Push `__index` generator function // Push `__index` generator function
init_userdata_metatable_index(state)?; init_userdata_metatable_index(state)?;
push_string(state, "__index")?; push_string(state, "__index", true)?;
let index_type = ffi::lua_rawget(state, -3); let index_type = ffi::lua_rawget(state, -3);
match index_type { match index_type {
ffi::LUA_TNIL | ffi::LUA_TTABLE | ffi::LUA_TFUNCTION => { ffi::LUA_TNIL | ffi::LUA_TTABLE | ffi::LUA_TFUNCTION => {
@ -530,7 +567,7 @@ pub unsafe fn init_userdata_metatable<T>(
// Push `__newindex` generator function // Push `__newindex` generator function
init_userdata_metatable_newindex(state)?; init_userdata_metatable_newindex(state)?;
push_string(state, "__newindex")?; push_string(state, "__newindex", true)?;
let newindex_type = ffi::lua_rawget(state, -3); let newindex_type = ffi::lua_rawget(state, -3);
match newindex_type { match newindex_type {
ffi::LUA_TNIL | ffi::LUA_TTABLE | ffi::LUA_TFUNCTION => { ffi::LUA_TNIL | ffi::LUA_TTABLE | ffi::LUA_TFUNCTION => {
@ -758,7 +795,7 @@ pub unsafe fn init_gc_metatable<T: Any>(
) -> Result<()> { ) -> Result<()> {
check_stack(state, 6)?; check_stack(state, 6)?;
push_table(state, 0, 3)?; push_table(state, 0, 3, true)?;
#[cfg(not(feature = "luau"))] #[cfg(not(feature = "luau"))]
{ {
@ -836,7 +873,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
} }
}?; }?;
push_string(state, &*err_buf)?; push_string(state, &*err_buf, true)?;
(*err_buf).clear(); (*err_buf).clear();
Ok(1) Ok(1)
@ -857,7 +894,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
callback_error(state, |_| Err(Error::CallbackDestructed)) callback_error(state, |_| Err(Error::CallbackDestructed))
} }
push_table(state, 0, 26)?; push_table(state, 0, 26, true)?;
ffi::lua_pushcfunction(state, destructed_error); ffi::lua_pushcfunction(state, destructed_error);
for &method in &[ for &method in &[
"__add", "__add",
@ -914,7 +951,7 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
// Create error print buffer // Create error print buffer
init_gc_metatable::<String>(state, None)?; init_gc_metatable::<String>(state, None)?;
push_gc_userdata(state, String::new())?; push_gc_userdata(state, String::new(), true)?;
protect_lua!(state, 1, 0, fn(state) { protect_lua!(state, 1, 0, fn(state) {
let err_buf_key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void; let err_buf_key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void;
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, err_buf_key); ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, err_buf_key);