Add `set_nth_user_value` and `get_nth_user_value` to `AnyUserData`
with `n` up to 65535 for all Lua versions.
This commit is contained in:
parent
2ea2b1f4fb
commit
153502ec73
17
src/lua.rs
17
src/lua.rs
|
@ -31,10 +31,15 @@ use crate::util::{
|
||||||
self, assert_stack, callback_error, check_stack, get_destructed_userdata_metatable,
|
self, assert_stack, callback_error, check_stack, get_destructed_userdata_metatable,
|
||||||
get_gc_metatable, get_gc_userdata, get_main_state, get_userdata, init_error_registry,
|
get_gc_metatable, get_gc_userdata, get_main_state, get_userdata, init_error_registry,
|
||||||
init_gc_metatable, init_userdata_metatable, pop_error, push_gc_userdata, push_string,
|
init_gc_metatable, init_userdata_metatable, pop_error, push_gc_userdata, push_string,
|
||||||
push_table, push_userdata, rawset_field, safe_pcall, safe_xpcall, StackGuard, WrappedFailure,
|
push_table, rawset_field, safe_pcall, safe_xpcall, StackGuard, WrappedFailure,
|
||||||
};
|
};
|
||||||
use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
|
use crate::value::{FromLua, FromLuaMulti, MultiValue, Nil, ToLua, ToLuaMulti, Value};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "lua54"))]
|
||||||
|
use crate::util::push_userdata;
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
use crate::{userdata::USER_VALUE_MAXSLOT, util::push_userdata_uv};
|
||||||
|
|
||||||
#[cfg(not(feature = "send"))]
|
#[cfg(not(feature = "send"))]
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
@ -2215,10 +2220,20 @@ 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>()?;
|
||||||
|
#[cfg(not(feature = "lua54"))]
|
||||||
push_userdata(self.state, data)?;
|
push_userdata(self.state, data)?;
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
push_userdata_uv(self.state, data, USER_VALUE_MAXSLOT as c_int)?;
|
||||||
ffi::lua_replace(self.state, -3);
|
ffi::lua_replace(self.state, -3);
|
||||||
ffi::lua_setmetatable(self.state, -2);
|
ffi::lua_setmetatable(self.state, -2);
|
||||||
|
|
||||||
|
// Set empty environment for Lua 5.1
|
||||||
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
|
protect_lua!(self.state, 1, 1, fn(state) {
|
||||||
|
ffi::lua_newtable(state);
|
||||||
|
ffi::lua_setuservalue(state, -2);
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(AnyUserData(self.pop_ref()))
|
Ok(AnyUserData(self.pop_ref()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
44
src/scope.rs
44
src/scope.rs
|
@ -23,6 +23,9 @@ use crate::util::{
|
||||||
};
|
};
|
||||||
use crate::value::{FromLua, FromLuaMulti, MultiValue, ToLua, ToLuaMulti, Value};
|
use crate::value::{FromLua, FromLuaMulti, MultiValue, ToLua, ToLuaMulti, Value};
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
use crate::userdata::USER_VALUE_MAXSLOT;
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
use {
|
use {
|
||||||
crate::types::{AsyncCallback, AsyncCallbackUpvalue, AsyncPollUpvalue},
|
crate::types::{AsyncCallback, AsyncCallbackUpvalue, AsyncPollUpvalue},
|
||||||
|
@ -197,12 +200,22 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear uservalue
|
// Clear associated user values
|
||||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
#[cfg(feature = "lua54")]
|
||||||
|
for i in 1..=USER_VALUE_MAXSLOT {
|
||||||
ffi::lua_pushnil(state);
|
ffi::lua_pushnil(state);
|
||||||
|
ffi::lua_setiuservalue(state, -2, i as c_int);
|
||||||
|
}
|
||||||
|
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||||
|
{
|
||||||
|
ffi::lua_pushnil(state);
|
||||||
|
ffi::lua_setuservalue(state, -2);
|
||||||
|
}
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
|
{
|
||||||
ud.lua.push_ref(&newtable.0);
|
ud.lua.push_ref(&newtable.0);
|
||||||
ffi::lua_setuservalue(state, -2);
|
ffi::lua_setuservalue(state, -2);
|
||||||
|
}
|
||||||
|
|
||||||
vec![Box::new(take_userdata::<UserDataCell<T>>(state))]
|
vec![Box::new(take_userdata::<UserDataCell<T>>(state))]
|
||||||
});
|
});
|
||||||
|
@ -323,8 +336,19 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
check_stack(lua.state, 13)?;
|
check_stack(lua.state, 13)?;
|
||||||
|
|
||||||
|
#[allow(clippy::let_and_return)]
|
||||||
let data_ptr = protect_lua!(lua.state, 0, 1, |state| {
|
let data_ptr = protect_lua!(lua.state, 0, 1, |state| {
|
||||||
ffi::lua_newuserdata(state, mem::size_of::<UserDataCell<Rc<RefCell<T>>>>())
|
let ud =
|
||||||
|
ffi::lua_newuserdata(state, mem::size_of::<UserDataCell<Rc<RefCell<T>>>>());
|
||||||
|
|
||||||
|
// Set empty environment for Lua 5.1
|
||||||
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
|
{
|
||||||
|
ffi::lua_newtable(state);
|
||||||
|
ffi::lua_setuservalue(state, -2);
|
||||||
|
}
|
||||||
|
|
||||||
|
ud
|
||||||
})?;
|
})?;
|
||||||
// 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;
|
||||||
|
@ -416,12 +440,22 @@ impl<'lua, 'scope> Scope<'lua, 'scope> {
|
||||||
ffi::lua_pop(state, 1);
|
ffi::lua_pop(state, 1);
|
||||||
ud.lua.deregister_userdata_metatable(mt_ptr);
|
ud.lua.deregister_userdata_metatable(mt_ptr);
|
||||||
|
|
||||||
// Clear uservalue
|
// Clear associated user values
|
||||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
#[cfg(feature = "lua54")]
|
||||||
|
for i in 1..=USER_VALUE_MAXSLOT {
|
||||||
ffi::lua_pushnil(state);
|
ffi::lua_pushnil(state);
|
||||||
|
ffi::lua_setiuservalue(state, -2, i as c_int);
|
||||||
|
}
|
||||||
|
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||||
|
{
|
||||||
|
ffi::lua_pushnil(state);
|
||||||
|
ffi::lua_setuservalue(state, -2);
|
||||||
|
}
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
|
{
|
||||||
ud.lua.push_ref(&newtable.0);
|
ud.lua.push_ref(&newtable.0);
|
||||||
ffi::lua_setuservalue(state, -2);
|
ffi::lua_setuservalue(state, -2);
|
||||||
|
}
|
||||||
|
|
||||||
// A hack to drop non-static `T`
|
// A hack to drop non-static `T`
|
||||||
unsafe fn seal<T>(t: T) -> Box<dyn FnOnce() + 'static> {
|
unsafe fn seal<T>(t: T) -> Box<dyn FnOnce() + 'static> {
|
||||||
|
|
168
src/userdata.rs
168
src/userdata.rs
|
@ -23,12 +23,15 @@ use crate::types::{Callback, LuaRef, MaybeSend};
|
||||||
use crate::util::{check_stack, get_userdata, take_userdata, StackGuard};
|
use crate::util::{check_stack, get_userdata, take_userdata, StackGuard};
|
||||||
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti};
|
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti};
|
||||||
|
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
#[cfg(feature = "lua54")]
|
||||||
use crate::value::Value;
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
use crate::types::AsyncCallback;
|
use crate::types::AsyncCallback;
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
pub(crate) const USER_VALUE_MAXSLOT: usize = 8;
|
||||||
|
|
||||||
/// Kinds of metamethods that can be overridden.
|
/// Kinds of metamethods that can be overridden.
|
||||||
///
|
///
|
||||||
/// Currently, this mechanism does not allow overriding the `__gc` metamethod, since there is
|
/// Currently, this mechanism does not allow overriding the `__gc` metamethod, since there is
|
||||||
|
@ -819,11 +822,13 @@ impl<'lua> AnyUserData<'lua> {
|
||||||
|
|
||||||
/// Takes out the value of `UserData` and sets the special "destructed" metatable that prevents
|
/// Takes out the value of `UserData` and sets the special "destructed" metatable that prevents
|
||||||
/// any further operations with this userdata.
|
/// any further operations with this userdata.
|
||||||
|
///
|
||||||
|
/// All associated user values will be also cleared.
|
||||||
pub fn take<T: 'static + UserData>(&self) -> Result<T> {
|
pub fn take<T: 'static + UserData>(&self) -> Result<T> {
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
check_stack(lua.state, 2)?;
|
check_stack(lua.state, 3)?;
|
||||||
|
|
||||||
let type_id = lua.push_userdata_ref(&self.0)?;
|
let type_id = lua.push_userdata_ref(&self.0)?;
|
||||||
match type_id {
|
match type_id {
|
||||||
|
@ -831,12 +836,22 @@ impl<'lua> AnyUserData<'lua> {
|
||||||
// Try to borrow userdata exclusively
|
// Try to borrow userdata exclusively
|
||||||
let _ = (*get_userdata::<UserDataCell<T>>(lua.state, -1)).try_borrow_mut()?;
|
let _ = (*get_userdata::<UserDataCell<T>>(lua.state, -1)).try_borrow_mut()?;
|
||||||
|
|
||||||
// Clear uservalue
|
// Clear associated user values
|
||||||
#[cfg(any(feature = "lua54", feature = "lua53", feature = "lua52"))]
|
#[cfg(feature = "lua54")]
|
||||||
|
for i in 1..=USER_VALUE_MAXSLOT {
|
||||||
|
ffi::lua_pushnil(lua.state);
|
||||||
|
ffi::lua_setiuservalue(lua.state, -2, i as c_int);
|
||||||
|
}
|
||||||
|
#[cfg(any(feature = "lua53", feature = "lua52"))]
|
||||||
|
{
|
||||||
ffi::lua_pushnil(lua.state);
|
ffi::lua_pushnil(lua.state);
|
||||||
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
|
||||||
protect_lua!(lua.state, 0, 1, fn(state) ffi::lua_newtable(state))?;
|
|
||||||
ffi::lua_setuservalue(lua.state, -2);
|
ffi::lua_setuservalue(lua.state, -2);
|
||||||
|
}
|
||||||
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
||||||
|
protect_lua!(lua.state, 1, 1, fn(state) {
|
||||||
|
ffi::lua_newtable(state);
|
||||||
|
ffi::lua_setuservalue(state, -2);
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(take_userdata::<UserDataCell<T>>(lua.state).into_inner())
|
Ok(take_userdata::<UserDataCell<T>>(lua.state).into_inner())
|
||||||
}
|
}
|
||||||
|
@ -848,27 +863,76 @@ impl<'lua> AnyUserData<'lua> {
|
||||||
/// Sets an associated value to this `AnyUserData`.
|
/// Sets an associated value to this `AnyUserData`.
|
||||||
///
|
///
|
||||||
/// The value may be any Lua value whatsoever, and can be retrieved with [`get_user_value`].
|
/// The value may be any Lua value whatsoever, and can be retrieved with [`get_user_value`].
|
||||||
/// As Lua < 5.3 allows to store only tables, the value will be stored in a table at index 1.
|
///
|
||||||
|
/// This is the same as calling [`set_nth_user_value`] with `n` set to 1.
|
||||||
///
|
///
|
||||||
/// [`get_user_value`]: #method.get_user_value
|
/// [`get_user_value`]: #method.get_user_value
|
||||||
|
/// [`set_nth_user_value`]: #method.set_nth_user_value
|
||||||
pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> {
|
pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> {
|
||||||
|
self.set_nth_user_value(1, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets an associated `n`th value to this `AnyUserData`.
|
||||||
|
///
|
||||||
|
/// The value may be any Lua value whatsoever, and can be retrieved with [`get_nth_user_value`].
|
||||||
|
/// `n` starts from 1 and can be up to 65535.
|
||||||
|
///
|
||||||
|
/// This is supported for all Lua versions.
|
||||||
|
/// In Lua 5.4 first 7 elements are stored in a most efficient way.
|
||||||
|
/// For other Lua versions this functionality is provided using a wrapping table.
|
||||||
|
///
|
||||||
|
/// [`get_nth_user_value`]: #method.get_nth_user_value
|
||||||
|
pub fn set_nth_user_value<V: ToLua<'lua>>(&self, n: usize, v: V) -> Result<()> {
|
||||||
|
if n < 1 || n > u16::MAX as usize {
|
||||||
|
return Err(Error::RuntimeError(
|
||||||
|
"user value index out of bounds".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
|
||||||
let v = {
|
|
||||||
// Lua <= 5.2 allows to store only a table. Then we will wrap the value.
|
|
||||||
let t = lua.create_table_with_capacity(1, 0)?;
|
|
||||||
t.raw_set(1, v)?;
|
|
||||||
Value::Table(t)
|
|
||||||
};
|
|
||||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
|
||||||
let v = v.to_lua(lua)?;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
check_stack(lua.state, 3)?;
|
check_stack(lua.state, 5)?;
|
||||||
|
|
||||||
lua.push_userdata_ref(&self.0)?;
|
lua.push_userdata_ref(&self.0)?;
|
||||||
lua.push_value(v)?;
|
lua.push_value(v.to_lua(lua)?)?;
|
||||||
ffi::lua_setuservalue(lua.state, -2);
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
if n < USER_VALUE_MAXSLOT {
|
||||||
|
ffi::lua_setiuservalue(lua.state, -2, n as c_int);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple (extra) user values are emulated by storing them in a table
|
||||||
|
|
||||||
|
let getuservalue_t = |state, idx| {
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
return ffi::lua_getiuservalue(state, idx, USER_VALUE_MAXSLOT as c_int);
|
||||||
|
#[cfg(not(feature = "lua54"))]
|
||||||
|
return ffi::lua_getuservalue(state, idx);
|
||||||
|
};
|
||||||
|
let getn = |n: usize| {
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
return n - USER_VALUE_MAXSLOT + 1;
|
||||||
|
#[cfg(not(feature = "lua54"))]
|
||||||
|
return n;
|
||||||
|
};
|
||||||
|
|
||||||
|
protect_lua!(lua.state, 2, 0, |state| {
|
||||||
|
if getuservalue_t(lua.state, -2) != ffi::LUA_TTABLE {
|
||||||
|
// Create a new table to use as uservalue
|
||||||
|
ffi::lua_pop(lua.state, 1);
|
||||||
|
ffi::lua_newtable(state);
|
||||||
|
ffi::lua_pushvalue(state, -1);
|
||||||
|
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
ffi::lua_setiuservalue(lua.state, -4, USER_VALUE_MAXSLOT as c_int);
|
||||||
|
#[cfg(not(feature = "lua54"))]
|
||||||
|
ffi::lua_setuservalue(lua.state, -4);
|
||||||
|
}
|
||||||
|
ffi::lua_pushvalue(state, -2);
|
||||||
|
ffi::lua_rawseti(state, -2, getn(n) as ffi::lua_Integer);
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -876,26 +940,68 @@ impl<'lua> AnyUserData<'lua> {
|
||||||
|
|
||||||
/// Returns an associated value set by [`set_user_value`].
|
/// Returns an associated value set by [`set_user_value`].
|
||||||
///
|
///
|
||||||
/// For Lua < 5.3 the value will be automatically extracted from the table wrapper from index 1.
|
/// This is the same as calling [`get_nth_user_value`] with `n` set to 1.
|
||||||
///
|
///
|
||||||
/// [`set_user_value`]: #method.set_user_value
|
/// [`set_user_value`]: #method.set_user_value
|
||||||
|
/// [`get_nth_user_value`]: #method.get_nth_user_value
|
||||||
pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
|
pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
|
||||||
|
self.get_nth_user_value(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an associated `n`th value set by [`set_nth_user_value`].
|
||||||
|
///
|
||||||
|
/// `n` starts from 1 and can be up to 65535.
|
||||||
|
///
|
||||||
|
/// This is supported for all Lua versions.
|
||||||
|
/// In Lua 5.4 first 7 elements are stored in a most efficient way.
|
||||||
|
/// For other Lua versions this functionality is provided using a wrapping table.
|
||||||
|
///
|
||||||
|
/// [`set_nth_user_value`]: #method.set_nth_user_value
|
||||||
|
pub fn get_nth_user_value<V: FromLua<'lua>>(&self, n: usize) -> Result<V> {
|
||||||
|
if n < 1 || n > u16::MAX as usize {
|
||||||
|
return Err(Error::RuntimeError(
|
||||||
|
"user value index out of bounds".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let lua = self.0.lua;
|
let lua = self.0.lua;
|
||||||
let res = unsafe {
|
unsafe {
|
||||||
let _sg = StackGuard::new(lua.state);
|
let _sg = StackGuard::new(lua.state);
|
||||||
check_stack(lua.state, 3)?;
|
check_stack(lua.state, 4)?;
|
||||||
|
|
||||||
lua.push_userdata_ref(&self.0)?;
|
lua.push_userdata_ref(&self.0)?;
|
||||||
ffi::lua_getuservalue(lua.state, -1);
|
|
||||||
lua.pop_value()
|
#[cfg(feature = "lua54")]
|
||||||
|
if n < USER_VALUE_MAXSLOT {
|
||||||
|
ffi::lua_getiuservalue(lua.state, -1, n as c_int);
|
||||||
|
return V::from_lua(lua.pop_value(), lua);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple (extra) user values are emulated by storing them in a table
|
||||||
|
|
||||||
|
let getuservalue_t = |state, idx| {
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
return ffi::lua_getiuservalue(state, idx, USER_VALUE_MAXSLOT as c_int);
|
||||||
|
#[cfg(not(feature = "lua54"))]
|
||||||
|
return ffi::lua_getuservalue(state, idx);
|
||||||
};
|
};
|
||||||
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
let getn = |n: usize| {
|
||||||
return match <Option<Table>>::from_lua(res, lua)? {
|
#[cfg(feature = "lua54")]
|
||||||
Some(t) => t.get(1),
|
return n - USER_VALUE_MAXSLOT + 1;
|
||||||
None => V::from_lua(Value::Nil, lua),
|
#[cfg(not(feature = "lua54"))]
|
||||||
|
return n;
|
||||||
};
|
};
|
||||||
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
|
||||||
V::from_lua(res, lua)
|
protect_lua!(lua.state, 1, 1, |state| {
|
||||||
|
if getuservalue_t(lua.state, -1) != ffi::LUA_TTABLE {
|
||||||
|
ffi::lua_pushnil(lua.state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ffi::lua_rawgeti(state, -1, getn(n) as ffi::lua_Integer);
|
||||||
|
})?;
|
||||||
|
|
||||||
|
V::from_lua(lua.pop_value(), lua)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a metatable of this `UserData`.
|
/// Returns a metatable of this `UserData`.
|
||||||
|
|
11
src/util.rs
11
src/util.rs
|
@ -287,6 +287,17 @@ pub unsafe fn push_userdata<T>(state: *mut ffi::lua_State, t: T) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internally uses 3 stack spaces, does not call checkstack.
|
||||||
|
#[cfg(feature = "lua54")]
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn push_userdata_uv<T>(state: *mut ffi::lua_State, t: T, nuvalue: c_int) -> Result<()> {
|
||||||
|
let ud = protect_lua!(state, 0, 1, |state| {
|
||||||
|
ffi::lua_newuserdatauv(state, mem::size_of::<T>(), nuvalue) as *mut T
|
||||||
|
})?;
|
||||||
|
ptr::write(ud, t);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn get_userdata<T>(state: *mut ffi::lua_State, index: c_int) -> *mut T {
|
pub unsafe fn get_userdata<T>(state: *mut ffi::lua_State, index: c_int) -> *mut T {
|
||||||
let ud = ffi::lua_touserdata(state, index) as *mut T;
|
let ud = ffi::lua_touserdata(state, index) as *mut T;
|
||||||
|
|
|
@ -299,7 +299,7 @@ fn test_userdata_take() -> Result<()> {
|
||||||
|
|
||||||
fn check_userdata_take(lua: &Lua, userdata: AnyUserData, rc: Arc<i64>) -> Result<()> {
|
fn check_userdata_take(lua: &Lua, userdata: AnyUserData, rc: Arc<i64>) -> Result<()> {
|
||||||
lua.globals().set("userdata", userdata.clone())?;
|
lua.globals().set("userdata", userdata.clone())?;
|
||||||
assert_eq!(Arc::strong_count(&rc), 2);
|
assert_eq!(Arc::strong_count(&rc), 3);
|
||||||
let userdata_copy = userdata.clone();
|
let userdata_copy = userdata.clone();
|
||||||
{
|
{
|
||||||
let _value = userdata.borrow::<MyUserdata>()?;
|
let _value = userdata.borrow::<MyUserdata>()?;
|
||||||
|
@ -313,6 +313,7 @@ fn test_userdata_take() -> Result<()> {
|
||||||
let value = userdata_copy.take::<MyUserdata>()?;
|
let value = userdata_copy.take::<MyUserdata>()?;
|
||||||
assert_eq!(*value.0, 18);
|
assert_eq!(*value.0, 18);
|
||||||
drop(value);
|
drop(value);
|
||||||
|
lua.gc_collect()?;
|
||||||
assert_eq!(Arc::strong_count(&rc), 1);
|
assert_eq!(Arc::strong_count(&rc), 1);
|
||||||
|
|
||||||
match userdata.borrow::<MyUserdata>() {
|
match userdata.borrow::<MyUserdata>() {
|
||||||
|
@ -333,6 +334,7 @@ fn test_userdata_take() -> Result<()> {
|
||||||
|
|
||||||
let rc = Arc::new(18);
|
let rc = Arc::new(18);
|
||||||
let userdata = lua.create_userdata(MyUserdata(rc.clone()))?;
|
let userdata = lua.create_userdata(MyUserdata(rc.clone()))?;
|
||||||
|
userdata.set_nth_user_value(2, MyUserdata(rc.clone()))?;
|
||||||
check_userdata_take(&lua, userdata, rc)?;
|
check_userdata_take(&lua, userdata, rc)?;
|
||||||
|
|
||||||
// Additionally check serializable userdata
|
// Additionally check serializable userdata
|
||||||
|
@ -340,6 +342,7 @@ fn test_userdata_take() -> Result<()> {
|
||||||
{
|
{
|
||||||
let rc = Arc::new(18);
|
let rc = Arc::new(18);
|
||||||
let userdata = lua.create_ser_userdata(MyUserdata(rc.clone()))?;
|
let userdata = lua.create_ser_userdata(MyUserdata(rc.clone()))?;
|
||||||
|
userdata.set_nth_user_value(2, MyUserdata(rc.clone()))?;
|
||||||
check_userdata_take(&lua, userdata, rc)?;
|
check_userdata_take(&lua, userdata, rc)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,16 +372,24 @@ fn test_destroy_userdata() -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_user_value() -> Result<()> {
|
fn test_user_values() -> Result<()> {
|
||||||
struct MyUserData;
|
struct MyUserData;
|
||||||
|
|
||||||
impl UserData for MyUserData {}
|
impl UserData for MyUserData {}
|
||||||
|
|
||||||
let lua = Lua::new();
|
let lua = Lua::new();
|
||||||
let ud = lua.create_userdata(MyUserData)?;
|
let ud = lua.create_userdata(MyUserData)?;
|
||||||
ud.set_user_value("hello")?;
|
|
||||||
assert_eq!(ud.get_user_value::<String>()?, "hello");
|
ud.set_nth_user_value(1, "hello")?;
|
||||||
assert!(ud.get_user_value::<u32>().is_err());
|
ud.set_nth_user_value(2, "world")?;
|
||||||
|
ud.set_nth_user_value(65535, 321)?;
|
||||||
|
assert_eq!(ud.get_nth_user_value::<String>(1)?, "hello");
|
||||||
|
assert_eq!(ud.get_nth_user_value::<String>(2)?, "world");
|
||||||
|
assert_eq!(ud.get_nth_user_value::<Value>(3)?, Value::Nil);
|
||||||
|
assert_eq!(ud.get_nth_user_value::<i32>(65535)?, 321);
|
||||||
|
|
||||||
|
assert!(ud.get_nth_user_value::<Value>(0).is_err());
|
||||||
|
assert!(ud.get_nth_user_value::<Value>(65536).is_err());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue