2017-10-23 16:42:20 -04:00
|
|
|
use std::cell::{Ref, RefCell, RefMut};
|
2017-09-30 01:08:08 -04:00
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
use crate::error::{Error, Result};
|
|
|
|
use crate::ffi;
|
|
|
|
use crate::lua::Lua;
|
|
|
|
use crate::types::LuaRef;
|
|
|
|
use crate::util::{assert_stack, get_userdata, StackGuard};
|
|
|
|
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti};
|
2018-09-04 19:05:21 -04:00
|
|
|
|
|
|
|
/// Kinds of metamethods that can be overridden.
|
|
|
|
///
|
|
|
|
/// Currently, this mechanism does not allow overriding the `__gc` metamethod, since there is
|
|
|
|
/// generally no need to do so: [`UserData`] implementors can instead just implement `Drop`.
|
|
|
|
///
|
|
|
|
/// [`UserData`]: trait.UserData.html
|
|
|
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
|
|
|
pub enum MetaMethod {
|
|
|
|
/// The `+` operator.
|
|
|
|
Add,
|
|
|
|
/// The `-` operator.
|
|
|
|
Sub,
|
|
|
|
/// The `*` operator.
|
|
|
|
Mul,
|
|
|
|
/// The `/` operator.
|
|
|
|
Div,
|
|
|
|
/// The `%` operator.
|
|
|
|
Mod,
|
|
|
|
/// The `^` operator.
|
|
|
|
Pow,
|
|
|
|
/// The unary minus (`-`) operator.
|
|
|
|
Unm,
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2018-09-04 19:05:21 -04:00
|
|
|
/// The floor division (//) operator.
|
|
|
|
IDiv,
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2018-09-04 19:05:21 -04:00
|
|
|
/// The bitwise AND (&) operator.
|
|
|
|
BAnd,
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2018-09-04 19:05:21 -04:00
|
|
|
/// The bitwise OR (|) operator.
|
|
|
|
BOr,
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2018-09-04 19:05:21 -04:00
|
|
|
/// The bitwise XOR (binary ~) operator.
|
|
|
|
BXor,
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2018-09-04 19:05:21 -04:00
|
|
|
/// The bitwise NOT (unary ~) operator.
|
|
|
|
BNot,
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2018-09-04 19:05:21 -04:00
|
|
|
/// The bitwise left shift (<<) operator.
|
|
|
|
Shl,
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2018-09-04 19:05:21 -04:00
|
|
|
/// The bitwise right shift (>>) operator.
|
|
|
|
Shr,
|
|
|
|
/// The string concatenation operator `..`.
|
|
|
|
Concat,
|
|
|
|
/// The length operator `#`.
|
|
|
|
Len,
|
|
|
|
/// The `==` operator.
|
|
|
|
Eq,
|
|
|
|
/// The `<` operator.
|
|
|
|
Lt,
|
|
|
|
/// The `<=` operator.
|
|
|
|
Le,
|
|
|
|
/// Index access `obj[key]`.
|
|
|
|
Index,
|
|
|
|
/// Index write access `obj[key] = value`.
|
|
|
|
NewIndex,
|
|
|
|
/// The call "operator" `obj(arg1, args2, ...)`.
|
|
|
|
Call,
|
|
|
|
/// The `__tostring` metamethod.
|
|
|
|
///
|
|
|
|
/// This is not an operator, but will be called by methods such as `tostring` and `print`.
|
|
|
|
ToString,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MetaMethod {
|
2019-09-27 12:27:37 -04:00
|
|
|
pub(crate) fn name(self) -> &'static [u8] {
|
2018-09-04 19:05:21 -04:00
|
|
|
match self {
|
2019-09-27 12:27:37 -04:00
|
|
|
MetaMethod::Add => b"__add",
|
|
|
|
MetaMethod::Sub => b"__sub",
|
|
|
|
MetaMethod::Mul => b"__mul",
|
|
|
|
MetaMethod::Div => b"__div",
|
|
|
|
MetaMethod::Mod => b"__mod",
|
|
|
|
MetaMethod::Pow => b"__pow",
|
|
|
|
MetaMethod::Unm => b"__unm",
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2019-09-27 12:27:37 -04:00
|
|
|
MetaMethod::IDiv => b"__idiv",
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2019-09-27 12:27:37 -04:00
|
|
|
MetaMethod::BAnd => b"__band",
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2019-09-27 12:27:37 -04:00
|
|
|
MetaMethod::BOr => b"__bor",
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2019-09-27 12:27:37 -04:00
|
|
|
MetaMethod::BXor => b"__bxor",
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2019-09-27 12:27:37 -04:00
|
|
|
MetaMethod::BNot => b"__bnot",
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2019-09-27 12:27:37 -04:00
|
|
|
MetaMethod::Shl => b"__shl",
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(feature = "lua53")]
|
2019-09-27 12:27:37 -04:00
|
|
|
MetaMethod::Shr => b"__shr",
|
|
|
|
MetaMethod::Concat => b"__concat",
|
|
|
|
MetaMethod::Len => b"__len",
|
|
|
|
MetaMethod::Eq => b"__eq",
|
|
|
|
MetaMethod::Lt => b"__lt",
|
|
|
|
MetaMethod::Le => b"__le",
|
|
|
|
MetaMethod::Index => b"__index",
|
|
|
|
MetaMethod::NewIndex => b"__newindex",
|
|
|
|
MetaMethod::Call => b"__call",
|
|
|
|
MetaMethod::ToString => b"__tostring",
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Method registry for [`UserData`] implementors.
|
|
|
|
///
|
|
|
|
/// [`UserData`]: trait.UserData.html
|
|
|
|
pub trait UserDataMethods<'lua, T: UserData> {
|
|
|
|
/// Add a method which accepts a `&T` as the first parameter.
|
|
|
|
///
|
|
|
|
/// Regular methods are implemented by overriding the `__index` metamethod and returning the
|
|
|
|
/// accessed method. This allows them to be used with the expected `userdata:method()` syntax.
|
|
|
|
///
|
|
|
|
/// If `add_meta_method` is used to set the `__index` metamethod, the `__index` metamethod will
|
|
|
|
/// be used as a fall-back if no regular method is found.
|
2019-09-27 12:27:37 -04:00
|
|
|
fn add_method<S, A, R, M>(&mut self, name: &S, method: M)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2019-09-27 12:27:37 -04:00
|
|
|
S: ?Sized + AsRef<[u8]>,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
|
|
|
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>;
|
|
|
|
|
|
|
|
/// Add a regular method which accepts a `&mut T` as the first parameter.
|
|
|
|
///
|
|
|
|
/// Refer to [`add_method`] for more information about the implementation.
|
|
|
|
///
|
|
|
|
/// [`add_method`]: #method.add_method
|
2019-09-27 12:27:37 -04:00
|
|
|
fn add_method_mut<S, A, R, M>(&mut self, name: &S, method: M)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2019-09-27 12:27:37 -04:00
|
|
|
S: ?Sized + AsRef<[u8]>,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
|
|
|
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
|
|
|
|
|
|
|
/// Add a regular method as a function which accepts generic arguments, the first argument will
|
2019-09-27 12:27:37 -04:00
|
|
|
/// be a `UserData` of type T if the method is called with Lua method syntax:
|
|
|
|
/// `my_userdata:my_method(arg1, arg2)`, or it is passed in as the first argument:
|
|
|
|
/// `my_userdata.my_method(my_userdata, arg1, arg2)`.
|
2018-09-04 19:05:21 -04:00
|
|
|
///
|
|
|
|
/// Prefer to use [`add_method`] or [`add_method_mut`] as they are easier to use.
|
|
|
|
///
|
|
|
|
/// [`add_method`]: #method.add_method
|
|
|
|
/// [`add_method_mut`]: #method.add_method_mut
|
2019-09-27 12:27:37 -04:00
|
|
|
fn add_function<S, A, R, F>(&mut self, name: &S, function: F)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2019-09-27 12:27:37 -04:00
|
|
|
S: ?Sized + AsRef<[u8]>,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
|
|
|
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>;
|
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
/// Add a regular method as a mutable function which accepts generic arguments.
|
2018-09-04 19:05:21 -04:00
|
|
|
///
|
|
|
|
/// This is a version of [`add_function`] that accepts a FnMut argument.
|
|
|
|
///
|
|
|
|
/// [`add_function`]: #method.add_function
|
2019-09-27 12:27:37 -04:00
|
|
|
fn add_function_mut<S, A, R, F>(&mut self, name: &S, function: F)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2019-09-27 12:27:37 -04:00
|
|
|
S: ?Sized + AsRef<[u8]>,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
|
|
|
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>;
|
|
|
|
|
|
|
|
/// Add a metamethod which accepts a `&T` as the first parameter.
|
|
|
|
///
|
|
|
|
/// # Note
|
|
|
|
///
|
|
|
|
/// This can cause an error with certain binary metamethods that can trigger if only the right
|
|
|
|
/// side has a metatable. To prevent this, use [`add_meta_function`].
|
|
|
|
///
|
|
|
|
/// [`add_meta_function`]: #method.add_meta_function
|
|
|
|
fn add_meta_method<A, R, M>(&mut self, meta: MetaMethod, method: M)
|
|
|
|
where
|
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
|
|
|
M: 'static + Send + Fn(&'lua Lua, &T, A) -> Result<R>;
|
|
|
|
|
|
|
|
/// Add a metamethod as a function which accepts a `&mut T` as the first parameter.
|
|
|
|
///
|
|
|
|
/// # Note
|
|
|
|
///
|
|
|
|
/// This can cause an error with certain binary metamethods that can trigger if only the right
|
|
|
|
/// side has a metatable. To prevent this, use [`add_meta_function`].
|
|
|
|
///
|
|
|
|
/// [`add_meta_function`]: #method.add_meta_function
|
|
|
|
fn add_meta_method_mut<A, R, M>(&mut self, meta: MetaMethod, method: M)
|
|
|
|
where
|
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
|
|
|
M: 'static + Send + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
|
|
|
|
|
|
|
/// Add a metamethod which accepts generic arguments.
|
|
|
|
///
|
|
|
|
/// Metamethods for binary operators can be triggered if either the left or right argument to
|
|
|
|
/// the binary operator has a metatable, so the first argument here is not necessarily a
|
|
|
|
/// userdata of type `T`.
|
|
|
|
fn add_meta_function<A, R, F>(&mut self, meta: MetaMethod, function: F)
|
|
|
|
where
|
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
|
|
|
F: 'static + Send + Fn(&'lua Lua, A) -> Result<R>;
|
|
|
|
|
|
|
|
/// Add a metamethod as a mutable function which accepts generic arguments.
|
|
|
|
///
|
|
|
|
/// This is a version of [`add_meta_function`] that accepts a FnMut argument.
|
|
|
|
///
|
|
|
|
/// [`add_meta_function`]: #method.add_meta_function
|
|
|
|
fn add_meta_function_mut<A, R, F>(&mut self, meta: MetaMethod, function: F)
|
|
|
|
where
|
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
|
|
|
F: 'static + Send + FnMut(&'lua Lua, A) -> Result<R>;
|
|
|
|
}
|
2017-09-30 01:08:08 -04:00
|
|
|
|
|
|
|
/// Trait for custom userdata types.
|
|
|
|
///
|
|
|
|
/// By implementing this trait, a struct becomes eligible for use inside Lua code. Implementations
|
|
|
|
/// of [`ToLua`] and [`FromLua`] are automatically provided.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
2019-10-17 11:59:33 -04:00
|
|
|
/// # use mlua::{Lua, Result, UserData};
|
2019-09-27 12:27:37 -04:00
|
|
|
/// # fn main() -> Result<()> {
|
2019-10-17 11:59:33 -04:00
|
|
|
/// # let lua = Lua::new();
|
2017-09-30 01:08:08 -04:00
|
|
|
/// struct MyUserData(i32);
|
|
|
|
///
|
|
|
|
/// impl UserData for MyUserData {}
|
|
|
|
///
|
|
|
|
/// // `MyUserData` now implements `ToLua`:
|
|
|
|
/// lua.globals().set("myobject", MyUserData(123))?;
|
|
|
|
///
|
2019-10-17 11:59:33 -04:00
|
|
|
/// lua.load("assert(type(myobject) == 'userdata')").exec()?;
|
2017-09-30 01:08:08 -04:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Custom methods and operators can be provided by implementing `add_methods` (refer to
|
|
|
|
/// [`UserDataMethods`] for more information):
|
|
|
|
///
|
|
|
|
/// ```
|
2019-10-17 11:59:33 -04:00
|
|
|
/// # use mlua::{Lua, MetaMethod, Result, UserData, UserDataMethods};
|
2019-09-27 12:27:37 -04:00
|
|
|
/// # fn main() -> Result<()> {
|
2019-10-17 11:59:33 -04:00
|
|
|
/// # let lua = Lua::new();
|
2017-09-30 01:08:08 -04:00
|
|
|
/// struct MyUserData(i32);
|
|
|
|
///
|
|
|
|
/// impl UserData for MyUserData {
|
2018-09-04 03:40:13 -04:00
|
|
|
/// fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
2017-09-30 01:08:08 -04:00
|
|
|
/// methods.add_method("get", |_, this, _: ()| {
|
|
|
|
/// Ok(this.0)
|
|
|
|
/// });
|
|
|
|
///
|
|
|
|
/// methods.add_method_mut("add", |_, this, value: i32| {
|
|
|
|
/// this.0 += value;
|
|
|
|
/// Ok(())
|
|
|
|
/// });
|
|
|
|
///
|
|
|
|
/// methods.add_meta_method(MetaMethod::Add, |_, this, value: i32| {
|
|
|
|
/// Ok(this.0 + value)
|
|
|
|
/// });
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// lua.globals().set("myobject", MyUserData(123))?;
|
|
|
|
///
|
2019-10-17 11:59:33 -04:00
|
|
|
/// lua.load(r#"
|
2017-09-30 01:08:08 -04:00
|
|
|
/// assert(myobject:get() == 123)
|
|
|
|
/// myobject:add(7)
|
|
|
|
/// assert(myobject:get() == 130)
|
|
|
|
/// assert(myobject + 10 == 140)
|
2019-10-17 11:59:33 -04:00
|
|
|
/// "#).exec()?;
|
2017-09-30 01:08:08 -04:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// [`ToLua`]: trait.ToLua.html
|
|
|
|
/// [`FromLua`]: trait.FromLua.html
|
2018-09-04 03:40:13 -04:00
|
|
|
/// [`UserDataMethods`]: trait.UserDataMethods.html
|
|
|
|
pub trait UserData: Sized {
|
2017-09-30 01:08:08 -04:00
|
|
|
/// Adds custom methods and operators specific to this userdata.
|
2018-09-04 03:40:13 -04:00
|
|
|
fn add_methods<'lua, T: UserDataMethods<'lua, Self>>(_methods: &mut T) {}
|
2017-09-30 01:08:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Handle to an internal Lua userdata for any type that implements [`UserData`].
|
|
|
|
///
|
|
|
|
/// Similar to `std::any::Any`, this provides an interface for dynamic type checking via the [`is`]
|
|
|
|
/// and [`borrow`] methods.
|
|
|
|
///
|
|
|
|
/// Internally, instances are stored in a `RefCell`, to best match the mutable semantics of the Lua
|
|
|
|
/// language.
|
|
|
|
///
|
|
|
|
/// # Note
|
|
|
|
///
|
|
|
|
/// This API should only be used when necessary. Implementing [`UserData`] already allows defining
|
|
|
|
/// methods which check the type and acquire a borrow behind the scenes.
|
|
|
|
///
|
|
|
|
/// [`UserData`]: trait.UserData.html
|
|
|
|
/// [`is`]: #method.is
|
|
|
|
/// [`borrow`]: #method.borrow
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct AnyUserData<'lua>(pub(crate) LuaRef<'lua>);
|
|
|
|
|
|
|
|
impl<'lua> AnyUserData<'lua> {
|
|
|
|
/// Checks whether the type of this userdata is `T`.
|
2018-09-04 03:40:13 -04:00
|
|
|
pub fn is<T: 'static + UserData>(&self) -> bool {
|
2017-12-03 23:45:00 -05:00
|
|
|
match self.inspect(|_: &RefCell<T>| Ok(())) {
|
2018-09-04 03:40:13 -04:00
|
|
|
Ok(()) => true,
|
|
|
|
Err(Error::UserDataTypeMismatch) => false,
|
|
|
|
Err(_) => unreachable!(),
|
2017-12-03 23:45:00 -05:00
|
|
|
}
|
2017-09-30 01:08:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Borrow this userdata immutably if it is of type `T`.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// Returns a `UserDataBorrowError` if the userdata is already mutably borrowed. Returns a
|
|
|
|
/// `UserDataTypeMismatch` if the userdata is not of type `T`.
|
2018-09-04 03:40:13 -04:00
|
|
|
pub fn borrow<T: 'static + UserData>(&self) -> Result<Ref<T>> {
|
2017-12-03 18:25:53 -05:00
|
|
|
self.inspect(|cell| Ok(cell.try_borrow().map_err(|_| Error::UserDataBorrowError)?))
|
2017-09-30 01:08:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Borrow this userdata mutably if it is of type `T`.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// Returns a `UserDataBorrowMutError` if the userdata is already borrowed. Returns a
|
|
|
|
/// `UserDataTypeMismatch` if the userdata is not of type `T`.
|
2018-09-04 03:40:13 -04:00
|
|
|
pub fn borrow_mut<T: 'static + UserData>(&self) -> Result<RefMut<T>> {
|
2017-09-30 01:08:08 -04:00
|
|
|
self.inspect(|cell| {
|
2018-08-05 09:51:39 -04:00
|
|
|
Ok(cell
|
|
|
|
.try_borrow_mut()
|
2017-10-23 16:42:20 -04:00
|
|
|
.map_err(|_| Error::UserDataBorrowMutError)?)
|
2017-12-03 23:45:00 -05:00
|
|
|
})
|
2017-09-30 01:08:08 -04:00
|
|
|
}
|
|
|
|
|
2018-03-19 15:16:40 -04:00
|
|
|
/// Sets an associated value to this `AnyUserData`.
|
|
|
|
///
|
|
|
|
/// The value may be any Lua value whatsoever, and can be retrieved with [`get_user_value`].
|
|
|
|
///
|
|
|
|
/// [`get_user_value`]: #method.get_user_value
|
|
|
|
pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> {
|
|
|
|
let lua = self.0.lua;
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
2019-10-14 17:21:30 -04:00
|
|
|
let v = {
|
2019-11-29 08:26:30 -05:00
|
|
|
// Lua 5.2/5.1 allows to store only table. Then we will wrap the value.
|
2019-10-14 17:21:30 -04:00
|
|
|
let t = lua.create_table()?;
|
|
|
|
t.raw_set(1, v)?;
|
|
|
|
crate::Value::Table(t)
|
|
|
|
};
|
|
|
|
#[cfg(feature = "lua53")]
|
2018-03-19 15:16:40 -04:00
|
|
|
let v = v.to_lua(lua)?;
|
|
|
|
unsafe {
|
|
|
|
let _sg = StackGuard::new(lua.state);
|
2018-03-19 15:26:21 -04:00
|
|
|
assert_stack(lua.state, 2);
|
2018-03-19 15:16:40 -04:00
|
|
|
lua.push_ref(&self.0);
|
2019-09-27 12:27:37 -04:00
|
|
|
lua.push_value(v)?;
|
2018-03-19 15:16:40 -04:00
|
|
|
ffi::lua_setuservalue(lua.state, -2);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns an associated value set by [`set_user_value`].
|
|
|
|
///
|
|
|
|
/// [`set_user_value`]: #method.set_user_value
|
|
|
|
pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
|
|
|
|
let lua = self.0.lua;
|
|
|
|
let res = unsafe {
|
|
|
|
let _sg = StackGuard::new(lua.state);
|
2018-03-19 15:26:21 -04:00
|
|
|
assert_stack(lua.state, 3);
|
2018-03-19 15:16:40 -04:00
|
|
|
lua.push_ref(&self.0);
|
|
|
|
ffi::lua_getuservalue(lua.state, -1);
|
|
|
|
lua.pop_value()
|
|
|
|
};
|
2019-11-29 08:26:30 -05:00
|
|
|
#[cfg(any(feature = "lua52", feature = "lua51", feature = "luajit"))]
|
2019-10-14 17:21:30 -04:00
|
|
|
return crate::Table::from_lua(res, lua)?.get(1);
|
|
|
|
#[cfg(feature = "lua53")]
|
2018-03-19 15:16:40 -04:00
|
|
|
V::from_lua(res, lua)
|
|
|
|
}
|
|
|
|
|
2017-12-03 23:45:00 -05:00
|
|
|
fn inspect<'a, T, R, F>(&'a self, func: F) -> Result<R>
|
2017-09-30 01:08:08 -04:00
|
|
|
where
|
2018-09-04 03:40:13 -04:00
|
|
|
T: 'static + UserData,
|
2017-12-03 23:45:00 -05:00
|
|
|
F: FnOnce(&'a RefCell<T>) -> Result<R>,
|
2017-09-30 01:08:08 -04:00
|
|
|
{
|
|
|
|
unsafe {
|
|
|
|
let lua = self.0.lua;
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(lua.state);
|
2018-03-19 15:26:21 -04:00
|
|
|
assert_stack(lua.state, 3);
|
2017-09-30 01:08:08 -04:00
|
|
|
|
2018-03-12 13:13:44 -04:00
|
|
|
lua.push_ref(&self.0);
|
2017-09-30 01:08:08 -04:00
|
|
|
|
2018-03-12 17:48:05 -04:00
|
|
|
if ffi::lua_getmetatable(lua.state, -1) == 0 {
|
2018-03-12 13:13:44 -04:00
|
|
|
Err(Error::UserDataTypeMismatch)
|
|
|
|
} else {
|
2018-03-12 17:48:05 -04:00
|
|
|
ffi::lua_rawgeti(
|
|
|
|
lua.state,
|
|
|
|
ffi::LUA_REGISTRYINDEX,
|
|
|
|
lua.userdata_metatable::<T>()? as ffi::lua_Integer,
|
|
|
|
);
|
|
|
|
|
|
|
|
if ffi::lua_rawequal(lua.state, -1, -2) == 0 {
|
|
|
|
Err(Error::UserDataTypeMismatch)
|
|
|
|
} else {
|
|
|
|
func(&*get_userdata::<RefCell<T>>(lua.state, -3))
|
|
|
|
}
|
2018-03-12 13:13:44 -04:00
|
|
|
}
|
2017-09-30 01:08:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|