2021-05-31 18:33:44 -04:00
|
|
|
use std::any::TypeId;
|
2021-04-27 13:31:57 -04:00
|
|
|
use std::cell::{Ref, RefCell, RefMut};
|
2021-02-19 06:48:56 -05:00
|
|
|
use std::fmt;
|
|
|
|
use std::hash::{Hash, Hasher};
|
2021-05-31 18:33:44 -04:00
|
|
|
use std::ops::{Deref, DerefMut};
|
2021-02-19 06:48:56 -05:00
|
|
|
use std::string::String as StdString;
|
2017-09-30 01:08:08 -04:00
|
|
|
|
2020-04-17 17:38:01 -04:00
|
|
|
#[cfg(feature = "async")]
|
|
|
|
use std::future::Future;
|
|
|
|
|
2020-12-12 15:37:17 -05:00
|
|
|
#[cfg(feature = "serialize")]
|
|
|
|
use {
|
|
|
|
serde::ser::{self, Serialize, Serializer},
|
|
|
|
std::result::Result as StdResult,
|
|
|
|
};
|
|
|
|
|
2019-09-27 12:27:37 -04:00
|
|
|
use crate::error::{Error, Result};
|
|
|
|
use crate::ffi;
|
2020-01-06 18:59:50 -05:00
|
|
|
use crate::function::Function;
|
2019-09-27 12:27:37 -04:00
|
|
|
use crate::lua::Lua;
|
2021-02-19 06:48:56 -05:00
|
|
|
use crate::table::{Table, TablePairs};
|
2021-05-31 18:33:44 -04:00
|
|
|
use crate::types::{Callback, LuaRef, MaybeSend};
|
2021-10-05 08:04:43 -04:00
|
|
|
use crate::util::{check_stack, get_userdata, take_userdata, StackGuard};
|
2021-05-05 06:11:32 -04:00
|
|
|
use crate::value::{FromLua, FromLuaMulti, ToLua, ToLuaMulti};
|
|
|
|
|
2021-11-08 16:16:31 -05:00
|
|
|
#[cfg(feature = "lua54")]
|
|
|
|
use std::os::raw::c_int;
|
2018-09-04 19:05:21 -04:00
|
|
|
|
2021-05-31 18:33:44 -04:00
|
|
|
#[cfg(feature = "async")]
|
|
|
|
use crate::types::AsyncCallback;
|
|
|
|
|
2021-11-08 16:16:31 -05:00
|
|
|
#[cfg(feature = "lua54")]
|
|
|
|
pub(crate) const USER_VALUE_MAXSLOT: usize = 8;
|
|
|
|
|
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`.
|
|
|
|
///
|
2021-10-11 17:43:33 -04:00
|
|
|
/// [`UserData`]: crate::UserData
|
2021-02-19 06:48:56 -05:00
|
|
|
#[derive(Debug, Clone)]
|
2018-09-04 19:05:21 -04:00
|
|
|
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,
|
|
|
|
/// The floor division (//) operator.
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "lua54/lua53"`
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
2018-09-04 19:05:21 -04:00
|
|
|
IDiv,
|
|
|
|
/// The bitwise AND (&) operator.
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "lua54/lua53"`
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
2018-09-04 19:05:21 -04:00
|
|
|
BAnd,
|
|
|
|
/// The bitwise OR (|) operator.
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "lua54/lua53"`
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
2018-09-04 19:05:21 -04:00
|
|
|
BOr,
|
|
|
|
/// The bitwise XOR (binary ~) operator.
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "lua54/lua53"`
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
2018-09-04 19:05:21 -04:00
|
|
|
BXor,
|
|
|
|
/// The bitwise NOT (unary ~) operator.
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "lua54/lua53"`
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
2018-09-04 19:05:21 -04:00
|
|
|
BNot,
|
|
|
|
/// The bitwise left shift (<<) operator.
|
2020-05-13 21:12:22 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
2018-09-04 19:05:21 -04:00
|
|
|
Shl,
|
|
|
|
/// The bitwise right shift (>>) operator.
|
2020-05-13 21:12:22 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53", doc))]
|
2018-09-04 19:05:21 -04:00
|
|
|
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,
|
2019-11-29 19:52:31 -05:00
|
|
|
/// The `__pairs` metamethod.
|
|
|
|
///
|
|
|
|
/// This is not an operator, but it will be called by the built-in `pairs` function.
|
2020-05-13 21:12:22 -04:00
|
|
|
///
|
|
|
|
/// Requires `feature = "lua54/lua53/lua52"`
|
2021-11-04 08:25:20 -04:00
|
|
|
#[cfg(any(
|
|
|
|
feature = "lua54",
|
|
|
|
feature = "lua53",
|
|
|
|
feature = "lua52",
|
|
|
|
feature = "luajit52",
|
|
|
|
doc
|
|
|
|
))]
|
2019-11-29 19:52:31 -05:00
|
|
|
Pairs,
|
2021-06-03 13:43:29 -04:00
|
|
|
/// The `__ipairs` metamethod.
|
|
|
|
///
|
|
|
|
/// This is not an operator, but it will be called by the built-in [`ipairs`] function.
|
|
|
|
///
|
|
|
|
/// Requires `feature = "lua52"`
|
|
|
|
///
|
|
|
|
/// [`ipairs`]: https://www.lua.org/manual/5.2/manual.html#pdf-ipairs
|
2021-11-04 08:25:20 -04:00
|
|
|
#[cfg(any(feature = "lua52", feature = "luajit52", doc))]
|
2021-06-03 13:43:29 -04:00
|
|
|
IPairs,
|
2020-05-09 06:24:31 -04:00
|
|
|
/// The `__close` metamethod.
|
|
|
|
///
|
|
|
|
/// Executed when a variable, that marked as to-be-closed, goes out of scope.
|
|
|
|
///
|
|
|
|
/// More information about to-be-closed variabled can be found in the Lua 5.4
|
|
|
|
/// [documentation][lua_doc].
|
|
|
|
///
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "lua54"`
|
|
|
|
///
|
2020-05-09 06:24:31 -04:00
|
|
|
/// [lua_doc]: https://www.lua.org/manual/5.4/manual.html#3.3.8
|
2020-05-13 21:12:22 -04:00
|
|
|
#[cfg(any(feature = "lua54", doc))]
|
2020-05-09 06:24:31 -04:00
|
|
|
Close,
|
2021-02-19 06:48:56 -05:00
|
|
|
/// A custom metamethod.
|
|
|
|
///
|
2021-05-02 05:38:33 -04:00
|
|
|
/// Must not be in the protected list: `__gc`, `__metatable`, `__mlua*`.
|
2021-02-19 06:48:56 -05:00
|
|
|
Custom(StdString),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for MetaMethod {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.name() == other.name()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Eq for MetaMethod {}
|
|
|
|
|
|
|
|
impl Hash for MetaMethod {
|
|
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
|
|
self.name().hash(state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for MetaMethod {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
write!(fmt, "{}", self.name())
|
|
|
|
}
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl MetaMethod {
|
2021-02-20 17:42:09 -05:00
|
|
|
/// Returns Lua metamethod name, usually prefixed by two underscores.
|
|
|
|
pub fn name(&self) -> &str {
|
2018-09-04 19:05:21 -04:00
|
|
|
match self {
|
2021-02-19 06:48:56 -05:00
|
|
|
MetaMethod::Add => "__add",
|
|
|
|
MetaMethod::Sub => "__sub",
|
|
|
|
MetaMethod::Mul => "__mul",
|
|
|
|
MetaMethod::Div => "__div",
|
|
|
|
MetaMethod::Mod => "__mod",
|
|
|
|
MetaMethod::Pow => "__pow",
|
|
|
|
MetaMethod::Unm => "__unm",
|
2020-05-09 06:24:31 -04:00
|
|
|
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
2021-02-19 06:48:56 -05:00
|
|
|
MetaMethod::IDiv => "__idiv",
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
2021-02-19 06:48:56 -05:00
|
|
|
MetaMethod::BAnd => "__band",
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
2021-02-19 06:48:56 -05:00
|
|
|
MetaMethod::BOr => "__bor",
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
2021-02-19 06:48:56 -05:00
|
|
|
MetaMethod::BXor => "__bxor",
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
2021-02-19 06:48:56 -05:00
|
|
|
MetaMethod::BNot => "__bnot",
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
2021-02-19 06:48:56 -05:00
|
|
|
MetaMethod::Shl => "__shl",
|
2020-05-08 07:42:40 -04:00
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
2021-02-19 06:48:56 -05:00
|
|
|
MetaMethod::Shr => "__shr",
|
|
|
|
|
|
|
|
MetaMethod::Concat => "__concat",
|
|
|
|
MetaMethod::Len => "__len",
|
|
|
|
MetaMethod::Eq => "__eq",
|
|
|
|
MetaMethod::Lt => "__lt",
|
|
|
|
MetaMethod::Le => "__le",
|
|
|
|
MetaMethod::Index => "__index",
|
|
|
|
MetaMethod::NewIndex => "__newindex",
|
|
|
|
MetaMethod::Call => "__call",
|
|
|
|
MetaMethod::ToString => "__tostring",
|
2020-05-09 06:24:31 -04:00
|
|
|
|
2021-11-04 08:25:20 -04:00
|
|
|
#[cfg(any(
|
|
|
|
feature = "lua54",
|
|
|
|
feature = "lua53",
|
|
|
|
feature = "lua52",
|
|
|
|
feature = "luajit52"
|
|
|
|
))]
|
2021-02-19 06:48:56 -05:00
|
|
|
MetaMethod::Pairs => "__pairs",
|
2021-11-04 08:25:20 -04:00
|
|
|
#[cfg(any(feature = "lua52", feature = "luajit52"))]
|
2021-06-03 13:43:29 -04:00
|
|
|
MetaMethod::IPairs => "__ipairs",
|
2020-05-09 06:24:31 -04:00
|
|
|
|
|
|
|
#[cfg(feature = "lua54")]
|
2021-02-19 06:48:56 -05:00
|
|
|
MetaMethod::Close => "__close",
|
|
|
|
|
|
|
|
MetaMethod::Custom(ref name) => name,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn validate(self) -> Result<Self> {
|
|
|
|
match self {
|
|
|
|
MetaMethod::Custom(name) if name == "__gc" => Err(Error::MetaMethodRestricted(name)),
|
|
|
|
MetaMethod::Custom(name) if name == "__metatable" => {
|
|
|
|
Err(Error::MetaMethodRestricted(name))
|
|
|
|
}
|
2021-03-13 15:01:25 -05:00
|
|
|
MetaMethod::Custom(name) if name.starts_with("__mlua") => {
|
|
|
|
Err(Error::MetaMethodRestricted(name))
|
|
|
|
}
|
2021-02-19 06:48:56 -05:00
|
|
|
_ => Ok(self),
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-19 06:48:56 -05:00
|
|
|
impl From<StdString> for MetaMethod {
|
|
|
|
fn from(name: StdString) -> Self {
|
|
|
|
match name.as_str() {
|
|
|
|
"__add" => MetaMethod::Add,
|
|
|
|
"__sub" => MetaMethod::Sub,
|
|
|
|
"__mul" => MetaMethod::Mul,
|
|
|
|
"__div" => MetaMethod::Div,
|
|
|
|
"__mod" => MetaMethod::Mod,
|
|
|
|
"__pow" => MetaMethod::Pow,
|
|
|
|
"__unm" => MetaMethod::Unm,
|
|
|
|
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
|
|
|
"__idiv" => MetaMethod::IDiv,
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
|
|
|
"__band" => MetaMethod::BAnd,
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
|
|
|
"__bor" => MetaMethod::BOr,
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
|
|
|
"__bxor" => MetaMethod::BXor,
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
|
|
|
"__bnot" => MetaMethod::BNot,
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
|
|
|
"__shl" => MetaMethod::Shl,
|
|
|
|
#[cfg(any(feature = "lua54", feature = "lua53"))]
|
|
|
|
"__shr" => MetaMethod::Shr,
|
|
|
|
|
|
|
|
"__concat" => MetaMethod::Concat,
|
|
|
|
"__len" => MetaMethod::Len,
|
|
|
|
"__eq" => MetaMethod::Eq,
|
|
|
|
"__lt" => MetaMethod::Lt,
|
|
|
|
"__le" => MetaMethod::Le,
|
|
|
|
"__index" => MetaMethod::Index,
|
|
|
|
"__newindex" => MetaMethod::NewIndex,
|
|
|
|
"__call" => MetaMethod::Call,
|
|
|
|
"__tostring" => MetaMethod::ToString,
|
|
|
|
|
2021-11-04 08:25:20 -04:00
|
|
|
#[cfg(any(
|
|
|
|
feature = "lua54",
|
|
|
|
feature = "lua53",
|
|
|
|
feature = "lua52",
|
|
|
|
feature = "luajit52"
|
|
|
|
))]
|
2021-02-19 06:48:56 -05:00
|
|
|
"__pairs" => MetaMethod::Pairs,
|
2021-11-04 08:25:20 -04:00
|
|
|
#[cfg(any(feature = "lua52", feature = "luajit52"))]
|
2021-06-03 13:43:29 -04:00
|
|
|
"__ipairs" => MetaMethod::IPairs,
|
2021-02-19 06:48:56 -05:00
|
|
|
|
|
|
|
#[cfg(feature = "lua54")]
|
|
|
|
"__close" => MetaMethod::Close,
|
|
|
|
|
|
|
|
_ => MetaMethod::Custom(name),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<&str> for MetaMethod {
|
|
|
|
fn from(name: &str) -> Self {
|
|
|
|
MetaMethod::from(name.to_owned())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-04 19:05:21 -04:00
|
|
|
/// Method registry for [`UserData`] implementors.
|
|
|
|
///
|
2021-10-11 17:43:33 -04:00
|
|
|
/// [`UserData`]: crate::UserData
|
2018-09-04 19:05:21 -04:00
|
|
|
pub trait UserDataMethods<'lua, T: UserData> {
|
2021-02-19 06:48:56 -05:00
|
|
|
/// Add a regular method which accepts a `&T` as the first parameter.
|
2018-09-04 19:05:21 -04:00
|
|
|
///
|
|
|
|
/// 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
|
2021-02-19 06:48:56 -05:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>;
|
2018-09-04 19:05:21 -04:00
|
|
|
|
|
|
|
/// 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
|
2021-02-19 06:48:56 -05:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
2020-04-17 17:38:01 -04:00
|
|
|
|
|
|
|
/// Add an async method which accepts a `T` as the first parameter and returns Future.
|
|
|
|
/// The passed `T` is cloned from the original value.
|
|
|
|
///
|
|
|
|
/// Refer to [`add_method`] for more information about the implementation.
|
|
|
|
///
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "async"`
|
|
|
|
///
|
2020-04-17 17:38:01 -04:00
|
|
|
/// [`add_method`]: #method.add_method
|
|
|
|
#[cfg(feature = "async")]
|
2020-12-29 20:43:00 -05:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
2020-04-17 17:38:01 -04:00
|
|
|
fn add_async_method<S, A, R, M, MR>(&mut self, name: &S, method: M)
|
|
|
|
where
|
|
|
|
T: Clone,
|
2021-02-19 06:48:56 -05:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2020-04-17 17:38:01 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
|
2020-05-05 08:03:28 -04:00
|
|
|
MR: 'lua + Future<Output = Result<R>>;
|
2018-09-04 19:05:21 -04:00
|
|
|
|
|
|
|
/// Add a regular method as a function which accepts generic arguments, the first argument will
|
2021-02-19 06:48:56 -05:00
|
|
|
/// be a [`AnyUserData`] of type `T` if the method is called with Lua method syntax:
|
2019-09-27 12:27:37 -04:00
|
|
|
/// `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.
|
|
|
|
///
|
2021-10-11 17:43:33 -04:00
|
|
|
/// [`AnyUserData`]: crate::AnyUserData
|
2018-09-04 19:05:21 -04:00
|
|
|
/// [`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
|
2021-02-19 06:48:56 -05:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>;
|
2018-09-04 19:05:21 -04:00
|
|
|
|
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
|
2021-02-19 06:48:56 -05:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>;
|
2020-04-17 17:38:01 -04:00
|
|
|
|
|
|
|
/// Add a regular method as an async function which accepts generic arguments
|
|
|
|
/// and returns Future.
|
|
|
|
///
|
|
|
|
/// This is an async version of [`add_function`].
|
|
|
|
///
|
2020-05-13 21:12:22 -04:00
|
|
|
/// Requires `feature = "async"`
|
|
|
|
///
|
2020-04-17 17:38:01 -04:00
|
|
|
/// [`add_function`]: #method.add_function
|
|
|
|
#[cfg(feature = "async")]
|
2020-12-29 20:43:00 -05:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
2020-04-17 17:38:01 -04:00
|
|
|
fn add_async_function<S, A, R, F, FR>(&mut self, name: &S, function: F)
|
|
|
|
where
|
2021-02-19 06:48:56 -05:00
|
|
|
S: AsRef<[u8]> + ?Sized,
|
2020-04-17 17:38:01 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
|
2020-05-05 08:03:28 -04:00
|
|
|
FR: 'lua + Future<Output = Result<R>>;
|
2018-09-04 19:05:21 -04:00
|
|
|
|
|
|
|
/// 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
|
2021-02-19 06:48:56 -05:00
|
|
|
fn add_meta_method<S, A, R, M>(&mut self, meta: S, method: M)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2021-02-19 06:48:56 -05:00
|
|
|
S: Into<MetaMethod>,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
M: 'static + MaybeSend + Fn(&'lua Lua, &T, A) -> Result<R>;
|
2018-09-04 19:05:21 -04:00
|
|
|
|
|
|
|
/// 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
|
2021-02-19 06:48:56 -05:00
|
|
|
fn add_meta_method_mut<S, A, R, M>(&mut self, meta: S, method: M)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2021-02-19 06:48:56 -05:00
|
|
|
S: Into<MetaMethod>,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<R>;
|
2018-09-04 19:05:21 -04:00
|
|
|
|
2021-09-25 19:37:32 -04:00
|
|
|
/// Add an async metamethod which accepts a `T` as the first parameter and returns Future.
|
|
|
|
/// The passed `T` is cloned from the original value.
|
|
|
|
///
|
|
|
|
/// This is an async version of [`add_meta_method`].
|
|
|
|
///
|
|
|
|
/// Requires `feature = "async"`
|
|
|
|
///
|
|
|
|
/// [`add_meta_method`]: #method.add_meta_method
|
|
|
|
#[cfg(all(feature = "async", not(feature = "lua51")))]
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
|
|
|
fn add_async_meta_method<S, A, R, M, MR>(&mut self, name: S, method: M)
|
|
|
|
where
|
|
|
|
T: Clone,
|
|
|
|
S: Into<MetaMethod>,
|
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
|
|
|
M: 'static + MaybeSend + Fn(&'lua Lua, T, A) -> MR,
|
|
|
|
MR: 'lua + Future<Output = Result<R>>;
|
|
|
|
|
2018-09-04 19:05:21 -04:00
|
|
|
/// 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`.
|
2021-02-19 06:48:56 -05:00
|
|
|
fn add_meta_function<S, A, R, F>(&mut self, meta: S, function: F)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2021-02-19 06:48:56 -05:00
|
|
|
S: Into<MetaMethod>,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> Result<R>;
|
2018-09-04 19:05:21 -04:00
|
|
|
|
|
|
|
/// 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
|
2021-02-19 06:48:56 -05:00
|
|
|
fn add_meta_function_mut<S, A, R, F>(&mut self, meta: S, function: F)
|
2018-09-04 19:05:21 -04:00
|
|
|
where
|
2021-02-19 06:48:56 -05:00
|
|
|
S: Into<MetaMethod>,
|
2018-09-04 19:05:21 -04:00
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
2020-05-06 08:18:04 -04:00
|
|
|
F: 'static + MaybeSend + FnMut(&'lua Lua, A) -> Result<R>;
|
2021-05-31 18:33:44 -04:00
|
|
|
|
2021-09-25 19:37:32 -04:00
|
|
|
/// Add a metamethod which accepts generic arguments and returns Future.
|
|
|
|
///
|
|
|
|
/// This is an async version of [`add_meta_function`].
|
|
|
|
///
|
|
|
|
/// Requires `feature = "async"`
|
|
|
|
///
|
|
|
|
/// [`add_meta_function`]: #method.add_meta_function
|
|
|
|
#[cfg(all(feature = "async", not(feature = "lua51")))]
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
|
|
|
|
fn add_async_meta_function<S, A, R, F, FR>(&mut self, name: S, function: F)
|
|
|
|
where
|
|
|
|
S: Into<MetaMethod>,
|
|
|
|
A: FromLuaMulti<'lua>,
|
|
|
|
R: ToLuaMulti<'lua>,
|
|
|
|
F: 'static + MaybeSend + Fn(&'lua Lua, A) -> FR,
|
|
|
|
FR: 'lua + Future<Output = Result<R>>;
|
|
|
|
|
2021-05-31 18:33:44 -04:00
|
|
|
//
|
|
|
|
// Below are internal methods used in generated code
|
|
|
|
//
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
fn add_callback(&mut self, _name: Vec<u8>, _callback: Callback<'lua, 'static>) {}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
fn add_async_callback(&mut self, _name: Vec<u8>, _callback: AsyncCallback<'lua, 'static>) {}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
fn add_meta_callback(&mut self, _meta: MetaMethod, _callback: Callback<'lua, 'static>) {}
|
2021-09-25 19:37:32 -04:00
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[cfg(feature = "async")]
|
|
|
|
fn add_async_meta_callback(
|
|
|
|
&mut self,
|
|
|
|
_meta: MetaMethod,
|
|
|
|
_callback: AsyncCallback<'lua, 'static>,
|
|
|
|
) {
|
|
|
|
}
|
2018-09-04 19:05:21 -04:00
|
|
|
}
|
2017-09-30 01:08:08 -04:00
|
|
|
|
2021-02-19 06:48:56 -05:00
|
|
|
/// Field registry for [`UserData`] implementors.
|
|
|
|
///
|
2021-10-11 17:43:33 -04:00
|
|
|
/// [`UserData`]: crate::UserData
|
2021-02-19 06:48:56 -05:00
|
|
|
pub trait UserDataFields<'lua, T: UserData> {
|
|
|
|
/// Add a regular field getter as a method which accepts a `&T` as the parameter.
|
|
|
|
///
|
|
|
|
/// Regular field getters are implemented by overriding the `__index` metamethod and returning the
|
|
|
|
/// accessed field. This allows them to be used with the expected `userdata.field` 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 field or method are found.
|
|
|
|
fn add_field_method_get<S, R, M>(&mut self, name: &S, method: M)
|
|
|
|
where
|
|
|
|
S: AsRef<[u8]> + ?Sized,
|
|
|
|
R: ToLua<'lua>,
|
|
|
|
M: 'static + MaybeSend + Fn(&'lua Lua, &T) -> Result<R>;
|
|
|
|
|
|
|
|
/// Add a regular field setter as a method which accepts a `&mut T` as the first parameter.
|
|
|
|
///
|
|
|
|
/// Regular field setters are implemented by overriding the `__newindex` metamethod and setting the
|
|
|
|
/// accessed field. This allows them to be used with the expected `userdata.field = value` syntax.
|
|
|
|
///
|
|
|
|
/// If `add_meta_method` is used to set the `__newindex` metamethod, the `__newindex` metamethod will
|
|
|
|
/// be used as a fall-back if no regular field is found.
|
|
|
|
fn add_field_method_set<S, A, M>(&mut self, name: &S, method: M)
|
|
|
|
where
|
|
|
|
S: AsRef<[u8]> + ?Sized,
|
|
|
|
A: FromLua<'lua>,
|
|
|
|
M: 'static + MaybeSend + FnMut(&'lua Lua, &mut T, A) -> Result<()>;
|
|
|
|
|
|
|
|
/// Add a regular field getter as a function which accepts a generic [`AnyUserData`] of type `T`
|
|
|
|
/// argument.
|
|
|
|
///
|
|
|
|
/// Prefer to use [`add_field_method_get`] as it is easier to use.
|
|
|
|
///
|
2021-10-11 17:43:33 -04:00
|
|
|
/// [`AnyUserData`]: crate::AnyUserData
|
2021-02-19 06:48:56 -05:00
|
|
|
/// [`add_field_method_get`]: #method.add_field_method_get
|
|
|
|
fn add_field_function_get<S, R, F>(&mut self, name: &S, function: F)
|
|
|
|
where
|
|
|
|
S: AsRef<[u8]> + ?Sized,
|
|
|
|
R: ToLua<'lua>,
|
|
|
|
F: 'static + MaybeSend + Fn(&'lua Lua, AnyUserData<'lua>) -> Result<R>;
|
|
|
|
|
|
|
|
/// Add a regular field setter as a function which accepts a generic [`AnyUserData`] of type `T`
|
|
|
|
/// first argument.
|
|
|
|
///
|
|
|
|
/// Prefer to use [`add_field_method_set`] as it is easier to use.
|
|
|
|
///
|
2021-10-11 17:43:33 -04:00
|
|
|
/// [`AnyUserData`]: crate::AnyUserData
|
2021-02-19 06:48:56 -05:00
|
|
|
/// [`add_field_method_set`]: #method.add_field_method_set
|
|
|
|
fn add_field_function_set<S, A, F>(&mut self, name: &S, function: F)
|
|
|
|
where
|
|
|
|
S: AsRef<[u8]> + ?Sized,
|
|
|
|
A: FromLua<'lua>,
|
|
|
|
F: 'static + MaybeSend + FnMut(&'lua Lua, AnyUserData<'lua>, A) -> Result<()>;
|
|
|
|
|
|
|
|
/// Add a metamethod value computed from `f`.
|
|
|
|
///
|
|
|
|
/// This will initialize the metamethod value from `f` on `UserData` creation.
|
|
|
|
///
|
|
|
|
/// # Note
|
|
|
|
///
|
|
|
|
/// `mlua` will trigger an error on an attempt to define a protected metamethod,
|
|
|
|
/// like `__gc` or `__metatable`.
|
|
|
|
fn add_meta_field_with<S, R, F>(&mut self, meta: S, f: F)
|
|
|
|
where
|
|
|
|
S: Into<MetaMethod>,
|
|
|
|
F: 'static + MaybeSend + Fn(&'lua Lua) -> Result<R>,
|
|
|
|
R: ToLua<'lua>;
|
2021-05-31 18:33:44 -04:00
|
|
|
|
|
|
|
//
|
|
|
|
// Below are internal methods used in generated code
|
|
|
|
//
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
fn add_field_getter(&mut self, _name: Vec<u8>, _callback: Callback<'lua, 'static>) {}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
fn add_field_setter(&mut self, _name: Vec<u8>, _callback: Callback<'lua, 'static>) {}
|
2021-02-19 06:48:56 -05:00
|
|
|
}
|
|
|
|
|
2017-09-30 01:08:08 -04:00
|
|
|
/// Trait for custom userdata types.
|
|
|
|
///
|
2021-08-04 07:12:02 -04:00
|
|
|
/// By implementing this trait, a struct becomes eligible for use inside Lua code.
|
|
|
|
/// Implementation of [`ToLua`] is automatically provided, [`FromLua`] is implemented
|
|
|
|
/// only for `T: UserData + Clone`.
|
|
|
|
///
|
2017-09-30 01:08:08 -04:00
|
|
|
///
|
|
|
|
/// # 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(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
2021-02-19 06:48:56 -05:00
|
|
|
/// Custom fields, methods and operators can be provided by implementing `add_fields` or `add_methods`
|
|
|
|
/// (refer to [`UserDataFields`] and [`UserDataMethods`] for more information):
|
2017-09-30 01:08:08 -04:00
|
|
|
///
|
|
|
|
/// ```
|
2021-02-19 06:48:56 -05:00
|
|
|
/// # use mlua::{Lua, MetaMethod, Result, UserData, UserDataFields, 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 {
|
2021-02-19 06:48:56 -05:00
|
|
|
/// fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
|
|
|
|
/// fields.add_field_method_get("val", |_, this| Ok(this.0));
|
|
|
|
/// }
|
2017-09-30 01:08:08 -04:00
|
|
|
///
|
2021-02-19 06:48:56 -05:00
|
|
|
/// fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
2017-09-30 01:08:08 -04:00
|
|
|
/// 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#"
|
2021-02-19 06:48:56 -05:00
|
|
|
/// assert(myobject.val == 123)
|
2017-09-30 01:08:08 -04:00
|
|
|
/// myobject:add(7)
|
2021-02-19 06:48:56 -05:00
|
|
|
/// assert(myobject.val == 130)
|
2017-09-30 01:08:08 -04:00
|
|
|
/// assert(myobject + 10 == 140)
|
2019-10-17 11:59:33 -04:00
|
|
|
/// "#).exec()?;
|
2017-09-30 01:08:08 -04:00
|
|
|
/// # Ok(())
|
|
|
|
/// # }
|
|
|
|
/// ```
|
|
|
|
///
|
2021-10-11 17:43:33 -04:00
|
|
|
/// [`ToLua`]: crate::ToLua
|
|
|
|
/// [`FromLua`]: crate::FromLua
|
|
|
|
/// [`UserDataFields`]: crate::UserDataFields
|
|
|
|
/// [`UserDataMethods`]: crate::UserDataMethods
|
2018-09-04 03:40:13 -04:00
|
|
|
pub trait UserData: Sized {
|
2021-02-19 06:48:56 -05:00
|
|
|
/// Adds custom fields specific to this userdata.
|
|
|
|
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(_fields: &mut F) {}
|
|
|
|
|
2017-09-30 01:08:08 -04:00
|
|
|
/// Adds custom methods and operators specific to this userdata.
|
2020-04-17 17:38:01 -04:00
|
|
|
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) {}
|
2017-09-30 01:08:08 -04:00
|
|
|
}
|
|
|
|
|
2021-05-02 05:38:33 -04:00
|
|
|
// Wraps UserData in a way to always implement `serde::Serialize` trait.
|
2021-05-31 18:33:44 -04:00
|
|
|
pub(crate) struct UserDataCell<T>(RefCell<UserDataWrapped<T>>);
|
2020-12-12 15:37:17 -05:00
|
|
|
|
2021-04-27 13:31:57 -04:00
|
|
|
impl<T> UserDataCell<T> {
|
2021-09-20 07:38:08 -04:00
|
|
|
#[inline]
|
2021-04-27 13:31:57 -04:00
|
|
|
pub(crate) fn new(data: T) -> Self {
|
2021-05-31 18:33:44 -04:00
|
|
|
UserDataCell(RefCell::new(UserDataWrapped::new(data)))
|
2020-12-12 15:37:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "serialize")]
|
2021-09-20 07:38:08 -04:00
|
|
|
#[inline]
|
2020-12-12 15:37:17 -05:00
|
|
|
pub(crate) fn new_ser(data: T) -> Self
|
|
|
|
where
|
|
|
|
T: 'static + Serialize,
|
|
|
|
{
|
2021-05-31 18:33:44 -04:00
|
|
|
UserDataCell(RefCell::new(UserDataWrapped::new_ser(data)))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Immutably borrows the wrapped value.
|
2021-09-20 07:38:08 -04:00
|
|
|
#[inline]
|
2021-09-25 20:05:37 -04:00
|
|
|
pub(crate) fn try_borrow(&self) -> Result<Ref<T>> {
|
2021-05-31 18:33:44 -04:00
|
|
|
self.0
|
|
|
|
.try_borrow()
|
2021-07-13 05:53:10 -04:00
|
|
|
.map(|r| Ref::map(r, |r| r.deref()))
|
2021-05-31 18:33:44 -04:00
|
|
|
.map_err(|_| Error::UserDataBorrowError)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mutably borrows the wrapped value.
|
2021-09-20 07:38:08 -04:00
|
|
|
#[inline]
|
2021-09-25 20:05:37 -04:00
|
|
|
pub(crate) fn try_borrow_mut(&self) -> Result<RefMut<T>> {
|
2021-05-31 18:33:44 -04:00
|
|
|
self.0
|
|
|
|
.try_borrow_mut()
|
2021-07-13 05:53:10 -04:00
|
|
|
.map(|r| RefMut::map(r, |r| r.deref_mut()))
|
2021-05-31 18:33:44 -04:00
|
|
|
.map_err(|_| Error::UserDataBorrowMutError)
|
|
|
|
}
|
2021-10-05 08:04:43 -04:00
|
|
|
|
|
|
|
// Consumes this `UserDataCell`, returning the wrapped value.
|
|
|
|
#[inline]
|
|
|
|
fn into_inner(self) -> T {
|
|
|
|
self.0.into_inner().into_inner()
|
|
|
|
}
|
2021-05-31 18:33:44 -04:00
|
|
|
}
|
|
|
|
|
2021-07-10 17:45:32 -04:00
|
|
|
pub(crate) enum UserDataWrapped<T> {
|
2021-10-05 08:04:43 -04:00
|
|
|
Default(Box<T>),
|
2021-04-27 13:31:57 -04:00
|
|
|
#[cfg(feature = "serialize")]
|
2021-10-05 08:04:43 -04:00
|
|
|
Serializable(Box<dyn erased_serde::Serialize>),
|
2021-04-27 13:31:57 -04:00
|
|
|
}
|
|
|
|
|
2021-05-31 18:33:44 -04:00
|
|
|
impl<T> UserDataWrapped<T> {
|
2021-09-20 07:38:08 -04:00
|
|
|
#[inline]
|
2021-05-31 18:33:44 -04:00
|
|
|
fn new(data: T) -> Self {
|
2021-10-05 08:04:43 -04:00
|
|
|
UserDataWrapped::Default(Box::new(data))
|
2021-05-31 18:33:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "serialize")]
|
2021-09-20 07:38:08 -04:00
|
|
|
#[inline]
|
2021-05-31 18:33:44 -04:00
|
|
|
fn new_ser(data: T) -> Self
|
|
|
|
where
|
|
|
|
T: 'static + Serialize,
|
|
|
|
{
|
2021-10-05 08:04:43 -04:00
|
|
|
UserDataWrapped::Serializable(Box::new(data))
|
2021-05-31 18:33:44 -04:00
|
|
|
}
|
|
|
|
|
2021-10-05 08:04:43 -04:00
|
|
|
#[inline]
|
|
|
|
fn into_inner(self) -> T {
|
|
|
|
match self {
|
|
|
|
Self::Default(data) => *data,
|
|
|
|
#[cfg(feature = "serialize")]
|
|
|
|
Self::Serializable(data) => unsafe { *Box::from_raw(Box::into_raw(data) as *mut T) },
|
2020-12-12 15:37:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-31 18:33:44 -04:00
|
|
|
impl<T> Deref for UserDataWrapped<T> {
|
|
|
|
type Target = T;
|
|
|
|
|
2021-09-20 07:38:08 -04:00
|
|
|
#[inline]
|
2021-05-31 18:33:44 -04:00
|
|
|
fn deref(&self) -> &Self::Target {
|
2021-07-10 17:45:32 -04:00
|
|
|
match self {
|
|
|
|
Self::Default(data) => data,
|
|
|
|
#[cfg(feature = "serialize")]
|
2021-10-05 08:04:43 -04:00
|
|
|
Self::Serializable(data) => unsafe {
|
|
|
|
&*(data.as_ref() as *const _ as *const Self::Target)
|
|
|
|
},
|
2021-07-10 17:45:32 -04:00
|
|
|
}
|
2020-12-12 15:37:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-31 18:33:44 -04:00
|
|
|
impl<T> DerefMut for UserDataWrapped<T> {
|
2021-09-20 07:38:08 -04:00
|
|
|
#[inline]
|
2021-05-31 18:33:44 -04:00
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
2021-07-10 17:45:32 -04:00
|
|
|
match self {
|
|
|
|
Self::Default(data) => data,
|
|
|
|
#[cfg(feature = "serialize")]
|
2021-10-05 08:04:43 -04:00
|
|
|
Self::Serializable(data) => unsafe {
|
|
|
|
&mut *(data.as_mut() as *mut _ as *mut Self::Target)
|
|
|
|
},
|
2021-07-10 17:45:32 -04:00
|
|
|
}
|
2020-12-12 15:37:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "serialize")]
|
2021-05-31 18:33:44 -04:00
|
|
|
struct UserDataSerializeError;
|
2020-12-12 15:37:17 -05:00
|
|
|
|
|
|
|
#[cfg(feature = "serialize")]
|
|
|
|
impl Serialize for UserDataSerializeError {
|
|
|
|
fn serialize<S>(&self, _serializer: S) -> StdResult<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
|
|
|
Err(ser::Error::custom("cannot serialize <userdata>"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
///
|
2021-10-11 17:43:33 -04:00
|
|
|
/// [`UserData`]: crate::UserData
|
|
|
|
/// [`is`]: crate::AnyUserData::is
|
|
|
|
/// [`borrow`]: crate::AnyUserData::borrow
|
2017-09-30 01:08:08 -04:00
|
|
|
#[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 {
|
2020-12-12 15:37:17 -05:00
|
|
|
match self.inspect(|_: &UserDataCell<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`.
|
2021-09-20 07:38:08 -04:00
|
|
|
#[inline]
|
2021-07-13 05:53:10 -04:00
|
|
|
pub fn borrow<T: 'static + UserData>(&self) -> Result<Ref<T>> {
|
2021-05-31 18:33:44 -04:00
|
|
|
self.inspect(|cell| cell.try_borrow())
|
2017-09-30 01:08:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Borrow this userdata mutably if it is of type `T`.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
2021-05-31 18:33:44 -04:00
|
|
|
/// Returns a `UserDataBorrowMutError` if the userdata cannot be mutably borrowed.
|
|
|
|
/// Returns a `UserDataTypeMismatch` if the userdata is not of type `T`.
|
2021-09-20 07:38:08 -04:00
|
|
|
#[inline]
|
2021-07-13 05:53:10 -04:00
|
|
|
pub fn borrow_mut<T: 'static + UserData>(&self) -> Result<RefMut<T>> {
|
2021-05-31 18:33:44 -04:00
|
|
|
self.inspect(|cell| cell.try_borrow_mut())
|
2017-09-30 01:08:08 -04:00
|
|
|
}
|
|
|
|
|
2021-10-05 08:04:43 -04:00
|
|
|
/// Takes out the value of `UserData` and sets the special "destructed" metatable that prevents
|
|
|
|
/// any further operations with this userdata.
|
2021-11-08 16:16:31 -05:00
|
|
|
///
|
|
|
|
/// All associated user values will be also cleared.
|
2021-10-05 08:04:43 -04:00
|
|
|
pub fn take<T: 'static + UserData>(&self) -> Result<T> {
|
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
|
|
|
let _sg = StackGuard::new(lua.state);
|
2021-11-08 16:16:31 -05:00
|
|
|
check_stack(lua.state, 3)?;
|
2021-10-05 08:04:43 -04:00
|
|
|
|
|
|
|
let type_id = lua.push_userdata_ref(&self.0)?;
|
|
|
|
match type_id {
|
|
|
|
Some(type_id) if type_id == TypeId::of::<T>() => {
|
|
|
|
// Try to borrow userdata exclusively
|
|
|
|
let _ = (*get_userdata::<UserDataCell<T>>(lua.state, -1)).try_borrow_mut()?;
|
|
|
|
|
2021-11-08 16:16:31 -05:00
|
|
|
// Clear associated user values
|
|
|
|
#[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_setuservalue(lua.state, -2);
|
|
|
|
}
|
2021-10-05 08:04:43 -04:00
|
|
|
#[cfg(any(feature = "lua51", feature = "luajit"))]
|
2021-11-08 16:16:31 -05:00
|
|
|
protect_lua!(lua.state, 1, 1, fn(state) {
|
|
|
|
ffi::lua_newtable(state);
|
|
|
|
ffi::lua_setuservalue(state, -2);
|
|
|
|
})?;
|
2021-10-05 08:04:43 -04:00
|
|
|
|
|
|
|
Ok(take_userdata::<UserDataCell<T>>(lua.state).into_inner())
|
|
|
|
}
|
|
|
|
_ => Err(Error::UserDataTypeMismatch),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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`].
|
2021-11-08 16:16:31 -05:00
|
|
|
///
|
|
|
|
/// This is the same as calling [`set_nth_user_value`] with `n` set to 1.
|
2018-03-19 15:16:40 -04:00
|
|
|
///
|
|
|
|
/// [`get_user_value`]: #method.get_user_value
|
2021-11-08 16:16:31 -05:00
|
|
|
/// [`set_nth_user_value`]: #method.set_nth_user_value
|
2018-03-19 15:16:40 -04:00
|
|
|
pub fn set_user_value<V: ToLua<'lua>>(&self, v: V) -> Result<()> {
|
2021-11-08 16:16:31 -05:00
|
|
|
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(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2018-03-19 15:16:40 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
unsafe {
|
|
|
|
let _sg = StackGuard::new(lua.state);
|
2021-11-08 16:16:31 -05:00
|
|
|
check_stack(lua.state, 5)?;
|
2021-05-02 05:38:33 -04:00
|
|
|
|
2021-09-25 20:05:37 -04:00
|
|
|
lua.push_userdata_ref(&self.0)?;
|
2021-11-08 16:16:31 -05:00
|
|
|
lua.push_value(v.to_lua(lua)?)?;
|
|
|
|
|
|
|
|
#[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);
|
|
|
|
})?;
|
2021-05-02 05:38:33 -04:00
|
|
|
|
2018-03-19 15:16:40 -04:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns an associated value set by [`set_user_value`].
|
|
|
|
///
|
2021-11-08 16:16:31 -05:00
|
|
|
/// This is the same as calling [`get_nth_user_value`] with `n` set to 1.
|
2020-05-08 07:42:40 -04:00
|
|
|
///
|
2018-03-19 15:16:40 -04:00
|
|
|
/// [`set_user_value`]: #method.set_user_value
|
2021-11-08 16:16:31 -05:00
|
|
|
/// [`get_nth_user_value`]: #method.get_nth_user_value
|
2018-03-19 15:16:40 -04:00
|
|
|
pub fn get_user_value<V: FromLua<'lua>>(&self) -> Result<V> {
|
2021-11-08 16:16:31 -05:00
|
|
|
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(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2018-03-19 15:16:40 -04:00
|
|
|
let lua = self.0.lua;
|
2021-11-08 16:16:31 -05:00
|
|
|
unsafe {
|
2018-03-19 15:16:40 -04:00
|
|
|
let _sg = StackGuard::new(lua.state);
|
2021-11-08 16:16:31 -05:00
|
|
|
check_stack(lua.state, 4)?;
|
2021-05-02 05:38:33 -04:00
|
|
|
|
2021-09-25 20:05:37 -04:00
|
|
|
lua.push_userdata_ref(&self.0)?;
|
2021-11-08 16:16:31 -05:00
|
|
|
|
|
|
|
#[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);
|
|
|
|
};
|
|
|
|
let getn = |n: usize| {
|
|
|
|
#[cfg(feature = "lua54")]
|
|
|
|
return n - USER_VALUE_MAXSLOT + 1;
|
|
|
|
#[cfg(not(feature = "lua54"))]
|
|
|
|
return n;
|
|
|
|
};
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
2018-03-19 15:16:40 -04:00
|
|
|
}
|
|
|
|
|
2021-02-19 06:48:56 -05:00
|
|
|
/// Returns a metatable of this `UserData`.
|
|
|
|
///
|
|
|
|
/// Returned [`UserDataMetatable`] object wraps the original metatable and
|
2021-05-10 14:53:38 -04:00
|
|
|
/// provides safe access to its methods.
|
2021-03-13 15:01:25 -05:00
|
|
|
///
|
|
|
|
/// For `T: UserData + 'static` returned metatable is shared among all instances of type `T`.
|
2021-02-19 06:48:56 -05:00
|
|
|
///
|
2021-10-11 17:43:33 -04:00
|
|
|
/// [`UserDataMetatable`]: crate::UserDataMetatable
|
2021-02-19 06:48:56 -05:00
|
|
|
pub fn get_metatable(&self) -> Result<UserDataMetatable<'lua>> {
|
|
|
|
self.get_raw_metatable().map(UserDataMetatable)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_raw_metatable(&self) -> Result<Table<'lua>> {
|
2020-01-06 18:59:50 -05:00
|
|
|
unsafe {
|
|
|
|
let lua = self.0.lua;
|
|
|
|
let _sg = StackGuard::new(lua.state);
|
2021-05-02 05:38:33 -04:00
|
|
|
check_stack(lua.state, 3)?;
|
2020-01-06 18:59:50 -05:00
|
|
|
|
2021-09-25 20:05:37 -04:00
|
|
|
lua.push_userdata_ref(&self.0)?;
|
2021-05-02 05:38:33 -04:00
|
|
|
ffi::lua_getmetatable(lua.state, -1); // Checked that non-empty on the previous call
|
2020-01-06 18:59:50 -05:00
|
|
|
Ok(Table(lua.pop_ref()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn equals<T: AsRef<Self>>(&self, other: T) -> Result<bool> {
|
|
|
|
let other = other.as_ref();
|
2021-02-19 06:48:56 -05:00
|
|
|
// Uses lua_rawequal() under the hood
|
2020-01-06 18:59:50 -05:00
|
|
|
if self == other {
|
|
|
|
return Ok(true);
|
|
|
|
}
|
|
|
|
|
2021-02-19 06:48:56 -05:00
|
|
|
let mt = self.get_raw_metatable()?;
|
|
|
|
if mt != other.get_raw_metatable()? {
|
2020-01-06 18:59:50 -05:00
|
|
|
return Ok(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
if mt.contains_key("__eq")? {
|
|
|
|
return mt
|
|
|
|
.get::<_, Function>("__eq")?
|
|
|
|
.call((self.clone(), other.clone()));
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
|
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,
|
2020-12-12 15:37:17 -05:00
|
|
|
F: FnOnce(&'a UserDataCell<T>) -> Result<R>,
|
2017-09-30 01:08:08 -04:00
|
|
|
{
|
2021-05-02 05:38:33 -04:00
|
|
|
let lua = self.0.lua;
|
2017-09-30 01:08:08 -04:00
|
|
|
unsafe {
|
2018-03-12 13:13:44 -04:00
|
|
|
let _sg = StackGuard::new(lua.state);
|
2021-09-25 20:05:37 -04:00
|
|
|
check_stack(lua.state, 2)?;
|
2017-09-30 01:08:08 -04:00
|
|
|
|
2021-09-25 20:05:37 -04:00
|
|
|
let type_id = lua.push_userdata_ref(&self.0)?;
|
|
|
|
match type_id {
|
|
|
|
Some(type_id) if type_id == TypeId::of::<T>() => {
|
|
|
|
func(&*get_userdata::<UserDataCell<T>>(lua.state, -1))
|
2018-03-12 17:48:05 -04:00
|
|
|
}
|
2021-09-25 20:05:37 -04:00
|
|
|
_ => Err(Error::UserDataTypeMismatch),
|
2018-03-12 13:13:44 -04:00
|
|
|
}
|
2017-09-30 01:08:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-06 18:59:50 -05:00
|
|
|
|
|
|
|
impl<'lua> PartialEq for AnyUserData<'lua> {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.0 == other.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'lua> AsRef<AnyUserData<'lua>> for AnyUserData<'lua> {
|
|
|
|
#[inline]
|
|
|
|
fn as_ref(&self) -> &Self {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
2020-12-12 15:37:17 -05:00
|
|
|
|
2021-02-19 06:48:56 -05:00
|
|
|
/// Handle to a `UserData` metatable.
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct UserDataMetatable<'lua>(pub(crate) Table<'lua>);
|
|
|
|
|
|
|
|
impl<'lua> UserDataMetatable<'lua> {
|
|
|
|
/// Gets the value associated to `key` from the metatable.
|
|
|
|
///
|
|
|
|
/// If no value is associated to `key`, returns the `Nil` value.
|
|
|
|
/// Access to restricted metamethods such as `__gc` or `__metatable` will cause an error.
|
|
|
|
pub fn get<K: Into<MetaMethod>, V: FromLua<'lua>>(&self, key: K) -> Result<V> {
|
|
|
|
self.0.raw_get(key.into().validate()?.name())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets a key-value pair in the metatable.
|
|
|
|
///
|
|
|
|
/// If the value is `Nil`, this will effectively remove the `key`.
|
|
|
|
/// Access to restricted metamethods such as `__gc` or `__metatable` will cause an error.
|
|
|
|
/// Setting `__index` or `__newindex` metamethods is also restricted because their values are cached
|
|
|
|
/// for `mlua` internal usage.
|
|
|
|
pub fn set<K: Into<MetaMethod>, V: ToLua<'lua>>(&self, key: K, value: V) -> Result<()> {
|
|
|
|
let key = key.into().validate()?;
|
|
|
|
// `__index` and `__newindex` cannot be changed in runtime, because values are cached
|
|
|
|
if key == MetaMethod::Index || key == MetaMethod::NewIndex {
|
|
|
|
return Err(Error::MetaMethodRestricted(key.to_string()));
|
|
|
|
}
|
|
|
|
self.0.raw_set(key.name(), value)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks whether the metatable contains a non-nil value for `key`.
|
|
|
|
pub fn contains<K: Into<MetaMethod>>(&self, key: K) -> Result<bool> {
|
|
|
|
self.0.contains_key(key.into().validate()?.name())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Consumes this metatable and returns an iterator over the pairs of the metatable.
|
|
|
|
///
|
|
|
|
/// The pairs are wrapped in a [`Result`], since they are lazily converted to `V` type.
|
|
|
|
///
|
2021-10-11 17:43:33 -04:00
|
|
|
/// [`Result`]: crate::Result
|
2021-02-20 17:42:09 -05:00
|
|
|
pub fn pairs<V: FromLua<'lua>>(self) -> UserDataMetatablePairs<'lua, V> {
|
2021-02-19 06:48:56 -05:00
|
|
|
UserDataMetatablePairs(self.0.pairs())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An iterator over the pairs of a [`UserData`] metatable.
|
|
|
|
///
|
|
|
|
/// It skips restricted metamethods, such as `__gc` or `__metatable`.
|
|
|
|
///
|
|
|
|
/// This struct is created by the [`UserDataMetatable::pairs`] method.
|
|
|
|
///
|
2021-10-11 17:43:33 -04:00
|
|
|
/// [`UserData`]: crate::UserData
|
|
|
|
/// [`UserDataMetatable::pairs`]: crate::UserDataMetatable::method.pairs
|
2021-02-19 06:48:56 -05:00
|
|
|
pub struct UserDataMetatablePairs<'lua, V>(TablePairs<'lua, StdString, V>);
|
|
|
|
|
|
|
|
impl<'lua, V> Iterator for UserDataMetatablePairs<'lua, V>
|
|
|
|
where
|
|
|
|
V: FromLua<'lua>,
|
|
|
|
{
|
|
|
|
type Item = Result<(MetaMethod, V)>;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
loop {
|
|
|
|
match self.0.next()? {
|
|
|
|
Ok((key, value)) => {
|
|
|
|
// Skip restricted metamethods
|
|
|
|
if let Ok(metamethod) = MetaMethod::from(key).validate() {
|
|
|
|
break Some(Ok((metamethod, value)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => break Some(Err(e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-12 15:37:17 -05:00
|
|
|
#[cfg(feature = "serialize")]
|
|
|
|
impl<'lua> Serialize for AnyUserData<'lua> {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
2021-10-05 08:04:43 -04:00
|
|
|
let lua = self.0.lua;
|
|
|
|
let data = unsafe {
|
2020-12-12 15:37:17 -05:00
|
|
|
let _sg = StackGuard::new(lua.state);
|
2021-05-31 18:33:44 -04:00
|
|
|
check_stack(lua.state, 3).map_err(ser::Error::custom)?;
|
2020-12-12 15:37:17 -05:00
|
|
|
|
2021-09-25 20:05:37 -04:00
|
|
|
lua.push_userdata_ref(&self.0).map_err(ser::Error::custom)?;
|
2021-10-05 08:04:43 -04:00
|
|
|
let ud = &*get_userdata::<UserDataCell<()>>(lua.state, -1);
|
|
|
|
ud.0.try_borrow()
|
|
|
|
.map_err(|_| ser::Error::custom(Error::UserDataBorrowError))?
|
|
|
|
};
|
|
|
|
match &*data {
|
|
|
|
UserDataWrapped::Default(_) => UserDataSerializeError.serialize(serializer),
|
|
|
|
UserDataWrapped::Serializable(ser) => ser.serialize(serializer),
|
2021-05-31 18:33:44 -04:00
|
|
|
}
|
2020-12-12 15:37:17 -05:00
|
|
|
}
|
|
|
|
}
|