Stack assertions review
Other minor code and documentation updates
This commit is contained in:
parent
463fc646bc
commit
3f55958bdd
|
@ -29,11 +29,13 @@ extern "C" {
|
||||||
fn lua_tolstring_s(L: *mut lua_State) -> c_int;
|
fn lua_tolstring_s(L: *mut lua_State) -> c_int;
|
||||||
fn lua_newthread_s(L: *mut lua_State) -> c_int;
|
fn lua_newthread_s(L: *mut lua_State) -> c_int;
|
||||||
fn lua_newuserdata_s(L: *mut lua_State) -> c_int;
|
fn lua_newuserdata_s(L: *mut lua_State) -> c_int;
|
||||||
|
fn lua_newwrappederror_s(L: *mut lua_State) -> c_int;
|
||||||
fn lua_pushcclosure_s(L: *mut lua_State) -> c_int;
|
fn lua_pushcclosure_s(L: *mut lua_State) -> c_int;
|
||||||
fn lua_pushrclosure_s(L: *mut lua_State) -> c_int;
|
fn lua_pushrclosure_s(L: *mut lua_State) -> c_int;
|
||||||
fn luaL_requiref_s(L: *mut lua_State) -> c_int;
|
fn luaL_requiref_s(L: *mut lua_State) -> c_int;
|
||||||
fn error_traceback_s(L: *mut lua_State) -> c_int;
|
fn error_traceback_s(L: *mut lua_State) -> c_int;
|
||||||
|
|
||||||
|
fn lua_newtable_s(L: *mut lua_State) -> c_int;
|
||||||
fn lua_createtable_s(L: *mut lua_State) -> c_int;
|
fn lua_createtable_s(L: *mut lua_State) -> c_int;
|
||||||
fn lua_gettable_s(L: *mut lua_State) -> c_int;
|
fn lua_gettable_s(L: *mut lua_State) -> c_int;
|
||||||
fn lua_settable_s(L: *mut lua_State) -> c_int;
|
fn lua_settable_s(L: *mut lua_State) -> c_int;
|
||||||
|
@ -118,21 +120,25 @@ pub unsafe fn lua_newuserdata(state: *mut lua_State, size: usize) -> Result<*mut
|
||||||
Ok(super::lua_touserdata(state, -1))
|
Ok(super::lua_touserdata(state, -1))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses 4 stack spaces
|
// Uses 2 stack spaces
|
||||||
pub unsafe fn lua_pushcclosure(state: *mut lua_State, f: lua_CFunction, n: c_int) -> Result<()> {
|
pub unsafe fn lua_newwrappederror(state: *mut lua_State) -> Result<*mut c_void> {
|
||||||
super::lua_pushlightuserdata(state, f as *mut c_void);
|
protect_lua(state, 0, lua_newwrappederror_s)?;
|
||||||
super::lua_pushinteger(state, n as lua_Integer);
|
Ok(super::lua_touserdata(state, -1))
|
||||||
protect_lua(state, n + 2, lua_pushcclosure_s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses 4 stack spaces
|
// Uses 3 stack spaces
|
||||||
|
pub unsafe fn lua_pushcclosure(state: *mut lua_State, f: lua_CFunction, n: c_int) -> Result<()> {
|
||||||
|
super::lua_pushlightuserdata(state, f as *mut c_void);
|
||||||
|
protect_lua(state, n + 1, lua_pushcclosure_s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uses 3 stack spaces
|
||||||
pub unsafe fn lua_pushrclosure(state: *mut lua_State, f: lua_CFunction, n: c_int) -> Result<()> {
|
pub unsafe fn lua_pushrclosure(state: *mut lua_State, f: lua_CFunction, n: c_int) -> Result<()> {
|
||||||
super::lua_pushlightuserdata(state, f as *mut c_void);
|
super::lua_pushlightuserdata(state, f as *mut c_void);
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
super::lua_rotate(state, -n - 1, 1);
|
super::lua_rotate(state, -n - 1, 1);
|
||||||
}
|
}
|
||||||
super::lua_pushinteger(state, n as lua_Integer + 1);
|
protect_lua(state, n + 1, lua_pushrclosure_s)
|
||||||
protect_lua(state, n + 2, lua_pushrclosure_s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uses 5 stack spaces
|
// Uses 5 stack spaces
|
||||||
|
@ -163,6 +169,11 @@ pub unsafe fn error_traceback2(state: *mut lua_State, state2: *mut lua_State) ->
|
||||||
// Table functions
|
// Table functions
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// Uses 2 stack spaces
|
||||||
|
pub unsafe fn lua_newtable(state: *mut lua_State) -> Result<()> {
|
||||||
|
protect_lua(state, 0, lua_newtable_s)
|
||||||
|
}
|
||||||
|
|
||||||
// Uses 4 stack spaces
|
// Uses 4 stack spaces
|
||||||
pub unsafe fn lua_createtable(state: *mut lua_State, narr: c_int, nrec: c_int) -> Result<()> {
|
pub unsafe fn lua_createtable(state: *mut lua_State, narr: c_int, nrec: c_int) -> Result<()> {
|
||||||
super::lua_pushinteger(state, narr as lua_Integer);
|
super::lua_pushinteger(state, narr as lua_Integer);
|
||||||
|
|
|
@ -135,16 +135,21 @@ int lua_newuserdata_s(lua_State *L) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lua_newwrappederror_s(lua_State *L) {
|
||||||
|
lua_newuserdata(L, MLUA_WRAPPED_ERROR_SIZE);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int lua_pushcclosure_s(lua_State *L) {
|
int lua_pushcclosure_s(lua_State *L) {
|
||||||
lua_CFunction fn = lua_touserdata(L, -2);
|
int n = lua_gettop(L) - 1;
|
||||||
lua_Integer n = lua_tointeger(L, -1);
|
lua_CFunction fn = lua_touserdata(L, -1);
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 1);
|
||||||
lua_pushcclosure(L, fn, n);
|
lua_pushcclosure(L, fn, n);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_pushrclosure_s(lua_State *L) {
|
int lua_pushrclosure_s(lua_State *L) {
|
||||||
lua_Integer n = lua_popinteger(L);
|
int n = lua_gettop(L);
|
||||||
lua_pushcclosure(L, lua_call_rust, n);
|
lua_pushcclosure(L, lua_call_rust, n);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -162,6 +167,11 @@ int luaL_requiref_s(lua_State *L) {
|
||||||
// Table functions
|
// Table functions
|
||||||
//
|
//
|
||||||
|
|
||||||
|
int lua_newtable_s(lua_State *L) {
|
||||||
|
lua_createtable(L, 0, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int lua_createtable_s(lua_State *L) {
|
int lua_createtable_s(lua_State *L) {
|
||||||
int nrec = lua_popinteger(L);
|
int nrec = lua_popinteger(L);
|
||||||
int narr = lua_popinteger(L);
|
int narr = lua_popinteger(L);
|
||||||
|
@ -344,7 +354,7 @@ int meta_newindex_impl(lua_State *state) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// See function::bind
|
// See Function::bind
|
||||||
int bind_call_impl(lua_State *state) {
|
int bind_call_impl(lua_State *state) {
|
||||||
int nargs = lua_gettop(state);
|
int nargs = lua_gettop(state);
|
||||||
int nbinds = lua_tointeger(state, lua_upvalueindex(2));
|
int nbinds = lua_tointeger(state, lua_upvalueindex(2));
|
||||||
|
|
|
@ -207,13 +207,9 @@ impl<'lua> Function<'lua> {
|
||||||
assert_stack(lua.state, 1);
|
assert_stack(lua.state, 1);
|
||||||
|
|
||||||
lua.push_ref(&self.0);
|
lua.push_ref(&self.0);
|
||||||
|
let data_ptr = &mut data as *mut Vec<u8> as *mut c_void;
|
||||||
let strip = if strip { 1 } else { 0 };
|
let strip = if strip { 1 } else { 0 };
|
||||||
ffi::lua_dump(
|
ffi::lua_dump(lua.state, writer, data_ptr, strip);
|
||||||
lua.state,
|
|
||||||
writer,
|
|
||||||
&mut data as *mut Vec<u8> as *mut c_void,
|
|
||||||
strip,
|
|
||||||
);
|
|
||||||
ffi::lua_pop(lua.state, 1);
|
ffi::lua_pop(lua.state, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
173
src/lua.rs
173
src/lua.rs
|
@ -84,9 +84,9 @@ struct MemoryInfo {
|
||||||
/// In Lua 5.4 GC can work in two modes: incremental and generational.
|
/// In Lua 5.4 GC can work in two modes: incremental and generational.
|
||||||
/// Previous Lua versions support only incremental GC.
|
/// Previous Lua versions support only incremental GC.
|
||||||
///
|
///
|
||||||
/// More information can be found in the Lua 5.x [documentation][lua_doc].
|
/// More information can be found in the Lua 5.x [documentation].
|
||||||
///
|
///
|
||||||
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#2.5
|
/// [documentation]: https://www.lua.org/manual/5.4/manual.html#2.5
|
||||||
pub enum GCMode {
|
pub enum GCMode {
|
||||||
Incremental,
|
Incremental,
|
||||||
/// Requires `feature = "lua54"`
|
/// Requires `feature = "lua54"`
|
||||||
|
@ -128,11 +128,15 @@ impl Drop for Lua {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Lua {
|
impl Lua {
|
||||||
/// Creates a new Lua state and loads the safe subset of the standard libraries.
|
/// Creates a new Lua state and loads the **safe** subset of the standard libraries.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// The created Lua state would have _some_ safety guarantees and would not allow to load unsafe
|
/// The created Lua state would have _some_ safety guarantees and would not allow to load unsafe
|
||||||
/// standard libraries or C modules.
|
/// standard libraries or C modules.
|
||||||
|
///
|
||||||
|
/// See [`StdLib`] documentation for a list of unsafe modules that cannot be loaded.
|
||||||
|
///
|
||||||
|
/// [`StdLib`]: struct.StdLib.html
|
||||||
#[allow(clippy::new_without_default)]
|
#[allow(clippy::new_without_default)]
|
||||||
pub fn new() -> Lua {
|
pub fn new() -> Lua {
|
||||||
mlua_expect!(
|
mlua_expect!(
|
||||||
|
@ -157,6 +161,8 @@ impl Lua {
|
||||||
/// The created Lua state would have _some_ safety guarantees and would not allow to load unsafe
|
/// The created Lua state would have _some_ safety guarantees and would not allow to load unsafe
|
||||||
/// standard libraries or C modules.
|
/// standard libraries or C modules.
|
||||||
///
|
///
|
||||||
|
/// See [`StdLib`] documentation for a list of unsafe modules that cannot be loaded.
|
||||||
|
///
|
||||||
/// [`StdLib`]: struct.StdLib.html
|
/// [`StdLib`]: struct.StdLib.html
|
||||||
pub fn new_with(libs: StdLib) -> Result<Lua> {
|
pub fn new_with(libs: StdLib) -> Result<Lua> {
|
||||||
if libs.contains(StdLib::DEBUG) {
|
if libs.contains(StdLib::DEBUG) {
|
||||||
|
@ -188,7 +194,7 @@ impl Lua {
|
||||||
/// Use the [`StdLib`] flags to specifiy the libraries you want to load.
|
/// Use the [`StdLib`] flags to specifiy the libraries you want to load.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// The created Lua state would not have safety guarantees and would allow to load C modules.
|
/// The created Lua state will not have safety guarantees and allow to load C modules.
|
||||||
///
|
///
|
||||||
/// [`StdLib`]: struct.StdLib.html
|
/// [`StdLib`]: struct.StdLib.html
|
||||||
pub unsafe fn unsafe_new_with(libs: StdLib) -> Lua {
|
pub unsafe fn unsafe_new_with(libs: StdLib) -> Lua {
|
||||||
|
@ -289,10 +295,18 @@ impl Lua {
|
||||||
let main_state = maybe_main_state.unwrap_or(state);
|
let main_state = maybe_main_state.unwrap_or(state);
|
||||||
let main_state_top = ffi::lua_gettop(main_state);
|
let main_state_top = ffi::lua_gettop(main_state);
|
||||||
|
|
||||||
let (ref_thread, wrapped_error_key, wrapped_panic_key) = mlua_expect!(
|
let ref_thread = mlua_expect!(
|
||||||
(|state| {
|
(|state| {
|
||||||
|
// Before initializing the error registry, we must set Error/Panic size.
|
||||||
|
// Error/Panic keys are not needed during the registry initialization.
|
||||||
|
ffi::safe::WRAPPED_ERROR_SIZE = mem::size_of::<WrappedError>();
|
||||||
|
ffi::safe::WRAPPED_PANIC_SIZE = mem::size_of::<WrappedPanic>();
|
||||||
|
|
||||||
let (wrapped_error_key, wrapped_panic_key) = init_error_registry(state)?;
|
let (wrapped_error_key, wrapped_panic_key) = init_error_registry(state)?;
|
||||||
|
|
||||||
|
ffi::safe::WRAPPED_ERROR_KEY = wrapped_error_key as *const c_void;
|
||||||
|
ffi::safe::WRAPPED_PANIC_KEY = wrapped_panic_key as *const c_void;
|
||||||
|
|
||||||
// Create the internal metatables and place them in the registry
|
// Create the internal metatables and place them in the registry
|
||||||
// to prevent them from being garbage collected.
|
// to prevent them from being garbage collected.
|
||||||
|
|
||||||
|
@ -317,7 +331,7 @@ impl Lua {
|
||||||
let ref_thread = ffi::safe::lua_newthread(state)?;
|
let ref_thread = ffi::safe::lua_newthread(state)?;
|
||||||
ffi::safe::luaL_ref(state, ffi::LUA_REGISTRYINDEX)?;
|
ffi::safe::luaL_ref(state, ffi::LUA_REGISTRYINDEX)?;
|
||||||
|
|
||||||
Ok::<_, Error>((ref_thread, wrapped_error_key, wrapped_panic_key))
|
Ok::<_, Error>(ref_thread)
|
||||||
})(main_state),
|
})(main_state),
|
||||||
"Error during Lua construction",
|
"Error during Lua construction",
|
||||||
);
|
);
|
||||||
|
@ -342,12 +356,9 @@ impl Lua {
|
||||||
push_gc_userdata(main_state, Arc::downgrade(&extra)),
|
push_gc_userdata(main_state, Arc::downgrade(&extra)),
|
||||||
"Error while storing extra data",
|
"Error while storing extra data",
|
||||||
);
|
);
|
||||||
|
let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void;
|
||||||
mlua_expect!(
|
mlua_expect!(
|
||||||
ffi::safe::lua_rawsetp(
|
ffi::safe::lua_rawsetp(main_state, ffi::LUA_REGISTRYINDEX, extra_key,),
|
||||||
main_state,
|
|
||||||
ffi::LUA_REGISTRYINDEX,
|
|
||||||
&EXTRA_REGISTRY_KEY as *const u8 as *const c_void
|
|
||||||
),
|
|
||||||
"Error while storing extra data"
|
"Error while storing extra data"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -357,11 +368,6 @@ impl Lua {
|
||||||
);
|
);
|
||||||
assert_stack(main_state, ffi::LUA_MINSTACK);
|
assert_stack(main_state, ffi::LUA_MINSTACK);
|
||||||
|
|
||||||
ffi::safe::WRAPPED_ERROR_SIZE = mem::size_of::<WrappedError>();
|
|
||||||
ffi::safe::WRAPPED_PANIC_SIZE = mem::size_of::<WrappedPanic>();
|
|
||||||
ffi::safe::WRAPPED_ERROR_KEY = wrapped_error_key as *const c_void;
|
|
||||||
ffi::safe::WRAPPED_PANIC_KEY = wrapped_panic_key as *const c_void;
|
|
||||||
|
|
||||||
Lua {
|
Lua {
|
||||||
state,
|
state,
|
||||||
main_state: maybe_main_state,
|
main_state: maybe_main_state,
|
||||||
|
@ -642,15 +648,8 @@ impl Lua {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lua54")]
|
#[cfg(feature = "lua54")]
|
||||||
let prev_mode = unsafe {
|
let prev_mode =
|
||||||
ffi::lua_gc(
|
unsafe { ffi::lua_gc(state, ffi::LUA_GCINC, pause, step_multiplier, step_size) };
|
||||||
state,
|
|
||||||
ffi::LUA_GCSETPAUSE,
|
|
||||||
pause,
|
|
||||||
step_multiplier,
|
|
||||||
step_size,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
#[cfg(feature = "lua54")]
|
#[cfg(feature = "lua54")]
|
||||||
match prev_mode {
|
match prev_mode {
|
||||||
ffi::LUA_GCINC => GCMode::Incremental,
|
ffi::LUA_GCINC => GCMode::Incremental,
|
||||||
|
@ -691,7 +690,7 @@ impl Lua {
|
||||||
/// [`Chunk::exec`]: struct.Chunk.html#method.exec
|
/// [`Chunk::exec`]: struct.Chunk.html#method.exec
|
||||||
pub fn load<'lua, 'a, S>(&'lua self, source: &'a S) -> Chunk<'lua, 'a>
|
pub fn load<'lua, 'a, S>(&'lua self, source: &'a S) -> Chunk<'lua, 'a>
|
||||||
where
|
where
|
||||||
S: ?Sized + AsRef<[u8]>,
|
S: AsRef<[u8]> + ?Sized,
|
||||||
{
|
{
|
||||||
Chunk {
|
Chunk {
|
||||||
lua: self,
|
lua: self,
|
||||||
|
@ -711,7 +710,7 @@ impl Lua {
|
||||||
) -> Result<Function<'lua>> {
|
) -> Result<Function<'lua>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 1);
|
check_stack(self.state, 1)?;
|
||||||
|
|
||||||
let mode_str = match mode {
|
let mode_str = match mode {
|
||||||
Some(ChunkMode::Binary) if self.safe => {
|
Some(ChunkMode::Binary) if self.safe => {
|
||||||
|
@ -756,11 +755,11 @@ impl Lua {
|
||||||
/// here.
|
/// here.
|
||||||
pub fn create_string<S>(&self, s: &S) -> Result<String>
|
pub fn create_string<S>(&self, s: &S) -> Result<String>
|
||||||
where
|
where
|
||||||
S: ?Sized + AsRef<[u8]>,
|
S: AsRef<[u8]> + ?Sized,
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 4);
|
check_stack(self.state, 3)?;
|
||||||
ffi::safe::lua_pushstring(self.state, s)?;
|
ffi::safe::lua_pushstring(self.state, s)?;
|
||||||
Ok(String(self.pop_ref()))
|
Ok(String(self.pop_ref()))
|
||||||
}
|
}
|
||||||
|
@ -768,7 +767,12 @@ impl Lua {
|
||||||
|
|
||||||
/// 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> {
|
||||||
self.create_table_with_capacity(0, 0)
|
unsafe {
|
||||||
|
let _sg = StackGuard::new(self.state);
|
||||||
|
check_stack(self.state, 2)?;
|
||||||
|
ffi::safe::lua_newtable(self.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.
|
||||||
|
@ -778,14 +782,14 @@ impl Lua {
|
||||||
pub fn create_table_with_capacity(&self, narr: c_int, nrec: c_int) -> Result<Table> {
|
pub fn create_table_with_capacity(&self, narr: c_int, nrec: c_int) -> Result<Table> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 4);
|
check_stack(self.state, 4)?;
|
||||||
ffi::safe::lua_createtable(self.state, narr, nrec)?;
|
ffi::safe::lua_createtable(self.state, narr, nrec)?;
|
||||||
Ok(Table(self.pop_ref()))
|
Ok(Table(self.pop_ref()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a table and fills it with values from an iterator.
|
/// Creates a table and fills it with values from an iterator.
|
||||||
pub fn create_table_from<'lua, K, V, I>(&'lua self, cont: I) -> Result<Table<'lua>>
|
pub fn create_table_from<'lua, K, V, I>(&'lua self, iter: I) -> Result<Table<'lua>>
|
||||||
where
|
where
|
||||||
K: ToLua<'lua>,
|
K: ToLua<'lua>,
|
||||||
V: ToLua<'lua>,
|
V: ToLua<'lua>,
|
||||||
|
@ -793,12 +797,12 @@ impl Lua {
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
// `Lua` instance assumes that on any callback, the Lua stack has at least LUA_MINSTACK
|
check_stack(self.state, 6)?;
|
||||||
// slots available to avoid panics.
|
|
||||||
check_stack(self.state, 5 + ffi::LUA_MINSTACK)?;
|
|
||||||
|
|
||||||
ffi::safe::lua_createtable(self.state, 0, 0)?;
|
let iter = iter.into_iter();
|
||||||
for (k, v) in cont {
|
let lower_bound = iter.size_hint().0;
|
||||||
|
ffi::safe::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(k.to_lua(self)?)?;
|
||||||
self.push_value(v.to_lua(self)?)?;
|
self.push_value(v.to_lua(self)?)?;
|
||||||
ffi::safe::lua_rawset(self.state, -3)?;
|
ffi::safe::lua_rawset(self.state, -3)?;
|
||||||
|
@ -809,12 +813,25 @@ impl Lua {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a table from an iterator of values, using `1..` as the keys.
|
/// Creates a table from an iterator of values, using `1..` as the keys.
|
||||||
pub fn create_sequence_from<'lua, T, I>(&'lua self, cont: I) -> Result<Table<'lua>>
|
pub fn create_sequence_from<'lua, T, I>(&'lua self, iter: I) -> Result<Table<'lua>>
|
||||||
where
|
where
|
||||||
T: ToLua<'lua>,
|
T: ToLua<'lua>,
|
||||||
I: IntoIterator<Item = T>,
|
I: IntoIterator<Item = T>,
|
||||||
{
|
{
|
||||||
self.create_table_from(cont.into_iter().enumerate().map(|(k, v)| (k + 1, v)))
|
unsafe {
|
||||||
|
let _sg = StackGuard::new(self.state);
|
||||||
|
check_stack(self.state, 6)?;
|
||||||
|
|
||||||
|
let iter = iter.into_iter();
|
||||||
|
let lower_bound = iter.size_hint().0;
|
||||||
|
ffi::safe::lua_createtable(self.state, lower_bound as c_int, 0)?;
|
||||||
|
for (i, v) in iter.enumerate() {
|
||||||
|
self.push_value(v.to_lua(self)?)?;
|
||||||
|
ffi::safe::lua_rawseti(self.state, -2, (i + 1) as Integer)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Table(self.pop_ref()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps a Rust function or closure, creating a callable Lua function handle to it.
|
/// Wraps a Rust function or closure, creating a callable Lua function handle to it.
|
||||||
|
@ -966,7 +983,7 @@ impl Lua {
|
||||||
pub fn create_thread<'lua>(&'lua self, func: Function<'lua>) -> Result<Thread<'lua>> {
|
pub fn create_thread<'lua>(&'lua self, func: Function<'lua>) -> Result<Thread<'lua>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 2);
|
check_stack(self.state, 2)?;
|
||||||
|
|
||||||
let thread_state = ffi::safe::lua_newthread(self.state)?;
|
let thread_state = ffi::safe::lua_newthread(self.state)?;
|
||||||
self.push_ref(&func.0);
|
self.push_ref(&func.0);
|
||||||
|
@ -1000,7 +1017,7 @@ impl Lua {
|
||||||
pub fn globals(&self) -> Table {
|
pub fn globals(&self) -> Table {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 2);
|
assert_stack(self.state, 1);
|
||||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
|
ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ffi::LUA_RIDX_GLOBALS);
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
|
@ -1013,6 +1030,8 @@ impl Lua {
|
||||||
/// for parameters given to a callback, this will be whatever Lua thread called the callback.
|
/// for parameters given to a callback, this will be whatever Lua thread called the callback.
|
||||||
pub fn current_thread(&self) -> Thread {
|
pub fn current_thread(&self) -> Thread {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let _sg = StackGuard::new(self.state);
|
||||||
|
assert_stack(self.state, 1);
|
||||||
ffi::lua_pushthread(self.state);
|
ffi::lua_pushthread(self.state);
|
||||||
Thread(self.pop_ref())
|
Thread(self.pop_ref())
|
||||||
}
|
}
|
||||||
|
@ -1078,7 +1097,7 @@ impl Lua {
|
||||||
Value::String(s) => Some(s),
|
Value::String(s) => Some(s),
|
||||||
v => unsafe {
|
v => unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 4);
|
check_stack(self.state, 5)?;
|
||||||
|
|
||||||
self.push_value(v)?;
|
self.push_value(v)?;
|
||||||
if !ffi::safe::lua_tolstring(self.state, -1, ptr::null_mut())?.is_null() {
|
if !ffi::safe::lua_tolstring(self.state, -1, ptr::null_mut())?.is_null() {
|
||||||
|
@ -1101,7 +1120,7 @@ impl Lua {
|
||||||
Value::Integer(i) => Some(i),
|
Value::Integer(i) => Some(i),
|
||||||
v => unsafe {
|
v => unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 2);
|
check_stack(self.state, 2)?;
|
||||||
|
|
||||||
self.push_value(v)?;
|
self.push_value(v)?;
|
||||||
let mut isint = 0;
|
let mut isint = 0;
|
||||||
|
@ -1125,7 +1144,7 @@ impl Lua {
|
||||||
Value::Number(n) => Some(n),
|
Value::Number(n) => Some(n),
|
||||||
v => unsafe {
|
v => unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 2);
|
check_stack(self.state, 2)?;
|
||||||
|
|
||||||
self.push_value(v)?;
|
self.push_value(v)?;
|
||||||
let mut isnum = 0;
|
let mut isnum = 0;
|
||||||
|
@ -1168,13 +1187,13 @@ impl Lua {
|
||||||
/// state.
|
/// state.
|
||||||
pub fn set_named_registry_value<'lua, S, T>(&'lua self, name: &S, t: T) -> Result<()>
|
pub fn set_named_registry_value<'lua, S, T>(&'lua self, name: &S, t: T) -> Result<()>
|
||||||
where
|
where
|
||||||
S: ?Sized + AsRef<[u8]>,
|
S: AsRef<[u8]> + ?Sized,
|
||||||
T: ToLua<'lua>,
|
T: ToLua<'lua>,
|
||||||
{
|
{
|
||||||
let t = t.to_lua(self)?;
|
let t = t.to_lua(self)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 5);
|
check_stack(self.state, 5)?;
|
||||||
|
|
||||||
self.push_value(t)?;
|
self.push_value(t)?;
|
||||||
ffi::safe::lua_rawsetfield(self.state, ffi::LUA_REGISTRYINDEX, name)
|
ffi::safe::lua_rawsetfield(self.state, ffi::LUA_REGISTRYINDEX, name)
|
||||||
|
@ -1189,12 +1208,12 @@ impl Lua {
|
||||||
/// [`set_named_registry_value`]: #method.set_named_registry_value
|
/// [`set_named_registry_value`]: #method.set_named_registry_value
|
||||||
pub fn named_registry_value<'lua, S, T>(&'lua self, name: &S) -> Result<T>
|
pub fn named_registry_value<'lua, S, T>(&'lua self, name: &S) -> Result<T>
|
||||||
where
|
where
|
||||||
S: ?Sized + AsRef<[u8]>,
|
S: AsRef<[u8]> + ?Sized,
|
||||||
T: FromLua<'lua>,
|
T: FromLua<'lua>,
|
||||||
{
|
{
|
||||||
let value = unsafe {
|
let value = unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 4);
|
check_stack(self.state, 3)?;
|
||||||
|
|
||||||
ffi::safe::lua_pushstring(self.state, name)?;
|
ffi::safe::lua_pushstring(self.state, name)?;
|
||||||
ffi::lua_rawget(self.state, ffi::LUA_REGISTRYINDEX);
|
ffi::lua_rawget(self.state, ffi::LUA_REGISTRYINDEX);
|
||||||
|
@ -1211,7 +1230,7 @@ impl Lua {
|
||||||
/// [`set_named_registry_value`]: #method.set_named_registry_value
|
/// [`set_named_registry_value`]: #method.set_named_registry_value
|
||||||
pub fn unset_named_registry_value<S>(&self, name: &S) -> Result<()>
|
pub fn unset_named_registry_value<S>(&self, name: &S) -> Result<()>
|
||||||
where
|
where
|
||||||
S: ?Sized + AsRef<[u8]>,
|
S: AsRef<[u8]> + ?Sized,
|
||||||
{
|
{
|
||||||
self.set_named_registry_value(name, Nil)
|
self.set_named_registry_value(name, Nil)
|
||||||
}
|
}
|
||||||
|
@ -1229,7 +1248,7 @@ impl Lua {
|
||||||
let t = t.to_lua(self)?;
|
let t = t.to_lua(self)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 2);
|
check_stack(self.state, 4)?;
|
||||||
|
|
||||||
self.push_value(t)?;
|
self.push_value(t)?;
|
||||||
let registry_id = ffi::safe::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX)?;
|
let registry_id = ffi::safe::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX)?;
|
||||||
|
@ -1250,13 +1269,13 @@ impl Lua {
|
||||||
///
|
///
|
||||||
/// [`create_registry_value`]: #method.create_registry_value
|
/// [`create_registry_value`]: #method.create_registry_value
|
||||||
pub fn registry_value<'lua, T: FromLua<'lua>>(&'lua self, key: &RegistryKey) -> Result<T> {
|
pub fn registry_value<'lua, T: FromLua<'lua>>(&'lua self, key: &RegistryKey) -> Result<T> {
|
||||||
let value = unsafe {
|
|
||||||
if !self.owns_registry_value(key) {
|
if !self.owns_registry_value(key) {
|
||||||
return Err(Error::MismatchedRegistryKey);
|
return Err(Error::MismatchedRegistryKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let value = unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 2);
|
check_stack(self.state, 1)?;
|
||||||
|
|
||||||
ffi::lua_rawgeti(
|
ffi::lua_rawgeti(
|
||||||
self.state,
|
self.state,
|
||||||
|
@ -1278,14 +1297,13 @@ impl Lua {
|
||||||
/// [`create_registry_value`]: #method.create_registry_value
|
/// [`create_registry_value`]: #method.create_registry_value
|
||||||
/// [`expire_registry_values`]: #method.expire_registry_values
|
/// [`expire_registry_values`]: #method.expire_registry_values
|
||||||
pub fn remove_registry_value(&self, key: RegistryKey) -> Result<()> {
|
pub fn remove_registry_value(&self, key: RegistryKey) -> Result<()> {
|
||||||
unsafe {
|
|
||||||
if !self.owns_registry_value(&key) {
|
if !self.owns_registry_value(&key) {
|
||||||
return Err(Error::MismatchedRegistryKey);
|
return Err(Error::MismatchedRegistryKey);
|
||||||
}
|
}
|
||||||
|
unsafe {
|
||||||
ffi::luaL_unref(self.state, ffi::LUA_REGISTRYINDEX, key.take());
|
ffi::luaL_unref(self.state, ffi::LUA_REGISTRYINDEX, key.take());
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the given `RegistryKey` was created by a `Lua` which shares the underlying
|
/// Returns true if the given `RegistryKey` was created by a `Lua` which shares the underlying
|
||||||
|
@ -1477,17 +1495,18 @@ impl Lua {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn userdata_metatable<T: 'static + UserData>(&self) -> Result<c_int> {
|
pub(crate) unsafe fn push_userdata_metatable<T: 'static + UserData>(&self) -> Result<()> {
|
||||||
let type_id = TypeId::of::<T>();
|
let type_id = TypeId::of::<T>();
|
||||||
if let Some(table_id) = mlua_expect!(self.extra.lock(), "extra is poisoned")
|
if let Some(&table_id) = mlua_expect!(self.extra.lock(), "extra is poisoned")
|
||||||
.registered_userdata
|
.registered_userdata
|
||||||
.get(&type_id)
|
.get(&type_id)
|
||||||
{
|
{
|
||||||
return Ok(*table_id);
|
ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, table_id as Integer);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new_extra(self.state, 1);
|
||||||
assert_stack(self.state, 10);
|
check_stack(self.state, 13)?;
|
||||||
|
|
||||||
let mut fields = StaticUserDataFields::default();
|
let mut fields = StaticUserDataFields::default();
|
||||||
let mut methods = StaticUserDataMethods::default();
|
let mut methods = StaticUserDataMethods::default();
|
||||||
|
@ -1565,13 +1584,14 @@ impl Lua {
|
||||||
ffi::lua_pop(self.state, extra_tables_count);
|
ffi::lua_pop(self.state, extra_tables_count);
|
||||||
|
|
||||||
let ptr = ffi::lua_topointer(self.state, -1);
|
let ptr = ffi::lua_topointer(self.state, -1);
|
||||||
|
ffi::lua_pushvalue(self.state, -1);
|
||||||
let id = ffi::safe::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX)?;
|
let id = ffi::safe::luaL_ref(self.state, ffi::LUA_REGISTRYINDEX)?;
|
||||||
|
|
||||||
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
let mut extra = mlua_expect!(self.extra.lock(), "extra is poisoned");
|
||||||
extra.registered_userdata.insert(type_id, id);
|
extra.registered_userdata.insert(type_id, id);
|
||||||
extra.registered_userdata_mt.insert(ptr as isize);
|
extra.registered_userdata_mt.insert(ptr as isize);
|
||||||
|
|
||||||
Ok(id)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn register_userdata_metatable(&self, id: isize) {
|
pub(crate) fn register_userdata_metatable(&self, id: isize) {
|
||||||
|
@ -1586,7 +1606,7 @@ impl Lua {
|
||||||
|
|
||||||
// Pushes a LuaRef value onto the stack, checking that it's a registered
|
// Pushes a LuaRef value onto the stack, checking that it's a registered
|
||||||
// and not destructed UserData.
|
// and not destructed UserData.
|
||||||
// Uses 3 stack spaces, does not call checkstack
|
// Uses 3 stack spaces, does not call checkstack.
|
||||||
pub(crate) unsafe fn push_userdata_ref(&self, lref: &LuaRef) -> Result<()> {
|
pub(crate) unsafe fn push_userdata_ref(&self, lref: &LuaRef) -> Result<()> {
|
||||||
self.push_ref(lref);
|
self.push_ref(lref);
|
||||||
if ffi::lua_getmetatable(self.state, -1) == 0 {
|
if ffi::lua_getmetatable(self.state, -1) == 0 {
|
||||||
|
@ -1663,7 +1683,7 @@ impl Lua {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 6);
|
check_stack(self.state, 5)?;
|
||||||
|
|
||||||
push_gc_userdata::<Callback>(self.state, mem::transmute(func))?;
|
push_gc_userdata::<Callback>(self.state, mem::transmute(func))?;
|
||||||
push_gc_userdata(self.state, self.clone())?;
|
push_gc_userdata(self.state, self.clone())?;
|
||||||
|
@ -1744,8 +1764,8 @@ impl Lua {
|
||||||
let mut waker = noop_waker();
|
let mut waker = noop_waker();
|
||||||
|
|
||||||
// Try to get an outer poll waker
|
// Try to get an outer poll waker
|
||||||
ffi::lua_pushlightuserdata(state, &WAKER_REGISTRY_KEY as *const u8 as *mut c_void);
|
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
||||||
ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, waker_key);
|
||||||
if let Some(w) = get_gc_userdata::<Waker>(state, -1).as_ref() {
|
if let Some(w) = get_gc_userdata::<Waker>(state, -1).as_ref() {
|
||||||
waker = (*w).clone();
|
waker = (*w).clone();
|
||||||
}
|
}
|
||||||
|
@ -1775,7 +1795,7 @@ impl Lua {
|
||||||
|
|
||||||
let get_poll = unsafe {
|
let get_poll = unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 6);
|
check_stack(self.state, 5)?;
|
||||||
|
|
||||||
push_gc_userdata::<AsyncCallback>(self.state, mem::transmute(func))?;
|
push_gc_userdata::<AsyncCallback>(self.state, mem::transmute(func))?;
|
||||||
push_gc_userdata(self.state, self.clone())?;
|
push_gc_userdata(self.state, self.clone())?;
|
||||||
|
@ -1786,7 +1806,7 @@ impl Lua {
|
||||||
|
|
||||||
let coroutine = self.globals().get::<_, Table>("coroutine")?;
|
let coroutine = self.globals().get::<_, Table>("coroutine")?;
|
||||||
|
|
||||||
let env = self.create_table()?;
|
let env = self.create_table_with_capacity(0, 4)?;
|
||||||
env.set("get_poll", get_poll)?;
|
env.set("get_poll", get_poll)?;
|
||||||
env.set("yield", coroutine.get::<_, Function>("yield")?)?;
|
env.set("yield", coroutine.get::<_, Function>("yield")?)?;
|
||||||
env.set(
|
env.set(
|
||||||
|
@ -1800,7 +1820,7 @@ impl Lua {
|
||||||
)?;
|
)?;
|
||||||
env.set("pending", unsafe {
|
env.set("pending", unsafe {
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
check_stack(self.state, 5)?;
|
check_stack(self.state, 3)?;
|
||||||
push_gc_userdata(self.state, AsyncPollPending)?;
|
push_gc_userdata(self.state, AsyncPollPending)?;
|
||||||
self.pop_value()
|
self.pop_value()
|
||||||
})?;
|
})?;
|
||||||
|
@ -1829,12 +1849,10 @@ impl Lua {
|
||||||
T: 'static + UserData,
|
T: 'static + UserData,
|
||||||
{
|
{
|
||||||
let _sg = StackGuard::new(self.state);
|
let _sg = StackGuard::new(self.state);
|
||||||
assert_stack(self.state, 4);
|
check_stack(self.state, 2)?;
|
||||||
|
|
||||||
let ud_index = self.userdata_metatable::<T>()?;
|
|
||||||
push_userdata(self.state, data)?;
|
push_userdata(self.state, data)?;
|
||||||
|
self.push_userdata_metatable::<T>()?;
|
||||||
ffi::lua_rawgeti(self.state, ffi::LUA_REGISTRYINDEX, ud_index as Integer);
|
|
||||||
ffi::lua_setmetatable(self.state, -2);
|
ffi::lua_setmetatable(self.state, -2);
|
||||||
|
|
||||||
Ok(AnyUserData(self.pop_ref()))
|
Ok(AnyUserData(self.pop_ref()))
|
||||||
|
@ -1879,13 +1897,10 @@ impl Lua {
|
||||||
|
|
||||||
pub(crate) unsafe fn make_from_ptr(state: *mut ffi::lua_State) -> Self {
|
pub(crate) unsafe fn make_from_ptr(state: *mut ffi::lua_State) -> Self {
|
||||||
let _sg = StackGuard::new(state);
|
let _sg = StackGuard::new(state);
|
||||||
assert_stack(state, 3);
|
assert_stack(state, 1);
|
||||||
|
|
||||||
ffi::lua_rawgetp(
|
let extra_key = &EXTRA_REGISTRY_KEY as *const u8 as *const c_void;
|
||||||
state,
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, extra_key);
|
||||||
ffi::LUA_REGISTRYINDEX,
|
|
||||||
&EXTRA_REGISTRY_KEY as *const u8 as *mut c_void,
|
|
||||||
);
|
|
||||||
let extra = mlua_expect!(
|
let extra = mlua_expect!(
|
||||||
(*get_gc_userdata::<Weak<Mutex<ExtraData>>>(state, -1)).upgrade(),
|
(*get_gc_userdata::<Weak<Mutex<ExtraData>>>(state, -1)).upgrade(),
|
||||||
"extra is destroyed"
|
"extra is destroyed"
|
||||||
|
@ -1929,7 +1944,7 @@ pub enum ChunkMode {
|
||||||
|
|
||||||
impl<'lua, 'a> Chunk<'lua, 'a> {
|
impl<'lua, 'a> Chunk<'lua, 'a> {
|
||||||
/// Sets the name of this chunk, which results in more informative error traces.
|
/// Sets the name of this chunk, which results in more informative error traces.
|
||||||
pub fn set_name<S: ?Sized + AsRef<[u8]>>(mut self, name: &S) -> Result<Chunk<'lua, 'a>> {
|
pub fn set_name<S: AsRef<[u8]> + ?Sized>(mut self, name: &S) -> Result<Chunk<'lua, 'a>> {
|
||||||
let name =
|
let name =
|
||||||
CString::new(name.as_ref().to_vec()).map_err(|e| Error::ToLuaConversionError {
|
CString::new(name.as_ref().to_vec()).map_err(|e| Error::ToLuaConversionError {
|
||||||
from: "&str",
|
from: "&str",
|
||||||
|
|
13
src/scope.rs
13
src/scope.rs
|
@ -16,7 +16,8 @@ use crate::userdata::{
|
||||||
AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
|
AnyUserData, MetaMethod, UserData, UserDataCell, UserDataFields, UserDataMethods,
|
||||||
};
|
};
|
||||||
use crate::util::{
|
use crate::util::{
|
||||||
assert_stack, get_userdata, init_userdata_metatable, push_userdata, take_userdata, StackGuard,
|
assert_stack, check_stack, get_userdata, init_userdata_metatable, push_userdata, take_userdata,
|
||||||
|
StackGuard,
|
||||||
};
|
};
|
||||||
use crate::value::{FromLua, FromLuaMulti, MultiValue, ToLua, ToLuaMulti, Value};
|
use crate::value::{FromLua, FromLuaMulti, MultiValue, ToLua, ToLuaMulti, Value};
|
||||||
|
|
||||||
|
@ -188,6 +189,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||||
let state = ud.lua.state;
|
let state = ud.lua.state;
|
||||||
let _sg = StackGuard::new(state);
|
let _sg = StackGuard::new(state);
|
||||||
assert_stack(state, 2);
|
assert_stack(state, 2);
|
||||||
|
|
||||||
ud.lua.push_ref(&ud);
|
ud.lua.push_ref(&ud);
|
||||||
|
|
||||||
// We know the destructor has not run yet because we hold a reference to the userdata.
|
// We know the destructor has not run yet because we hold a reference to the userdata.
|
||||||
|
@ -260,7 +262,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||||
if let Some(Value::UserData(ud)) = value {
|
if let Some(Value::UserData(ud)) = value {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 3);
|
check_stack(lua.state, 3)?;
|
||||||
lua.push_userdata_ref(&ud.0)?;
|
lua.push_userdata_ref(&ud.0)?;
|
||||||
if get_userdata(lua.state, -1) == data_ptr {
|
if get_userdata(lua.state, -1) == data_ptr {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -320,7 +322,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let lua = self.lua;
|
let lua = self.lua;
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 13);
|
check_stack(lua.state, 13)?;
|
||||||
|
|
||||||
push_userdata(lua.state, data.clone())?;
|
push_userdata(lua.state, data.clone())?;
|
||||||
let data_ptr = ffi::lua_touserdata(lua.state, -1);
|
let data_ptr = ffi::lua_touserdata(lua.state, -1);
|
||||||
|
@ -401,6 +403,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||||
let state = ud.lua.state;
|
let state = ud.lua.state;
|
||||||
let _sg = StackGuard::new(state);
|
let _sg = StackGuard::new(state);
|
||||||
assert_stack(state, 2);
|
assert_stack(state, 2);
|
||||||
|
|
||||||
ud.lua.push_ref(&ud);
|
ud.lua.push_ref(&ud);
|
||||||
|
|
||||||
// We know the destructor has not run yet because we hold a reference to the userdata.
|
// We know the destructor has not run yet because we hold a reference to the userdata.
|
||||||
|
@ -450,6 +453,7 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||||
let state = f.lua.state;
|
let state = f.lua.state;
|
||||||
let _sg = StackGuard::new(state);
|
let _sg = StackGuard::new(state);
|
||||||
assert_stack(state, 3);
|
assert_stack(state, 3);
|
||||||
|
|
||||||
f.lua.push_ref(&f);
|
f.lua.push_ref(&f);
|
||||||
|
|
||||||
// We know the destructor has not run yet because we hold a reference to the callback.
|
// We know the destructor has not run yet because we hold a reference to the callback.
|
||||||
|
@ -487,7 +491,8 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||||
let destructor: DestructorCallback = Box::new(move |f| {
|
let destructor: DestructorCallback = Box::new(move |f| {
|
||||||
let state = f.lua.state;
|
let state = f.lua.state;
|
||||||
let _sg = StackGuard::new(state);
|
let _sg = StackGuard::new(state);
|
||||||
assert_stack(state, 4);
|
assert_stack(state, 5);
|
||||||
|
|
||||||
f.lua.push_ref(&f);
|
f.lua.push_ref(&f);
|
||||||
|
|
||||||
// We know the destructor has not run yet because we hold a reference to the callback.
|
// We know the destructor has not run yet because we hold a reference to the callback.
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::ffi;
|
||||||
use crate::lua::Lua;
|
use crate::lua::Lua;
|
||||||
use crate::table::Table;
|
use crate::table::Table;
|
||||||
use crate::types::LightUserData;
|
use crate::types::LightUserData;
|
||||||
use crate::util::{assert_stack, StackGuard};
|
use crate::util::{assert_stack, check_stack, StackGuard};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
/// Trait for serializing/deserializing Lua values using Serde.
|
/// Trait for serializing/deserializing Lua values using Serde.
|
||||||
|
@ -200,22 +200,22 @@ impl<'lua> LuaSerdeExt<'lua> for Lua {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Uses 6 stack spaces and calls checkstack.
|
||||||
pub(crate) unsafe fn init_metatables(state: *mut ffi::lua_State) -> Result<()> {
|
pub(crate) unsafe fn init_metatables(state: *mut ffi::lua_State) -> Result<()> {
|
||||||
ffi::lua_pushlightuserdata(
|
check_stack(state, 6)?;
|
||||||
state,
|
|
||||||
&ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void,
|
|
||||||
);
|
|
||||||
ffi::safe::lua_createtable(state, 0, 1)?;
|
ffi::safe::lua_createtable(state, 0, 1)?;
|
||||||
|
|
||||||
ffi::lua_pushboolean(state, 0);
|
ffi::lua_pushboolean(state, 0);
|
||||||
ffi::safe::lua_rawsetfield(state, -2, "__metatable")?;
|
ffi::safe::lua_rawsetfield(state, -2, "__metatable")?;
|
||||||
|
|
||||||
ffi::safe::lua_rawset(state, ffi::LUA_REGISTRYINDEX)
|
let array_metatable_key = &ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *const c_void;
|
||||||
|
ffi::safe::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, array_metatable_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn push_array_metatable(state: *mut ffi::lua_State) {
|
pub(crate) unsafe fn push_array_metatable(state: *mut ffi::lua_State) {
|
||||||
let key = &ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void;
|
let array_metatable_key = &ARRAY_METATABLE_REGISTRY_KEY as *const u8 as *mut c_void;
|
||||||
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key);
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, array_metatable_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ARRAY_METATABLE_REGISTRY_KEY: u8 = 0;
|
static ARRAY_METATABLE_REGISTRY_KEY: u8 = 0;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::lua::Lua;
|
||||||
use crate::string::String;
|
use crate::string::String;
|
||||||
use crate::table::Table;
|
use crate::table::Table;
|
||||||
use crate::types::Integer;
|
use crate::types::Integer;
|
||||||
use crate::util::{assert_stack, StackGuard};
|
use crate::util::{check_stack, StackGuard};
|
||||||
use crate::value::{ToLua, Value};
|
use crate::value::{ToLua, Value};
|
||||||
|
|
||||||
/// A struct for serializing Rust values into Lua values.
|
/// A struct for serializing Rust values into Lua values.
|
||||||
|
@ -137,7 +137,7 @@ impl<'lua> ser::Serializer for Serializer<'lua> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize_some<T>(self, value: &T) -> Result<Value<'lua>>
|
fn serialize_some<T>(self, value: &T) -> Result<Value<'lua>>
|
||||||
where
|
where
|
||||||
T: ?Sized + Serialize,
|
T: Serialize + ?Sized,
|
||||||
{
|
{
|
||||||
value.serialize(self)
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ impl<'lua> ser::Serializer for Serializer<'lua> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<Value<'lua>>
|
fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<Value<'lua>>
|
||||||
where
|
where
|
||||||
T: ?Sized + Serialize,
|
T: Serialize + ?Sized,
|
||||||
{
|
{
|
||||||
value.serialize(self)
|
value.serialize(self)
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ impl<'lua> ser::Serializer for Serializer<'lua> {
|
||||||
value: &T,
|
value: &T,
|
||||||
) -> Result<Value<'lua>>
|
) -> Result<Value<'lua>>
|
||||||
where
|
where
|
||||||
T: ?Sized + Serialize,
|
T: Serialize + ?Sized,
|
||||||
{
|
{
|
||||||
let table = self.lua.create_table()?;
|
let table = self.lua.create_table()?;
|
||||||
let variant = self.lua.create_string(variant)?;
|
let variant = self.lua.create_string(variant)?;
|
||||||
|
@ -279,13 +279,13 @@ impl<'lua> ser::SerializeSeq for SerializeVec<'lua> {
|
||||||
|
|
||||||
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
|
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
|
||||||
where
|
where
|
||||||
T: ?Sized + Serialize,
|
T: Serialize + ?Sized,
|
||||||
{
|
{
|
||||||
let lua = self.table.0.lua;
|
let lua = self.table.0.lua;
|
||||||
let value = lua.to_value_with(value, self.options)?;
|
let value = lua.to_value_with(value, self.options)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 5);
|
check_stack(lua.state, 6)?;
|
||||||
|
|
||||||
lua.push_ref(&self.table.0);
|
lua.push_ref(&self.table.0);
|
||||||
lua.push_value(value)?;
|
lua.push_value(value)?;
|
||||||
|
@ -305,7 +305,7 @@ impl<'lua> ser::SerializeTuple for SerializeVec<'lua> {
|
||||||
|
|
||||||
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
|
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
|
||||||
where
|
where
|
||||||
T: ?Sized + Serialize,
|
T: Serialize + ?Sized,
|
||||||
{
|
{
|
||||||
ser::SerializeSeq::serialize_element(self, value)
|
ser::SerializeSeq::serialize_element(self, value)
|
||||||
}
|
}
|
||||||
|
@ -321,7 +321,7 @@ impl<'lua> ser::SerializeTupleStruct for SerializeVec<'lua> {
|
||||||
|
|
||||||
fn serialize_field<T>(&mut self, value: &T) -> Result<()>
|
fn serialize_field<T>(&mut self, value: &T) -> Result<()>
|
||||||
where
|
where
|
||||||
T: ?Sized + Serialize,
|
T: Serialize + ?Sized,
|
||||||
{
|
{
|
||||||
ser::SerializeSeq::serialize_element(self, value)
|
ser::SerializeSeq::serialize_element(self, value)
|
||||||
}
|
}
|
||||||
|
@ -344,7 +344,7 @@ impl<'lua> ser::SerializeTupleVariant for SerializeTupleVariant<'lua> {
|
||||||
|
|
||||||
fn serialize_field<T>(&mut self, value: &T) -> Result<()>
|
fn serialize_field<T>(&mut self, value: &T) -> Result<()>
|
||||||
where
|
where
|
||||||
T: ?Sized + Serialize,
|
T: Serialize + ?Sized,
|
||||||
{
|
{
|
||||||
let lua = self.table.0.lua;
|
let lua = self.table.0.lua;
|
||||||
let idx = self.table.raw_len() + 1;
|
let idx = self.table.raw_len() + 1;
|
||||||
|
@ -373,7 +373,7 @@ impl<'lua> ser::SerializeMap for SerializeMap<'lua> {
|
||||||
|
|
||||||
fn serialize_key<T>(&mut self, key: &T) -> Result<()>
|
fn serialize_key<T>(&mut self, key: &T) -> Result<()>
|
||||||
where
|
where
|
||||||
T: ?Sized + Serialize,
|
T: Serialize + ?Sized,
|
||||||
{
|
{
|
||||||
let lua = self.table.0.lua;
|
let lua = self.table.0.lua;
|
||||||
self.key = Some(lua.to_value_with(key, self.options)?);
|
self.key = Some(lua.to_value_with(key, self.options)?);
|
||||||
|
@ -382,7 +382,7 @@ impl<'lua> ser::SerializeMap for SerializeMap<'lua> {
|
||||||
|
|
||||||
fn serialize_value<T>(&mut self, value: &T) -> Result<()>
|
fn serialize_value<T>(&mut self, value: &T) -> Result<()>
|
||||||
where
|
where
|
||||||
T: ?Sized + Serialize,
|
T: Serialize + ?Sized,
|
||||||
{
|
{
|
||||||
let lua = self.table.0.lua;
|
let lua = self.table.0.lua;
|
||||||
let key = mlua_expect!(
|
let key = mlua_expect!(
|
||||||
|
@ -404,7 +404,7 @@ impl<'lua> ser::SerializeStruct for SerializeMap<'lua> {
|
||||||
|
|
||||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
|
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
|
||||||
where
|
where
|
||||||
T: ?Sized + Serialize,
|
T: Serialize + ?Sized,
|
||||||
{
|
{
|
||||||
ser::SerializeMap::serialize_key(self, key)?;
|
ser::SerializeMap::serialize_key(self, key)?;
|
||||||
ser::SerializeMap::serialize_value(self, value)
|
ser::SerializeMap::serialize_value(self, value)
|
||||||
|
@ -428,7 +428,7 @@ impl<'lua> ser::SerializeStructVariant for SerializeStructVariant<'lua> {
|
||||||
|
|
||||||
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
|
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
|
||||||
where
|
where
|
||||||
T: ?Sized + Serialize,
|
T: Serialize + ?Sized,
|
||||||
{
|
{
|
||||||
let lua = self.table.0.lua;
|
let lua = self.table.0.lua;
|
||||||
self.table
|
self.table
|
||||||
|
|
|
@ -39,17 +39,17 @@ impl StdLib {
|
||||||
#[cfg(any(feature = "luajit", doc))]
|
#[cfg(any(feature = "luajit", doc))]
|
||||||
pub const JIT: StdLib = StdLib(1 << 9);
|
pub const JIT: StdLib = StdLib(1 << 9);
|
||||||
|
|
||||||
/// (unsafe) [`ffi`](http://luajit.org/ext_ffi.html) library
|
/// (**unsafe**) [`ffi`](http://luajit.org/ext_ffi.html) library
|
||||||
///
|
///
|
||||||
/// Requires `feature = "luajit"`
|
/// Requires `feature = "luajit"`
|
||||||
#[cfg(any(feature = "luajit", doc))]
|
#[cfg(any(feature = "luajit", doc))]
|
||||||
pub const FFI: StdLib = StdLib(1 << 30);
|
pub const FFI: StdLib = StdLib(1 << 30);
|
||||||
/// (unsafe) [`debug`](https://www.lua.org/manual/5.3/manual.html#6.10) library
|
/// (**unsafe**) [`debug`](https://www.lua.org/manual/5.3/manual.html#6.10) library
|
||||||
pub const DEBUG: StdLib = StdLib(1 << 31);
|
pub const DEBUG: StdLib = StdLib(1 << 31);
|
||||||
|
|
||||||
/// No libraries
|
/// No libraries
|
||||||
pub const NONE: StdLib = StdLib(0);
|
pub const NONE: StdLib = StdLib(0);
|
||||||
/// (unsafe) All standard libraries
|
/// (**unsafe**) All standard libraries
|
||||||
pub const ALL: StdLib = StdLib(u32::MAX);
|
pub const ALL: StdLib = StdLib(u32::MAX);
|
||||||
/// The safe subset of the standard libraries
|
/// The safe subset of the standard libraries
|
||||||
pub const ALL_SAFE: StdLib = StdLib((1 << 30) - 1);
|
pub const ALL_SAFE: StdLib = StdLib((1 << 30) - 1);
|
||||||
|
|
84
src/table.rs
84
src/table.rs
|
@ -10,7 +10,7 @@ use crate::error::{Error, Result};
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
use crate::function::Function;
|
use crate::function::Function;
|
||||||
use crate::types::{Integer, LuaRef};
|
use crate::types::{Integer, LuaRef};
|
||||||
use crate::util::{assert_stack, StackGuard};
|
use crate::util::{assert_stack, check_stack, StackGuard};
|
||||||
use crate::value::{FromLua, FromLuaMulti, Nil, ToLua, ToLuaMulti, Value};
|
use crate::value::{FromLua, FromLuaMulti, Nil, ToLua, ToLuaMulti, Value};
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
|
@ -62,7 +62,7 @@ impl<'lua> Table<'lua> {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 5);
|
check_stack(lua.state, 6)?;
|
||||||
|
|
||||||
lua.push_ref(&self.0);
|
lua.push_ref(&self.0);
|
||||||
lua.push_value(key)?;
|
lua.push_value(key)?;
|
||||||
|
@ -101,7 +101,7 @@ impl<'lua> Table<'lua> {
|
||||||
|
|
||||||
let value = unsafe {
|
let value = unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 4);
|
check_stack(lua.state, 5)?;
|
||||||
|
|
||||||
lua.push_ref(&self.0);
|
lua.push_ref(&self.0);
|
||||||
lua.push_value(key)?;
|
lua.push_value(key)?;
|
||||||
|
@ -119,7 +119,7 @@ impl<'lua> Table<'lua> {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 4);
|
check_stack(lua.state, 5)?;
|
||||||
|
|
||||||
lua.push_ref(&self.0);
|
lua.push_ref(&self.0);
|
||||||
lua.push_value(key)?;
|
lua.push_value(key)?;
|
||||||
|
@ -193,7 +193,7 @@ impl<'lua> Table<'lua> {
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 5);
|
check_stack(lua.state, 6)?;
|
||||||
|
|
||||||
lua.push_ref(&self.0);
|
lua.push_ref(&self.0);
|
||||||
lua.push_value(key)?;
|
lua.push_value(key)?;
|
||||||
|
@ -209,7 +209,7 @@ impl<'lua> Table<'lua> {
|
||||||
|
|
||||||
let value = unsafe {
|
let value = unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 2);
|
check_stack(lua.state, 3)?;
|
||||||
|
|
||||||
lua.push_ref(&self.0);
|
lua.push_ref(&self.0);
|
||||||
lua.push_value(key)?;
|
lua.push_value(key)?;
|
||||||
|
@ -232,7 +232,7 @@ impl<'lua> Table<'lua> {
|
||||||
let value = value.to_lua(lua)?;
|
let value = value.to_lua(lua)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 5);
|
check_stack(lua.state, 6)?;
|
||||||
|
|
||||||
lua.push_ref(&self.0);
|
lua.push_ref(&self.0);
|
||||||
lua.push_value(value)?;
|
lua.push_value(value)?;
|
||||||
|
@ -258,7 +258,7 @@ impl<'lua> Table<'lua> {
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 4);
|
check_stack(lua.state, 5)?;
|
||||||
|
|
||||||
lua.push_ref(&self.0);
|
lua.push_ref(&self.0);
|
||||||
ffi::safe::lua_rawremove(lua.state, -1, idx)
|
ffi::safe::lua_rawremove(lua.state, -1, idx)
|
||||||
|
@ -277,7 +277,7 @@ impl<'lua> Table<'lua> {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 4);
|
check_stack(lua.state, 4)?;
|
||||||
|
|
||||||
lua.push_ref(&self.0);
|
lua.push_ref(&self.0);
|
||||||
ffi::safe::luaL_len(lua.state, -1)
|
ffi::safe::luaL_len(lua.state, -1)
|
||||||
|
@ -370,7 +370,7 @@ impl<'lua> Table<'lua> {
|
||||||
pub fn pairs<K: FromLua<'lua>, V: FromLua<'lua>>(self) -> TablePairs<'lua, K, V> {
|
pub fn pairs<K: FromLua<'lua>, V: FromLua<'lua>>(self) -> TablePairs<'lua, K, V> {
|
||||||
TablePairs {
|
TablePairs {
|
||||||
table: self.0,
|
table: self.0,
|
||||||
next_key: Some(Nil),
|
key: Some(Nil),
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -635,7 +635,7 @@ impl<'lua> Serialize for Table<'lua> {
|
||||||
/// [`Table::pairs`]: struct.Table.html#method.pairs
|
/// [`Table::pairs`]: struct.Table.html#method.pairs
|
||||||
pub struct TablePairs<'lua, K, V> {
|
pub struct TablePairs<'lua, K, V> {
|
||||||
table: LuaRef<'lua>,
|
table: LuaRef<'lua>,
|
||||||
next_key: Option<Value<'lua>>,
|
key: Option<Value<'lua>>,
|
||||||
_phantom: PhantomData<(K, V)>,
|
_phantom: PhantomData<(K, V)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,38 +647,34 @@ where
|
||||||
type Item = Result<(K, V)>;
|
type Item = Result<(K, V)>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if let Some(next_key) = self.next_key.take() {
|
if let Some(prev_key) = self.key.take() {
|
||||||
let lua = self.table.lua;
|
let lua = self.table.lua;
|
||||||
|
|
||||||
let res = (|| {
|
let res = (|| unsafe {
|
||||||
let res = unsafe {
|
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 4);
|
check_stack(lua.state, 5)?;
|
||||||
|
|
||||||
lua.push_ref(&self.table);
|
lua.push_ref(&self.table);
|
||||||
lua.push_value(next_key)?;
|
lua.push_value(prev_key)?;
|
||||||
|
|
||||||
if ffi::safe::lua_next(lua.state, -2)? != 0 {
|
if ffi::safe::lua_next(lua.state, -2)? != 0 {
|
||||||
ffi::lua_pushvalue(lua.state, -2);
|
|
||||||
let key = lua.pop_value();
|
|
||||||
let value = lua.pop_value();
|
let value = lua.pop_value();
|
||||||
self.next_key = Some(lua.pop_value());
|
let key = lua.pop_value();
|
||||||
|
Ok(Some((
|
||||||
Some((key, value))
|
key.clone(),
|
||||||
|
K::from_lua(key, lua)?,
|
||||||
|
V::from_lua(value, lua)?,
|
||||||
|
)))
|
||||||
} else {
|
} else {
|
||||||
None
|
Ok(None)
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
Ok(if let Some((key, value)) = res {
|
|
||||||
Some((K::from_lua(key, lua)?, V::from_lua(value, lua)?))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
})
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok(Some((key, value))) => Some(Ok((key, value))),
|
Ok(Some((key, ret_key, value))) => {
|
||||||
|
self.key = Some(key);
|
||||||
|
Some(Ok((ret_key, value)))
|
||||||
|
}
|
||||||
Ok(None) => None,
|
Ok(None) => None,
|
||||||
Err(e) => Some(Err(e)),
|
Err(e) => Some(Err(e)),
|
||||||
}
|
}
|
||||||
|
@ -711,31 +707,29 @@ where
|
||||||
if let Some(index) = self.index.take() {
|
if let Some(index) = self.index.take() {
|
||||||
let lua = self.table.lua;
|
let lua = self.table.lua;
|
||||||
|
|
||||||
let res = unsafe {
|
let res = (|| unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 4);
|
check_stack(lua.state, 1 + if self.raw { 0 } else { 4 })?;
|
||||||
|
|
||||||
lua.push_ref(&self.table);
|
lua.push_ref(&self.table);
|
||||||
let res = if self.raw {
|
let res = if self.raw {
|
||||||
Ok(ffi::lua_rawgeti(lua.state, -1, index))
|
ffi::lua_rawgeti(lua.state, -1, index)
|
||||||
} else {
|
} else {
|
||||||
ffi::safe::lua_geti(lua.state, -1, index)
|
ffi::safe::lua_geti(lua.state, -1, index)?
|
||||||
};
|
};
|
||||||
match res {
|
match res {
|
||||||
Ok(ffi::LUA_TNIL) if index > self.len.unwrap_or(0) => None,
|
ffi::LUA_TNIL if index > self.len.unwrap_or(0) => Ok(None),
|
||||||
Ok(_) => {
|
_ => Ok(Some((index, lua.pop_value()))),
|
||||||
let value = lua.pop_value();
|
|
||||||
self.index = Some(index + 1);
|
|
||||||
Some(Ok(value))
|
|
||||||
}
|
}
|
||||||
Err(err) => Some(Err(err)),
|
})();
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Some(Ok(r)) => Some(V::from_lua(r, lua)),
|
Ok(Some((index, r))) => {
|
||||||
Some(Err(err)) => Some(Err(err)),
|
self.index = Some(index + 1);
|
||||||
None => None,
|
Some(V::from_lua(r, lua))
|
||||||
|
}
|
||||||
|
Ok(None) => None,
|
||||||
|
Err(err) => Some(Err(err)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::cmp;
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
|
@ -107,9 +108,10 @@ impl<'lua> Thread<'lua> {
|
||||||
{
|
{
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
let args = args.to_lua_multi(lua)?;
|
let args = args.to_lua_multi(lua)?;
|
||||||
|
let nargs = args.len() as c_int;
|
||||||
let results = unsafe {
|
let results = unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 2);
|
check_stack(lua.state, cmp::min(nargs + 1, 3))?;
|
||||||
|
|
||||||
lua.push_ref(&self.0);
|
lua.push_ref(&self.0);
|
||||||
let thread_state = ffi::lua_tothread(lua.state, -1);
|
let thread_state = ffi::lua_tothread(lua.state, -1);
|
||||||
|
@ -120,10 +122,7 @@ impl<'lua> Thread<'lua> {
|
||||||
return Err(Error::CoroutineInactive);
|
return Err(Error::CoroutineInactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
let nargs = args.len() as c_int;
|
check_stack(thread_state, nargs)?;
|
||||||
check_stack(lua.state, nargs)?;
|
|
||||||
check_stack(thread_state, nargs + 1)?;
|
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
lua.push_value(arg)?;
|
lua.push_value(arg)?;
|
||||||
}
|
}
|
||||||
|
@ -138,10 +137,9 @@ impl<'lua> Thread<'lua> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut results = MultiValue::new();
|
let mut results = MultiValue::new();
|
||||||
check_stack(lua.state, nresults)?;
|
check_stack(lua.state, nresults + 2)?; // 2 is extra for `lua.pop_value()` below
|
||||||
ffi::lua_xmove(thread_state, lua.state, nresults);
|
ffi::lua_xmove(thread_state, lua.state, nresults);
|
||||||
|
|
||||||
assert_stack(lua.state, 2);
|
|
||||||
for _ in 0..nresults {
|
for _ in 0..nresults {
|
||||||
results.push_front(lua.pop_value());
|
results.push_front(lua.pop_value());
|
||||||
}
|
}
|
||||||
|
@ -314,9 +312,7 @@ fn is_poll_pending(lua: &Lua, val: &MultiValue) -> bool {
|
||||||
assert_stack(lua.state, 3);
|
assert_stack(lua.state, 3);
|
||||||
|
|
||||||
lua.push_ref(&ud.0);
|
lua.push_ref(&ud.0);
|
||||||
let is_pending = get_gc_userdata::<AsyncPollPending>(lua.state, -1)
|
let is_pending = !get_gc_userdata::<AsyncPollPending>(lua.state, -1).is_null();
|
||||||
.as_ref()
|
|
||||||
.is_some();
|
|
||||||
ffi::lua_pop(lua.state, 1);
|
ffi::lua_pop(lua.state, 1);
|
||||||
|
|
||||||
return is_pending;
|
return is_pending;
|
||||||
|
@ -334,11 +330,11 @@ impl WakerGuard {
|
||||||
pub fn new(state: *mut ffi::lua_State, waker: Waker) -> Result<WakerGuard> {
|
pub fn new(state: *mut ffi::lua_State, waker: Waker) -> Result<WakerGuard> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(state);
|
let _sg = StackGuard::new(state);
|
||||||
assert_stack(state, 6);
|
check_stack(state, 5)?;
|
||||||
|
|
||||||
ffi::lua_pushlightuserdata(state, &WAKER_REGISTRY_KEY as *const u8 as *mut c_void);
|
|
||||||
push_gc_userdata(state, waker)?;
|
push_gc_userdata(state, waker)?;
|
||||||
ffi::safe::lua_rawset(state, ffi::LUA_REGISTRYINDEX)?;
|
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
||||||
|
ffi::safe::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, waker_key)?;
|
||||||
|
|
||||||
Ok(WakerGuard(state))
|
Ok(WakerGuard(state))
|
||||||
}
|
}
|
||||||
|
@ -348,14 +344,14 @@ impl WakerGuard {
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
impl Drop for WakerGuard {
|
impl Drop for WakerGuard {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
|
||||||
let state = self.0;
|
let state = self.0;
|
||||||
|
unsafe {
|
||||||
let _sg = StackGuard::new(state);
|
let _sg = StackGuard::new(state);
|
||||||
assert_stack(state, 2);
|
assert_stack(state, 1);
|
||||||
|
|
||||||
ffi::lua_pushlightuserdata(state, &WAKER_REGISTRY_KEY as *const u8 as *mut c_void);
|
|
||||||
ffi::lua_pushnil(state);
|
ffi::lua_pushnil(state);
|
||||||
ffi::lua_rawset(state, ffi::LUA_REGISTRYINDEX); // TODO: make safe
|
let waker_key = &WAKER_REGISTRY_KEY as *const u8 as *const c_void;
|
||||||
|
ffi::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, waker_key); // TODO: make safe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,8 @@ use crate::ffi;
|
||||||
use crate::function::Function;
|
use crate::function::Function;
|
||||||
use crate::lua::Lua;
|
use crate::lua::Lua;
|
||||||
use crate::table::{Table, TablePairs};
|
use crate::table::{Table, TablePairs};
|
||||||
use crate::types::{Integer, LuaRef, MaybeSend};
|
use crate::types::{LuaRef, MaybeSend};
|
||||||
use crate::util::{assert_stack, get_destructed_userdata_metatable, get_userdata, StackGuard};
|
use crate::util::{check_stack, get_destructed_userdata_metatable, get_userdata, StackGuard};
|
||||||
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti, Value};
|
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti, Value};
|
||||||
|
|
||||||
/// Kinds of metamethods that can be overridden.
|
/// Kinds of metamethods that can be overridden.
|
||||||
|
@ -112,7 +112,7 @@ pub enum MetaMethod {
|
||||||
Close,
|
Close,
|
||||||
/// A custom metamethod.
|
/// A custom metamethod.
|
||||||
///
|
///
|
||||||
/// Must not be in the protected list: `__gc`, `__metatable`.
|
/// Must not be in the protected list: `__gc`, `__metatable`, `__mlua*`.
|
||||||
Custom(StdString),
|
Custom(StdString),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,6 +546,7 @@ pub trait UserData: Sized {
|
||||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) {}
|
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wraps UserData in a way to always implement `serde::Serialize` trait.
|
||||||
pub(crate) enum UserDataCell<T> {
|
pub(crate) enum UserDataCell<T> {
|
||||||
Arc(Arc<RefCell<UserDataWrapped<T>>>),
|
Arc(Arc<RefCell<UserDataWrapped<T>>>),
|
||||||
Plain(RefCell<UserDataWrapped<T>>),
|
Plain(RefCell<UserDataWrapped<T>>),
|
||||||
|
@ -596,7 +597,7 @@ impl<T> Clone for UserDataCell<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
UserDataCell::Arc(t) => UserDataCell::Arc(t.clone()),
|
UserDataCell::Arc(t) => UserDataCell::Arc(t.clone()),
|
||||||
UserDataCell::Plain(_) => mlua_panic!("cannot clone plain userdata"),
|
UserDataCell::Plain(_) => mlua_panic!("cannot clone non-arc userdata"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -711,8 +712,8 @@ impl<'lua> AnyUserData<'lua> {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
||||||
let v = {
|
let v = {
|
||||||
// Lua 5.2/5.1 allows to store only a table. Then we will wrap the value.
|
// Lua <= 5.2 allows to store only a table. Then we will wrap the value.
|
||||||
let t = lua.create_table()?;
|
let t = lua.create_table_with_capacity(1, 0)?;
|
||||||
t.raw_set(1, v)?;
|
t.raw_set(1, v)?;
|
||||||
Value::Table(t)
|
Value::Table(t)
|
||||||
};
|
};
|
||||||
|
@ -720,10 +721,12 @@ impl<'lua> AnyUserData<'lua> {
|
||||||
let v = v.to_lua(lua)?;
|
let v = v.to_lua(lua)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 3);
|
check_stack(lua.state, 3)?;
|
||||||
|
|
||||||
lua.push_userdata_ref(&self.0)?;
|
lua.push_userdata_ref(&self.0)?;
|
||||||
lua.push_value(v)?;
|
lua.push_value(v)?;
|
||||||
ffi::lua_setuservalue(lua.state, -2);
|
ffi::lua_setuservalue(lua.state, -2);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -737,7 +740,8 @@ impl<'lua> AnyUserData<'lua> {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
let res = unsafe {
|
let res = unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 3);
|
check_stack(lua.state, 3)?;
|
||||||
|
|
||||||
lua.push_userdata_ref(&self.0)?;
|
lua.push_userdata_ref(&self.0)?;
|
||||||
ffi::lua_getuservalue(lua.state, -1);
|
ffi::lua_getuservalue(lua.state, -1);
|
||||||
lua.pop_value()
|
lua.pop_value()
|
||||||
|
@ -792,13 +796,10 @@ impl<'lua> AnyUserData<'lua> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 3);
|
check_stack(lua.state, 3)?;
|
||||||
|
|
||||||
lua.push_userdata_ref(&self.0)?;
|
lua.push_userdata_ref(&self.0)?;
|
||||||
if ffi::lua_getmetatable(lua.state, -1) == 0 {
|
ffi::lua_getmetatable(lua.state, -1); // Checked that non-empty on the previous call
|
||||||
return Err(Error::UserDataTypeMismatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Table(lua.pop_ref()))
|
Ok(Table(lua.pop_ref()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -829,20 +830,16 @@ impl<'lua> AnyUserData<'lua> {
|
||||||
T: 'static + UserData,
|
T: 'static + UserData,
|
||||||
F: FnOnce(&'a UserDataCell<T>) -> Result<R>,
|
F: FnOnce(&'a UserDataCell<T>) -> Result<R>,
|
||||||
{
|
{
|
||||||
unsafe {
|
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 3);
|
check_stack(lua.state, 3)?;
|
||||||
|
|
||||||
lua.push_ref(&self.0);
|
lua.push_ref(&self.0);
|
||||||
if ffi::lua_getmetatable(lua.state, -1) == 0 {
|
if ffi::lua_getmetatable(lua.state, -1) == 0 {
|
||||||
return Err(Error::UserDataTypeMismatch);
|
return Err(Error::UserDataTypeMismatch);
|
||||||
}
|
}
|
||||||
ffi::lua_rawgeti(
|
lua.push_userdata_metatable::<T>()?;
|
||||||
lua.state,
|
|
||||||
ffi::LUA_REGISTRYINDEX,
|
|
||||||
lua.userdata_metatable::<T>()? as Integer,
|
|
||||||
);
|
|
||||||
|
|
||||||
if ffi::lua_rawequal(lua.state, -1, -2) == 0 {
|
if ffi::lua_rawequal(lua.state, -1, -2) == 0 {
|
||||||
// Maybe UserData destructed?
|
// Maybe UserData destructed?
|
||||||
|
@ -956,7 +953,7 @@ impl<'lua> Serialize for AnyUserData<'lua> {
|
||||||
let res = (|| unsafe {
|
let res = (|| unsafe {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
assert_stack(lua.state, 3);
|
check_stack(lua.state, 3)?;
|
||||||
|
|
||||||
lua.push_userdata_ref(&self.0)?;
|
lua.push_userdata_ref(&self.0)?;
|
||||||
let ud = &*get_userdata::<UserDataCell<()>>(lua.state, -1);
|
let ud = &*get_userdata::<UserDataCell<()>>(lua.state, -1);
|
||||||
|
|
107
src/util.rs
107
src/util.rs
|
@ -40,6 +40,7 @@ pub unsafe fn check_stack(state: *mut ffi::lua_State, amount: c_int) -> Result<(
|
||||||
pub struct StackGuard {
|
pub struct StackGuard {
|
||||||
state: *mut ffi::lua_State,
|
state: *mut ffi::lua_State,
|
||||||
top: c_int,
|
top: c_int,
|
||||||
|
extra: c_int,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StackGuard {
|
impl StackGuard {
|
||||||
|
@ -50,6 +51,16 @@ impl StackGuard {
|
||||||
StackGuard {
|
StackGuard {
|
||||||
state,
|
state,
|
||||||
top: ffi::lua_gettop(state),
|
top: ffi::lua_gettop(state),
|
||||||
|
extra: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similar to `new`, but checks and keeps `extra` elements from top of the stack on Drop.
|
||||||
|
pub unsafe fn new_extra(state: *mut ffi::lua_State, extra: c_int) -> StackGuard {
|
||||||
|
StackGuard {
|
||||||
|
state,
|
||||||
|
top: ffi::lua_gettop(state),
|
||||||
|
extra,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,11 +69,14 @@ impl Drop for StackGuard {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let top = ffi::lua_gettop(self.state);
|
let top = ffi::lua_gettop(self.state);
|
||||||
if top < self.top {
|
if top < self.top + self.extra {
|
||||||
mlua_panic!("{} too many stack values popped", self.top - top)
|
mlua_panic!("{} too many stack values popped", self.top - top)
|
||||||
}
|
}
|
||||||
if top > self.top {
|
if top > self.top + self.extra {
|
||||||
ffi::lua_settop(self.state, self.top);
|
if self.extra > 0 {
|
||||||
|
ffi::lua_rotate(self.state, self.top + 1, self.extra);
|
||||||
|
}
|
||||||
|
ffi::lua_settop(self.state, self.top + self.extra);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,7 +161,7 @@ pub unsafe fn pop_error(state: *mut ffi::lua_State, err_code: c_int) -> Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internally uses 3 stack spaces, does not call checkstack
|
// Internally uses 3 stack spaces, does not call checkstack.
|
||||||
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) -> Result<()> {
|
||||||
let ud = ffi::safe::lua_newuserdata(state, mem::size_of::<T>())? as *mut T;
|
let ud = ffi::safe::lua_newuserdata(state, mem::size_of::<T>())? as *mut T;
|
||||||
ptr::write(ud, t);
|
ptr::write(ud, t);
|
||||||
|
@ -171,14 +185,13 @@ pub unsafe fn take_userdata<T>(state: *mut ffi::lua_State) -> T {
|
||||||
// after the first call to __gc.
|
// after the first call to __gc.
|
||||||
get_destructed_userdata_metatable(state);
|
get_destructed_userdata_metatable(state);
|
||||||
ffi::lua_setmetatable(state, -2);
|
ffi::lua_setmetatable(state, -2);
|
||||||
let ud = ffi::lua_touserdata(state, -1) as *mut T;
|
let ud = get_userdata(state, -1);
|
||||||
mlua_debug_assert!(!ud.is_null(), "userdata pointer is null");
|
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
ptr::read(ud)
|
ptr::read(ud)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pushes the userdata and attaches a metatable with __gc method.
|
// Pushes the userdata and attaches a metatable with __gc method.
|
||||||
// Internally uses 4 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>(state: *mut ffi::lua_State, t: T) -> Result<()> {
|
||||||
push_userdata(state, t)?;
|
push_userdata(state, t)?;
|
||||||
get_gc_metatable_for::<T>(state);
|
get_gc_metatable_for::<T>(state);
|
||||||
|
@ -193,9 +206,9 @@ pub unsafe fn get_gc_userdata<T: Any>(state: *mut ffi::lua_State, index: c_int)
|
||||||
return ptr::null_mut();
|
return ptr::null_mut();
|
||||||
}
|
}
|
||||||
get_gc_metatable_for::<T>(state);
|
get_gc_metatable_for::<T>(state);
|
||||||
let res = ffi::lua_rawequal(state, -1, -2) != 0;
|
let res = ffi::lua_rawequal(state, -1, -2);
|
||||||
ffi::lua_pop(state, 2);
|
ffi::lua_pop(state, 2);
|
||||||
if !res {
|
if res == 0 {
|
||||||
return ptr::null_mut();
|
return ptr::null_mut();
|
||||||
}
|
}
|
||||||
ud
|
ud
|
||||||
|
@ -208,7 +221,7 @@ pub unsafe fn get_gc_userdata<T: Any>(state: *mut ffi::lua_State, index: c_int)
|
||||||
// (capturing previous one) to lookup in `field_getters` first, then `methods` and falling back to the
|
// (capturing previous one) to lookup in `field_getters` first, then `methods` and falling back to the
|
||||||
// captured `__index` if no matches found.
|
// captured `__index` if no matches found.
|
||||||
// The same is also applicable for `__newindex` metamethod and `field_setters` table.
|
// The same is also applicable for `__newindex` metamethod and `field_setters` table.
|
||||||
// Internally uses 8 stack spaces and does not call checkstack.
|
// Internally uses 9 stack spaces and does not call checkstack.
|
||||||
pub unsafe fn init_userdata_metatable<T>(
|
pub unsafe fn init_userdata_metatable<T>(
|
||||||
state: *mut ffi::lua_State,
|
state: *mut ffi::lua_State,
|
||||||
metatable: c_int,
|
metatable: c_int,
|
||||||
|
@ -277,15 +290,15 @@ pub unsafe extern "C" fn userdata_destructor<T>(state: *mut ffi::lua_State) -> c
|
||||||
|
|
||||||
// In the context of a lua callback, this will call the given function and if the given function
|
// In the context of a lua callback, this will call the given function and if the given function
|
||||||
// returns an error, *or if the given function panics*, this will result in a call to lua_error (a
|
// returns an error, *or if the given function panics*, this will result in a call to lua_error (a
|
||||||
// longjmp). The error or panic is wrapped in such a way that when calling pop_error back on
|
// longjmp) by a C shim. The error or panic is wrapped in such a way that when calling pop_error back
|
||||||
// the rust side, it will resume the panic.
|
// on the rust side, it will resume the panic (or when popping a panic value from the stack).
|
||||||
//
|
//
|
||||||
// This function assumes the structure of the stack at the beginning of a callback, that the only
|
// This function assumes the structure of the stack at the beginning of a callback, that the only
|
||||||
// elements on the stack are the arguments to the callback.
|
// elements on the stack are the arguments to the callback.
|
||||||
//
|
//
|
||||||
// This function uses some of the bottom of the stack for error handling, the given callback will be
|
// This function uses some of the bottom of the stack for error handling, the given callback will be
|
||||||
// given the number of arguments available as an argument, and should return the number of returns
|
// given the number of arguments available as an argument, and should return the number of returns
|
||||||
// as normal, but cannot assume that the arguments available start at 0.
|
// as normal, but cannot assume that the arguments available start at 1.
|
||||||
pub unsafe fn callback_error<F>(state: *mut ffi::lua_State, f: F) -> c_int
|
pub unsafe fn callback_error<F>(state: *mut ffi::lua_State, f: F) -> c_int
|
||||||
where
|
where
|
||||||
F: FnOnce(c_int) -> Result<c_int>,
|
F: FnOnce(c_int) -> Result<c_int>,
|
||||||
|
@ -315,6 +328,9 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A part of the C shim (error_traceback).
|
||||||
|
// Receives absolute index of error in the stack, a pointer to pre-allocated WrappedError memory,
|
||||||
|
// and optional boolean flag if a traceback value is on top of the stack.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wrapped_error_traceback(
|
pub unsafe extern "C" fn wrapped_error_traceback(
|
||||||
state: *mut ffi::lua_State,
|
state: *mut ffi::lua_State,
|
||||||
|
@ -348,6 +364,7 @@ pub unsafe extern "C" fn wrapped_error_traceback(
|
||||||
ffi::lua_setmetatable(state, -2);
|
ffi::lua_setmetatable(state, -2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns Lua main thread for Lua >= 5.2 or checks that the passed thread is main for Lua 5.1.
|
||||||
// Does not call lua_checkstack, uses 1 stack space.
|
// Does not call lua_checkstack, uses 1 stack space.
|
||||||
pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut ffi::lua_State> {
|
pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut ffi::lua_State> {
|
||||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
||||||
|
@ -370,10 +387,14 @@ pub unsafe fn get_main_state(state: *mut ffi::lua_State) -> Option<*mut ffi::lua
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pushes a WrappedError to the top of the stack. Uses two stack spaces and does not call
|
// Pushes a WrappedError to the top of the stack.
|
||||||
// lua_checkstack.
|
// Uses 2 stack spaces and does not call checkstack.
|
||||||
pub unsafe fn push_wrapped_error(state: *mut ffi::lua_State, err: Error) -> Result<()> {
|
pub unsafe fn push_wrapped_error(state: *mut ffi::lua_State, err: Error) -> Result<()> {
|
||||||
push_gc_userdata::<WrappedError>(state, WrappedError(err))
|
let error_ud = ffi::safe::lua_newwrappederror(state)? as *mut WrappedError;
|
||||||
|
ptr::write(error_ud, WrappedError(err));
|
||||||
|
get_gc_metatable_for::<WrappedError>(state);
|
||||||
|
ffi::lua_setmetatable(state, -2);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if the value at the given index is a WrappedError, and if it is returns a pointer to it,
|
// Checks if the value at the given index is a WrappedError, and if it is returns a pointer to it,
|
||||||
|
@ -387,13 +408,15 @@ pub unsafe fn get_wrapped_error(state: *mut ffi::lua_State, index: c_int) -> *co
|
||||||
&(*ud).0
|
&(*ud).0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the internal (with __gc) metatable for a type T
|
// Initialize the internal (with __gc method) metatable for a type T.
|
||||||
|
// Uses 6 stack spaces and calls checkstack.
|
||||||
pub unsafe fn init_gc_metatable_for<T: Any>(
|
pub unsafe fn init_gc_metatable_for<T: Any>(
|
||||||
state: *mut ffi::lua_State,
|
state: *mut ffi::lua_State,
|
||||||
customize_fn: Option<fn(*mut ffi::lua_State) -> Result<()>>,
|
customize_fn: Option<fn(*mut ffi::lua_State) -> Result<()>>,
|
||||||
) -> Result<*const u8> {
|
) -> Result<*const u8> {
|
||||||
let type_id = TypeId::of::<T>();
|
check_stack(state, 6)?;
|
||||||
|
|
||||||
|
let type_id = TypeId::of::<T>();
|
||||||
let ref_addr = {
|
let ref_addr = {
|
||||||
let mut mt_cache = mlua_expect!(METATABLE_CACHE.lock(), "cannot lock metatable cache");
|
let mut mt_cache = mlua_expect!(METATABLE_CACHE.lock(), "cannot lock metatable cache");
|
||||||
mlua_assert!(
|
mlua_assert!(
|
||||||
|
@ -433,7 +456,7 @@ pub unsafe fn get_gc_metatable_for<T: Any>(state: *mut ffi::lua_State) {
|
||||||
// Initialize the error, panic, and destructed userdata metatables.
|
// Initialize the error, panic, and destructed userdata metatables.
|
||||||
// Returns address of WrappedError and WrappedPanic metatables in Lua registry.
|
// Returns address of WrappedError and WrappedPanic metatables in Lua registry.
|
||||||
pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<(*const u8, *const u8)> {
|
pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<(*const u8, *const u8)> {
|
||||||
assert_stack(state, 8);
|
check_stack(state, 7)?;
|
||||||
|
|
||||||
// Create error and panic metatables
|
// Create error and panic metatables
|
||||||
|
|
||||||
|
@ -442,11 +465,8 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<(*const
|
||||||
check_stack(state, 3)?;
|
check_stack(state, 3)?;
|
||||||
|
|
||||||
let err_buf = if let Some(error) = get_wrapped_error(state, -1).as_ref() {
|
let err_buf = if let Some(error) = get_wrapped_error(state, -1).as_ref() {
|
||||||
ffi::lua_pushlightuserdata(
|
let err_buf_key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void;
|
||||||
state,
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, err_buf_key);
|
||||||
&ERROR_PRINT_BUFFER_KEY as *const u8 as *mut c_void,
|
|
||||||
);
|
|
||||||
ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
|
|
||||||
let err_buf = ffi::lua_touserdata(state, -1) as *mut String;
|
let err_buf = ffi::lua_touserdata(state, -1) as *mut String;
|
||||||
ffi::lua_pop(state, 2);
|
ffi::lua_pop(state, 2);
|
||||||
|
|
||||||
|
@ -507,22 +527,16 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<(*const
|
||||||
|
|
||||||
unsafe extern "C" fn destructed_error(state: *mut ffi::lua_State) -> c_int {
|
unsafe extern "C" fn destructed_error(state: *mut ffi::lua_State) -> c_int {
|
||||||
callback_error(state, |_| {
|
callback_error(state, |_| {
|
||||||
check_stack(state, 3)?;
|
check_stack(state, 2)?;
|
||||||
let ud = ffi::safe::lua_newuserdata(state, mem::size_of::<WrappedError>())?
|
let error_ud = ffi::safe::lua_newwrappederror(state)? as *mut WrappedError;
|
||||||
as *mut WrappedError;
|
ptr::write(error_ud, WrappedError(Error::CallbackDestructed));
|
||||||
ptr::write(ud, WrappedError(Error::CallbackDestructed));
|
|
||||||
get_gc_metatable_for::<WrappedError>(state);
|
get_gc_metatable_for::<WrappedError>(state);
|
||||||
ffi::lua_setmetatable(state, -2);
|
ffi::lua_setmetatable(state, -2);
|
||||||
Ok(-1) // to trigger lua_error
|
Ok(-1) // to trigger lua_error
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
ffi::lua_pushlightuserdata(
|
|
||||||
state,
|
|
||||||
&DESTRUCTED_USERDATA_METATABLE as *const u8 as *mut c_void,
|
|
||||||
);
|
|
||||||
ffi::safe::lua_createtable(state, 0, 26)?;
|
ffi::safe::lua_createtable(state, 0, 26)?;
|
||||||
|
|
||||||
ffi::safe::lua_pushrclosure(state, destructed_error, 0)?;
|
ffi::safe::lua_pushrclosure(state, destructed_error, 0)?;
|
||||||
for &method in &[
|
for &method in &[
|
||||||
"__add",
|
"__add",
|
||||||
|
@ -567,22 +581,14 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<(*const
|
||||||
}
|
}
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
|
|
||||||
ffi::safe::lua_rawset(state, ffi::LUA_REGISTRYINDEX)?;
|
let destructed_metatable_key = &DESTRUCTED_USERDATA_METATABLE as *const u8 as *const c_void;
|
||||||
|
ffi::safe::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, destructed_metatable_key)?;
|
||||||
|
|
||||||
// Create error print buffer
|
// Create error print buffer
|
||||||
|
init_gc_metatable_for::<String>(state, None)?;
|
||||||
ffi::lua_pushlightuserdata(state, &ERROR_PRINT_BUFFER_KEY as *const u8 as *mut c_void);
|
push_gc_userdata(state, String::new())?;
|
||||||
|
let err_buf_key = &ERROR_PRINT_BUFFER_KEY as *const u8 as *const c_void;
|
||||||
let ud = ffi::safe::lua_newuserdata(state, mem::size_of::<String>())? as *mut String;
|
ffi::safe::lua_rawsetp(state, ffi::LUA_REGISTRYINDEX, err_buf_key)?;
|
||||||
ptr::write(ud, String::new());
|
|
||||||
|
|
||||||
ffi::safe::lua_createtable(state, 0, 1)?;
|
|
||||||
ffi::safe::lua_pushrclosure(state, userdata_destructor::<String>, 0)?;
|
|
||||||
ffi::safe::lua_rawsetfield(state, -2, "__gc")?;
|
|
||||||
|
|
||||||
ffi::lua_setmetatable(state, -2);
|
|
||||||
|
|
||||||
ffi::safe::lua_rawset(state, ffi::LUA_REGISTRYINDEX)?;
|
|
||||||
|
|
||||||
Ok((wrapped_error_key, wrapped_panic_key))
|
Ok((wrapped_error_key, wrapped_panic_key))
|
||||||
}
|
}
|
||||||
|
@ -625,11 +631,8 @@ unsafe fn to_string(state: *mut ffi::lua_State, index: c_int) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn get_destructed_userdata_metatable(state: *mut ffi::lua_State) {
|
pub(crate) unsafe fn get_destructed_userdata_metatable(state: *mut ffi::lua_State) {
|
||||||
ffi::lua_pushlightuserdata(
|
let key = &DESTRUCTED_USERDATA_METATABLE as *const u8 as *const c_void;
|
||||||
state,
|
ffi::lua_rawgetp(state, ffi::LUA_REGISTRYINDEX, key);
|
||||||
&DESTRUCTED_USERDATA_METATABLE as *const u8 as *mut c_void,
|
|
||||||
);
|
|
||||||
ffi::lua_rawget(state, ffi::LUA_REGISTRYINDEX);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static DESTRUCTED_USERDATA_METATABLE: u8 = 0;
|
static DESTRUCTED_USERDATA_METATABLE: u8 = 0;
|
||||||
|
|
|
@ -18,8 +18,7 @@ use crate::userdata::AnyUserData;
|
||||||
|
|
||||||
/// A dynamically typed Lua value. The `String`, `Table`, `Function`, `Thread`, and `UserData`
|
/// A dynamically typed Lua value. The `String`, `Table`, `Function`, `Thread`, and `UserData`
|
||||||
/// variants contain handle types into the internal Lua state. It is a logic error to mix handle
|
/// variants contain handle types into the internal Lua state. It is a logic error to mix handle
|
||||||
/// types between separate `Lua` instances, or between a parent `Lua` instance and one received as a
|
/// types between separate `Lua` instances, and doing so will result in a panic.
|
||||||
/// parameter in a Rust callback, and doing so will result in a panic.
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Value<'lua> {
|
pub enum Value<'lua> {
|
||||||
/// The Lua value `nil`.
|
/// The Lua value `nil`.
|
||||||
|
|
Loading…
Reference in New Issue