Code cleanup
This commit is contained in:
parent
6e787af0f0
commit
b0902967d1
|
@ -1,80 +1,48 @@
|
|||
use std::ffi::CStr;
|
||||
|
||||
use crate::{ensure_type, FromLuaStack, LuaRef, PushToLuaStack, StackGuard, State, Userdata};
|
||||
use std::{cell::{Ref, RefCell, RefMut}, ffi::CStr};
|
||||
|
||||
use mlua_sys as lua;
|
||||
|
||||
pub struct UnsafeUserdata<'a> {
|
||||
use crate::{ensure_type, AsLua, FromLua, FromLuaStack, Function, IntoLuaVec, LuaRef, PushToLuaStack, StackGuard, State, Table, Userdata, Value};
|
||||
|
||||
/// A handle to some userdata on the stack
|
||||
//#[derive(Clone)]
|
||||
pub struct AnyUserdata<'a> {
|
||||
pub(crate) lref: LuaRef<'a>,
|
||||
state: &'a State,
|
||||
}
|
||||
|
||||
impl<'a> Clone for UnsafeUserdata<'a> {
|
||||
impl<'a> Clone for AnyUserdata<'a> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
lref: self.lref.clone(),
|
||||
state: self.state,
|
||||
lref: self.lref.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> UnsafeUserdata<'a> {
|
||||
impl<'a> AnyUserdata<'a> {
|
||||
pub fn from_ref(state: &'a State, lref: LuaRef<'a>) -> Self {
|
||||
Self {
|
||||
lref,
|
||||
state,
|
||||
lref,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a borrow to the userdata.
|
||||
pub fn as_ref<T: Userdata + 'static>(&self) -> crate::Result<&'a T> {
|
||||
pub fn as_ref<T: Userdata + 'static>(&self) -> crate::Result<Ref<'a, T>> {
|
||||
unsafe {
|
||||
self.state.ensure_stack(3)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
return Err(crate::Error::UserdataMismatch);
|
||||
}
|
||||
|
||||
self.state.get_userdata_metatable::<T>()
|
||||
.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_rawequal(s, -2, -1) == 1 {
|
||||
let cptr = lua::lua_touserdata(s, -3);
|
||||
let t = &*cptr.cast::<T>();
|
||||
Ok(t)
|
||||
} else {
|
||||
return Err(crate::Error::UserdataMismatch);
|
||||
}
|
||||
let cell = self.as_ptr::<T>()?;
|
||||
let cell = cell.as_ref().unwrap();
|
||||
Ok(cell.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the userdata.
|
||||
pub fn as_mut<T: Userdata + 'static>(&self) -> crate::Result<&'a mut T> {
|
||||
pub fn as_mut<T: Userdata + 'static>(&self) -> crate::Result<RefMut<'a, T>> {
|
||||
unsafe {
|
||||
self.state.ensure_stack(3)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
self.lref.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
return Err(crate::Error::MissingMetatable);
|
||||
}
|
||||
|
||||
self.state.get_userdata_metatable::<T>()
|
||||
.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_rawequal(s, -2, -1) == 1 {
|
||||
let cptr = lua::lua_touserdata(s, -3);
|
||||
let t = &mut *cptr.cast::<T>();
|
||||
Ok(t)
|
||||
} else {
|
||||
Err(crate::Error::UserdataMismatch)
|
||||
}
|
||||
let cell = self.as_ptr::<T>()?;
|
||||
let cell = cell.as_mut().unwrap();
|
||||
Ok(cell.borrow_mut())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,9 +52,9 @@ impl<'a> UnsafeUserdata<'a> {
|
|||
/// * You must be certain that the type `T` is the same type that this userdata has a handle to.
|
||||
/// There is a blind cast from `void*` to `T*`
|
||||
///
|
||||
/// If there is a possibility that these types do not match, use [`UnsafeUserdata::as_ptr`]
|
||||
/// If there is a possibility that these types do not match, use [`AnyUserdata::as_ptr`]
|
||||
/// which does verify the types.
|
||||
pub unsafe fn as_ptr_unchecked<T>(&self) -> crate::Result<*mut T> {
|
||||
pub unsafe fn as_ptr_unchecked<T: Userdata + 'static>(&self) -> crate::Result<*mut RefCell<T>> {
|
||||
self.state.ensure_stack(1)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
@ -97,11 +65,11 @@ impl<'a> UnsafeUserdata<'a> {
|
|||
Ok(cptr.cast())
|
||||
}
|
||||
|
||||
/// Returns a mutable pointer of the data stored.
|
||||
/// Returns a mutable pointer of the [`RefCell`] storing the userdata.
|
||||
///
|
||||
/// This function ensures that the type of the userdata this struct has a handle to is the
|
||||
/// same as `T`. If it isn't, a `UserdataMismatch` error will be returned.
|
||||
pub unsafe fn as_ptr<T: Userdata + 'static>(&self) -> crate::Result<*mut T> {
|
||||
pub unsafe fn as_ptr<T: Userdata + 'static>(&self) -> crate::Result<*mut RefCell<T>> {
|
||||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
|
@ -148,33 +116,108 @@ impl<'a> UnsafeUserdata<'a> {
|
|||
Ok(cstr.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the metatable of this userdata
|
||||
pub fn get_metatable(&'a self) -> crate::Result<Table<'a>> {
|
||||
unsafe {
|
||||
self.state.ensure_stack(2)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
|
||||
//self.unsafe_ud.lref.push_to_lua_stack(self.state)?;
|
||||
self.push_to_lua_stack(self.state)?;
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
Err(crate::Error::MissingMetatable)
|
||||
} else {
|
||||
let mut t = Table::from_lua_stack(self.state)?;
|
||||
t.mt_marker = true;
|
||||
|
||||
Ok(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets something from the userdata.
|
||||
///
|
||||
/// Will trigger a call to the `__index` metamethod. Use [`AnyUserdata::raw_get`] if you
|
||||
/// don't want to call it.
|
||||
pub fn get<K, V>(&'a self, key: K) -> crate::Result<V>
|
||||
where
|
||||
K: AsLua<'a>,
|
||||
V: FromLua<'a>,
|
||||
{
|
||||
let mt = self.get_metatable()?;
|
||||
mt.get::<K, V>(key)
|
||||
}
|
||||
|
||||
/// Gets something from the userdata. Will **not** trigger a call to the `__index` metamethod.
|
||||
pub fn raw_get<K, V>(&'a self, key: K) -> crate::Result<V>
|
||||
where
|
||||
K: AsLua<'a>,
|
||||
V: FromLua<'a>,
|
||||
{
|
||||
let mt = self.get_metatable()?;
|
||||
mt.raw_get::<K, V>(key)
|
||||
}
|
||||
|
||||
/// Execute a method on this userdata. This finds a function with `name` and executes it
|
||||
/// with the userdata as the first argument.
|
||||
pub fn execute_method<A, R>(&'a self, name: &str, args: A) -> crate::Result<R>
|
||||
where
|
||||
A: IntoLuaVec<'a>,
|
||||
R: FromLua<'a>,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let mt = self.get_metatable()?;
|
||||
let f = mt.get::<_, Function>(name)?;
|
||||
|
||||
let mut args = args.into_lua_value_vec(self.state)?;
|
||||
args.push_front(self.clone().as_lua(self.state)?);
|
||||
|
||||
f.exec(args)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromLuaStack<'a> for UnsafeUserdata<'a> {
|
||||
impl<'a> FromLuaStack<'a> for AnyUserdata<'a> {
|
||||
unsafe fn from_lua_stack(state: &'a State) -> crate::Result<Self> {
|
||||
ensure_type(state, lua::LUA_TUSERDATA, -1)?;
|
||||
|
||||
Ok(UnsafeUserdata {
|
||||
lref: LuaRef::from_stack(state)?,
|
||||
Ok(AnyUserdata {
|
||||
state,
|
||||
lref: LuaRef::from_stack(state)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PushToLuaStack<'a> for UnsafeUserdata<'a> {
|
||||
impl<'a> PushToLuaStack<'a> for AnyUserdata<'a> {
|
||||
unsafe fn push_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
||||
self.lref.push_to_lua_stack(state)
|
||||
}
|
||||
}
|
||||
|
||||
/* impl<'a> AsLua<'a> for UnsafeUserdata<'a> {
|
||||
impl<'a> AsLua<'a> for AnyUserdata<'a> {
|
||||
fn as_lua(&self, _lua: &'a State) -> crate::Result<Value<'a>> {
|
||||
Ok(Value::Userdata(self.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromLua<'a> for UnsafeUserdata<'a> {
|
||||
impl<'a> FromLua<'a> for AnyUserdata<'a> {
|
||||
fn from_lua(_lua: &State, val: Value<'a>) -> crate::Result<Self> {
|
||||
val.into_userdata()
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
impl<'a, T: Userdata + 'static> FromLua<'a> for Ref<'a, T> {
|
||||
fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result<Self> {
|
||||
let ud = val.into_userdata()?;
|
||||
ud.as_ref::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Userdata + 'static> FromLua<'a> for RefMut<'a, T> {
|
||||
fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result<Self> {
|
||||
let ud = val.into_userdata()?;
|
||||
ud.as_mut::<T>()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,283 @@
|
|||
use std::{cell::OnceCell, collections::HashMap, marker::PhantomData, mem, ops::DerefMut, sync::Arc};
|
||||
|
||||
use crate::{AnyUserdata, AsLua, FromLua, FromLuaVec, State, Userdata, Value, ValueVec};
|
||||
|
||||
pub type UserdataFn<'a> = Box<dyn Fn(&'a State, ValueVec<'a>) -> crate::Result<Value<'a>>>;
|
||||
pub type UserdataGetterFn<'a> = Arc<OnceCell<Box<dyn Fn(AnyUserdata<'a>) -> crate::Result<*const ()>>>>;
|
||||
pub type UserdataMutGetterFn<'a> = Arc<OnceCell<Box<dyn Fn(AnyUserdata<'a>) -> crate::Result<*mut ()>>>>;
|
||||
|
||||
pub struct UserdataBuilder<'a, T> {
|
||||
pub(crate) name: String,
|
||||
pub(crate) field_getters: HashMap<String, UserdataFn<'a>>,
|
||||
pub(crate) field_setters: HashMap<String, UserdataFn<'a>>,
|
||||
pub(crate) functions: HashMap<String, UserdataFn<'a>>,
|
||||
pub(crate) meta_methods: HashMap<String, UserdataFn<'a>>,
|
||||
|
||||
pub(crate) wrapped_getter: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'a>) -> crate::Result<*const ()>>>>,
|
||||
pub(crate) wrapped_getter_mut: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'a>) -> crate::Result<*mut ()>>>>,
|
||||
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
name: T::name(),
|
||||
field_getters: HashMap::new(),
|
||||
field_setters: HashMap::new(),
|
||||
functions: HashMap::new(),
|
||||
meta_methods: HashMap::new(),
|
||||
wrapped_getter: Arc::new(OnceCell::new()),
|
||||
wrapped_getter_mut: Arc::new(OnceCell::new()),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field_getter<F, R>(&mut self, name: &str, f: F) -> &mut Self
|
||||
where
|
||||
F: Fn(&'a State, &T) -> crate::Result<R> + 'static,
|
||||
R: AsLua<'a>,
|
||||
T: Userdata + 'static
|
||||
{
|
||||
let wrapped = self.wrapped_getter.clone();
|
||||
let wrapped: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'_>) -> Result<*const (), crate::Error>>>> = unsafe { mem::transmute(wrapped) };
|
||||
|
||||
let ud_name = self.name.clone();
|
||||
let fn_name = name.to_string();
|
||||
|
||||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||
let val = val.pop_front().unwrap();
|
||||
let this = val.as_userdata().unwrap(); // if this panics, its a bug
|
||||
|
||||
if let Some(getter) = wrapped.get() {
|
||||
let this_ptr = Self::result_to_bad_arg(
|
||||
getter(this.clone()),
|
||||
&ud_name,
|
||||
&fn_name,
|
||||
1,
|
||||
Some("self")
|
||||
)?;
|
||||
let this_ptr = this_ptr.cast::<T>();
|
||||
let this = unsafe { &*this_ptr };
|
||||
|
||||
f(lua, this).and_then(|r| r.as_lua(lua))
|
||||
} else {
|
||||
let this = this.as_ref::<T>()?;
|
||||
f(lua, &*this).and_then(|r| r.as_lua(lua))
|
||||
}
|
||||
};
|
||||
self.field_getters.insert(name.to_string(), Box::new(wrap));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn field_setter<F, V>(&mut self, name: &str, f: F) -> &mut Self
|
||||
where
|
||||
F: Fn(&'a State, &mut T, V) -> () + 'static,
|
||||
V: FromLua<'a>,
|
||||
T: Userdata + 'static
|
||||
{
|
||||
let wrapped = self.wrapped_getter_mut.clone();
|
||||
let wrapped: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'_>) -> Result<*mut (), crate::Error>>>> = unsafe { mem::transmute(wrapped) };
|
||||
|
||||
let ud_name = self.name.clone();
|
||||
let fn_name = name.to_string();
|
||||
|
||||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||
let lua_val = val.pop_front().unwrap();
|
||||
let this = lua_val.as_userdata().unwrap(); // if this panics, its a bug
|
||||
|
||||
let lua_val = val.pop_front().unwrap();
|
||||
let v_arg = V::from_lua(lua, lua_val)?;
|
||||
|
||||
if let Some(mut_getter) = wrapped.get() {
|
||||
let this_ptr = Self::result_to_bad_arg(
|
||||
mut_getter(this.clone()),
|
||||
&ud_name,
|
||||
&fn_name,
|
||||
1,
|
||||
Some("self")
|
||||
)?;
|
||||
let this_ptr = this_ptr.cast::<T>();
|
||||
let this = unsafe { this_ptr.as_mut().unwrap() };
|
||||
|
||||
f(lua, this, v_arg).as_lua(lua)
|
||||
} else {
|
||||
let mut this = this.as_mut::<T>()?;
|
||||
|
||||
f(lua, this.deref_mut(), v_arg).as_lua(lua)
|
||||
}
|
||||
};
|
||||
self.field_setters.insert(name.to_string(), Box::new(wrap));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
fn arg_result_to_bad_arg<R>(res: crate::Result<R>, ud_name: &str, fn_name: &str) -> crate::Result<R> {
|
||||
res.map_err(|e| match e {
|
||||
crate::Error::ValueVecError { value_idx, error } => {
|
||||
let full_name = format!("{}.{}", ud_name, fn_name);
|
||||
// added 2 to value index since the error idx starts at 0,
|
||||
// and `this` counts as the first argument in the lua function.
|
||||
crate::Error::BadArgument { func: Some(full_name), arg_index: value_idx + 2, arg_name: None, error, }
|
||||
},
|
||||
_ => e
|
||||
})
|
||||
}
|
||||
|
||||
fn result_to_bad_arg<R>(res: crate::Result<R>, ud_name: &str, fn_name: &str, arg_idx: i32, arg_name: Option<&str>) -> crate::Result<R> {
|
||||
res.map_err(|e| {
|
||||
let full_name = format!("{}.{}", ud_name, fn_name);
|
||||
let arg_name = arg_name.map(|s| s.to_string());
|
||||
|
||||
crate::Error::BadArgument { func: Some(full_name), arg_index: arg_idx, arg_name, error: Arc::new(e), }
|
||||
})
|
||||
}
|
||||
|
||||
pub fn function<F, R, A>(&mut self, name: &str, f: F) -> &mut Self
|
||||
where
|
||||
F: Fn(&'a State, A) -> crate::Result<R> + 'static,
|
||||
A: FromLuaVec<'a>,
|
||||
R: AsLua<'a>,
|
||||
{
|
||||
let ud_name = self.name.clone();
|
||||
let fn_name = name.to_string();
|
||||
let wrap = move |lua: &'a State, val: ValueVec<'a>| {
|
||||
let args = Self::arg_result_to_bad_arg(
|
||||
A::from_lua_value_vec(lua, val),
|
||||
&ud_name, &fn_name
|
||||
)?;
|
||||
f(lua, args).and_then(|r| r.as_lua(lua))
|
||||
};
|
||||
self.functions.insert(name.to_string(), Box::new(wrap));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn method<F, R, A>(&mut self, name: &str, f: F) -> &mut Self
|
||||
where
|
||||
F: Fn(&'a State, &T, A) -> crate::Result<R> + 'static,
|
||||
A: FromLuaVec<'a>,
|
||||
R: AsLua<'a>,
|
||||
T: Userdata + 'static
|
||||
{
|
||||
let wrapped = self.wrapped_getter.clone();
|
||||
let wrapped: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'_>) -> Result<*const (), crate::Error>>>> = unsafe { mem::transmute(wrapped) };
|
||||
|
||||
let ud_name = self.name.clone();
|
||||
let fn_name = name.to_string();
|
||||
|
||||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||
let this_val = val.pop_front().unwrap();
|
||||
let this = this_val.as_userdata().unwrap(); // if this panics, its a bug
|
||||
|
||||
let args = Self::arg_result_to_bad_arg(
|
||||
A::from_lua_value_vec(lua, val),
|
||||
&ud_name, &fn_name
|
||||
)?;
|
||||
|
||||
if let Some(mut_getter) = wrapped.get() {
|
||||
let this_ptr = Self::result_to_bad_arg(
|
||||
mut_getter(this.clone()),
|
||||
&ud_name,
|
||||
&fn_name,
|
||||
1,
|
||||
Some("self")
|
||||
)?;
|
||||
let this_ptr = this_ptr.cast::<T>();
|
||||
let this = unsafe { this_ptr.as_ref().unwrap() };
|
||||
|
||||
f(lua, this, args).and_then(|r| r.as_lua(lua))
|
||||
} else {
|
||||
let this = this.as_ref::<T>()?;
|
||||
|
||||
f(lua, &*this, args).and_then(|r| r.as_lua(lua))
|
||||
}
|
||||
};
|
||||
self.functions.insert(name.to_string(), Box::new(wrap));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn method_mut<F, R, A>(&mut self, name: &str, f: F) -> &mut Self
|
||||
where
|
||||
F: Fn(&'a State, &mut T, A) -> crate::Result<R> + 'static,
|
||||
A: FromLuaVec<'a>,
|
||||
R: AsLua<'a>,
|
||||
T: Userdata + 'static
|
||||
{
|
||||
let wrapped = self.wrapped_getter_mut.clone();
|
||||
let wrapped: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'_>) -> Result<*mut (), crate::Error>>>> = unsafe { mem::transmute(wrapped) };
|
||||
|
||||
let ud_name = self.name.clone();
|
||||
let fn_name = name.to_string();
|
||||
|
||||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||
let this_val = val.pop_front().unwrap();
|
||||
let this = this_val.as_userdata().unwrap(); // if this panics, its a bug
|
||||
|
||||
let args = Self::arg_result_to_bad_arg(
|
||||
A::from_lua_value_vec(lua, val),
|
||||
&ud_name, &fn_name
|
||||
)?;
|
||||
|
||||
if let Some(mut_getter) = wrapped.get() {
|
||||
let this_ptr = Self::result_to_bad_arg(
|
||||
mut_getter(this.clone()),
|
||||
&ud_name,
|
||||
&fn_name,
|
||||
1,
|
||||
Some("self")
|
||||
)?;
|
||||
let this_ptr = this_ptr.cast::<T>();
|
||||
let this = unsafe { this_ptr.as_mut().unwrap() };
|
||||
|
||||
f(lua, this, args).and_then(|r| r.as_lua(lua))
|
||||
} else {
|
||||
let mut this = this.as_mut::<T>()?;
|
||||
|
||||
f(lua, this.deref_mut(), args).and_then(|r| r.as_lua(lua))
|
||||
}
|
||||
};
|
||||
self.functions.insert(name.to_string(), Box::new(wrap));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn meta_method<N, F, R, A>(&mut self, name: N, f: F) -> &mut Self
|
||||
where
|
||||
N: AsRef<str>,
|
||||
F: Fn(&'a State, &T, A) -> crate::Result<R> + 'static,
|
||||
A: FromLuaVec<'a>,
|
||||
R: AsLua<'a>,
|
||||
T: Userdata + 'static
|
||||
{
|
||||
let ud_name = self.name.clone();
|
||||
let fn_name = name.as_ref().to_string();
|
||||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||
let this_val = val.pop_front().unwrap();
|
||||
let this = this_val.as_userdata().unwrap(); // if this panics, its a bug
|
||||
let this = this.as_ref::<T>()?;
|
||||
|
||||
let args = Self::arg_result_to_bad_arg(
|
||||
A::from_lua_value_vec(lua, val),
|
||||
&ud_name, &fn_name
|
||||
)?;
|
||||
|
||||
f(lua, &*this, args).and_then(|r| r.as_lua(lua))
|
||||
};
|
||||
self.meta_methods.insert(name.as_ref().to_string(), Box::new(wrap));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
//fn append_fields_from<S>(&mut self, other: UserDataRegistry<'lua, S>) {
|
||||
pub fn expand_with<U>(&mut self, other: UserdataBuilder<'a, U>) {
|
||||
self.field_getters = other.field_getters;
|
||||
self.field_setters = other.field_setters;
|
||||
self.functions = other.functions;
|
||||
self.meta_methods = other.meta_methods;
|
||||
self.wrapped_getter = other.wrapped_getter;
|
||||
self.wrapped_getter_mut = other.wrapped_getter_mut;
|
||||
}
|
||||
}
|
|
@ -1,27 +1,26 @@
|
|||
use std::{cell::{OnceCell, Ref, RefCell, RefMut}, collections::HashMap, ffi::CStr, marker::PhantomData, mem, ops::DerefMut, sync::Arc};
|
||||
use crate::{AsLua, PushToLuaStack, State, Value};
|
||||
|
||||
use crate::{ensure_type, AsLua, FromLua, FromLuaStack, FromLuaVec, Function, IntoLuaVec, LuaRef, PushToLuaStack, StackGuard, State, Table, Value, ValueVec};
|
||||
|
||||
use mlua_sys as lua;
|
||||
|
||||
pub mod unsafe_ud;
|
||||
pub use unsafe_ud::*;
|
||||
pub mod any;
|
||||
#[allow(unused_imports)]
|
||||
pub use any::*;
|
||||
|
||||
pub mod proxy;
|
||||
#[allow(unused_imports)]
|
||||
use proxy::*;
|
||||
pub use proxy::*;
|
||||
|
||||
pub mod builder;
|
||||
#[allow(unused_imports)]
|
||||
pub use builder::*;
|
||||
|
||||
pub mod borrow;
|
||||
#[allow(unused_imports)]
|
||||
use borrow::*;
|
||||
pub use borrow::*;
|
||||
|
||||
pub mod borrow_mut;
|
||||
#[allow(unused_imports)]
|
||||
use borrow_mut::*;
|
||||
pub use borrow_mut::*;
|
||||
|
||||
|
||||
/// An enum representing all Lua MetaMethods
|
||||
/// https://gist.github.com/oatmealine/655c9e64599d0f0dd47687c1186de99f
|
||||
/// An enum representing Lua meta methods and fields
|
||||
pub enum MetaMethod {
|
||||
Add,
|
||||
Sub,
|
||||
|
@ -105,499 +104,8 @@ impl<'a> PushToLuaStack<'a> for MetaMethod {
|
|||
}
|
||||
}
|
||||
|
||||
pub type UserdataFn<'a> = Box<dyn Fn(&'a State, ValueVec<'a>) -> crate::Result<Value<'a>>>;
|
||||
pub type UserdataGetterFn<'a> = Arc<OnceCell<Box<dyn Fn(AnyUserdata<'a>) -> crate::Result<*const ()>>>>;
|
||||
pub type UserdataMutGetterFn<'a> = Arc<OnceCell<Box<dyn Fn(AnyUserdata<'a>) -> crate::Result<*mut ()>>>>;
|
||||
|
||||
pub struct UserdataBuilder<'a, T> {
|
||||
pub(crate) name: String,
|
||||
pub(crate) field_getters: HashMap<String, UserdataFn<'a>>,
|
||||
pub(crate) field_setters: HashMap<String, UserdataFn<'a>>,
|
||||
pub(crate) functions: HashMap<String, UserdataFn<'a>>,
|
||||
pub(crate) meta_methods: HashMap<String, UserdataFn<'a>>,
|
||||
|
||||
pub(crate) wrapped_getter: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'a>) -> crate::Result<*const ()>>>>,
|
||||
pub(crate) wrapped_getter_mut: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'a>) -> crate::Result<*mut ()>>>>,
|
||||
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
name: T::name(),
|
||||
field_getters: HashMap::new(),
|
||||
field_setters: HashMap::new(),
|
||||
functions: HashMap::new(),
|
||||
meta_methods: HashMap::new(),
|
||||
wrapped_getter: Arc::new(OnceCell::new()),
|
||||
wrapped_getter_mut: Arc::new(OnceCell::new()),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field_getter<F, R>(&mut self, name: &str, f: F) -> &mut Self
|
||||
where
|
||||
F: Fn(&'a State, &T) -> crate::Result<R> + 'static,
|
||||
R: AsLua<'a>,
|
||||
T: Userdata + 'static
|
||||
{
|
||||
let wrapped = self.wrapped_getter.clone();
|
||||
let wrapped: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'_>) -> Result<*const (), crate::Error>>>> = unsafe { mem::transmute(wrapped) };
|
||||
|
||||
let ud_name = self.name.clone();
|
||||
let fn_name = name.to_string();
|
||||
|
||||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||
let val = val.pop_front().unwrap();
|
||||
let this = val.as_userdata().unwrap(); // if this panics, its a bug
|
||||
|
||||
if let Some(getter) = wrapped.get() {
|
||||
let this_ptr = Self::result_to_bad_arg(
|
||||
getter(this.clone()),
|
||||
&ud_name,
|
||||
&fn_name,
|
||||
1,
|
||||
Some("self")
|
||||
)?;
|
||||
let this_ptr = this_ptr.cast::<T>();
|
||||
let this = unsafe { &*this_ptr };
|
||||
|
||||
f(lua, this).and_then(|r| r.as_lua(lua))
|
||||
} else {
|
||||
let this = this.as_ref::<T>()?;
|
||||
f(lua, &*this).and_then(|r| r.as_lua(lua))
|
||||
}
|
||||
};
|
||||
self.field_getters.insert(name.to_string(), Box::new(wrap));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn field_setter<F, V>(&mut self, name: &str, f: F) -> &mut Self
|
||||
where
|
||||
F: Fn(&'a State, &mut T, V) -> () + 'static,
|
||||
V: FromLua<'a>,
|
||||
T: Userdata + 'static
|
||||
{
|
||||
let wrapped = self.wrapped_getter_mut.clone();
|
||||
let wrapped: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'_>) -> Result<*mut (), crate::Error>>>> = unsafe { mem::transmute(wrapped) };
|
||||
|
||||
let ud_name = self.name.clone();
|
||||
let fn_name = name.to_string();
|
||||
|
||||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||
let lua_val = val.pop_front().unwrap();
|
||||
let this = lua_val.as_userdata().unwrap(); // if this panics, its a bug
|
||||
|
||||
let lua_val = val.pop_front().unwrap();
|
||||
let v_arg = V::from_lua(lua, lua_val)?;
|
||||
|
||||
if let Some(mut_getter) = wrapped.get() {
|
||||
let this_ptr = Self::result_to_bad_arg(
|
||||
mut_getter(this.clone()),
|
||||
&ud_name,
|
||||
&fn_name,
|
||||
1,
|
||||
Some("self")
|
||||
)?;
|
||||
let this_ptr = this_ptr.cast::<T>();
|
||||
let this = unsafe { this_ptr.as_mut().unwrap() };
|
||||
|
||||
f(lua, this, v_arg).as_lua(lua)
|
||||
} else {
|
||||
let mut this = this.as_mut::<T>()?;
|
||||
|
||||
f(lua, this.deref_mut(), v_arg).as_lua(lua)
|
||||
}
|
||||
};
|
||||
self.field_setters.insert(name.to_string(), Box::new(wrap));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
fn arg_result_to_bad_arg<R>(res: crate::Result<R>, ud_name: &str, fn_name: &str) -> crate::Result<R> {
|
||||
res.map_err(|e| match e {
|
||||
crate::Error::ValueVecError { value_idx, error } => {
|
||||
let full_name = format!("{}.{}", ud_name, fn_name);
|
||||
// added 2 to value index since the error idx starts at 0,
|
||||
// and `this` counts as the first argument in the lua function.
|
||||
crate::Error::BadArgument { func: Some(full_name), arg_index: value_idx + 2, arg_name: None, error, }
|
||||
},
|
||||
_ => e
|
||||
})
|
||||
}
|
||||
|
||||
fn result_to_bad_arg<R>(res: crate::Result<R>, ud_name: &str, fn_name: &str, arg_idx: i32, arg_name: Option<&str>) -> crate::Result<R> {
|
||||
res.map_err(|e| {
|
||||
let full_name = format!("{}.{}", ud_name, fn_name);
|
||||
let arg_name = arg_name.map(|s| s.to_string());
|
||||
|
||||
crate::Error::BadArgument { func: Some(full_name), arg_index: arg_idx, arg_name, error: Arc::new(e), }
|
||||
})
|
||||
}
|
||||
|
||||
pub fn function<F, R, A>(&mut self, name: &str, f: F) -> &mut Self
|
||||
where
|
||||
F: Fn(&'a State, A) -> crate::Result<R> + 'static,
|
||||
A: FromLuaVec<'a>,
|
||||
R: AsLua<'a>,
|
||||
{
|
||||
let ud_name = self.name.clone();
|
||||
let fn_name = name.to_string();
|
||||
let wrap = move |lua: &'a State, val: ValueVec<'a>| {
|
||||
let args = Self::arg_result_to_bad_arg(
|
||||
A::from_lua_value_vec(lua, val),
|
||||
&ud_name, &fn_name
|
||||
)?;
|
||||
f(lua, args).and_then(|r| r.as_lua(lua))
|
||||
};
|
||||
self.functions.insert(name.to_string(), Box::new(wrap));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn method<F, R, A>(&mut self, name: &str, f: F) -> &mut Self
|
||||
where
|
||||
F: Fn(&'a State, &T, A) -> crate::Result<R> + 'static,
|
||||
A: FromLuaVec<'a>,
|
||||
R: AsLua<'a>,
|
||||
T: Userdata + 'static
|
||||
{
|
||||
let wrapped = self.wrapped_getter.clone();
|
||||
let wrapped: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'_>) -> Result<*const (), crate::Error>>>> = unsafe { mem::transmute(wrapped) };
|
||||
|
||||
let ud_name = self.name.clone();
|
||||
let fn_name = name.to_string();
|
||||
|
||||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||
let this_val = val.pop_front().unwrap();
|
||||
let this = this_val.as_userdata().unwrap(); // if this panics, its a bug
|
||||
|
||||
let args = Self::arg_result_to_bad_arg(
|
||||
A::from_lua_value_vec(lua, val),
|
||||
&ud_name, &fn_name
|
||||
)?;
|
||||
|
||||
if let Some(mut_getter) = wrapped.get() {
|
||||
let this_ptr = Self::result_to_bad_arg(
|
||||
mut_getter(this.clone()),
|
||||
&ud_name,
|
||||
&fn_name,
|
||||
1,
|
||||
Some("self")
|
||||
)?;
|
||||
let this_ptr = this_ptr.cast::<T>();
|
||||
let this = unsafe { this_ptr.as_ref().unwrap() };
|
||||
|
||||
f(lua, this, args).and_then(|r| r.as_lua(lua))
|
||||
} else {
|
||||
let this = this.as_ref::<T>()?;
|
||||
|
||||
f(lua, &*this, args).and_then(|r| r.as_lua(lua))
|
||||
}
|
||||
};
|
||||
self.functions.insert(name.to_string(), Box::new(wrap));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn method_mut<F, R, A>(&mut self, name: &str, f: F) -> &mut Self
|
||||
where
|
||||
F: Fn(&'a State, &mut T, A) -> crate::Result<R> + 'static,
|
||||
A: FromLuaVec<'a>,
|
||||
R: AsLua<'a>,
|
||||
T: Userdata + 'static
|
||||
{
|
||||
let wrapped = self.wrapped_getter_mut.clone();
|
||||
let wrapped: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'_>) -> Result<*mut (), crate::Error>>>> = unsafe { mem::transmute(wrapped) };
|
||||
|
||||
let ud_name = self.name.clone();
|
||||
let fn_name = name.to_string();
|
||||
|
||||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||
let this_val = val.pop_front().unwrap();
|
||||
let this = this_val.as_userdata().unwrap(); // if this panics, its a bug
|
||||
|
||||
let args = Self::arg_result_to_bad_arg(
|
||||
A::from_lua_value_vec(lua, val),
|
||||
&ud_name, &fn_name
|
||||
)?;
|
||||
|
||||
if let Some(mut_getter) = wrapped.get() {
|
||||
let this_ptr = Self::result_to_bad_arg(
|
||||
mut_getter(this.clone()),
|
||||
&ud_name,
|
||||
&fn_name,
|
||||
1,
|
||||
Some("self")
|
||||
)?;
|
||||
let this_ptr = this_ptr.cast::<T>();
|
||||
let this = unsafe { this_ptr.as_mut().unwrap() };
|
||||
|
||||
f(lua, this, args).and_then(|r| r.as_lua(lua))
|
||||
} else {
|
||||
let mut this = this.as_mut::<T>()?;
|
||||
|
||||
f(lua, this.deref_mut(), args).and_then(|r| r.as_lua(lua))
|
||||
}
|
||||
};
|
||||
self.functions.insert(name.to_string(), Box::new(wrap));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn meta_method<N, F, R, A>(&mut self, name: N, f: F) -> &mut Self
|
||||
where
|
||||
N: AsRef<str>,
|
||||
F: Fn(&'a State, &T, A) -> crate::Result<R> + 'static,
|
||||
A: FromLuaVec<'a>,
|
||||
R: AsLua<'a>,
|
||||
T: Userdata + 'static
|
||||
{
|
||||
let ud_name = self.name.clone();
|
||||
let fn_name = name.as_ref().to_string();
|
||||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||
let this_val = val.pop_front().unwrap();
|
||||
let this = this_val.as_userdata().unwrap(); // if this panics, its a bug
|
||||
let this = this.as_ref::<T>()?;
|
||||
|
||||
let args = Self::arg_result_to_bad_arg(
|
||||
A::from_lua_value_vec(lua, val),
|
||||
&ud_name, &fn_name
|
||||
)?;
|
||||
|
||||
f(lua, &*this, args).and_then(|r| r.as_lua(lua))
|
||||
};
|
||||
self.meta_methods.insert(name.as_ref().to_string(), Box::new(wrap));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
//fn append_fields_from<S>(&mut self, other: UserDataRegistry<'lua, S>) {
|
||||
pub fn expand_with<U>(&mut self, other: UserdataBuilder<'a, U>) {
|
||||
self.field_getters = other.field_getters;
|
||||
self.field_setters = other.field_setters;
|
||||
self.functions = other.functions;
|
||||
self.meta_methods = other.meta_methods;
|
||||
self.wrapped_getter = other.wrapped_getter;
|
||||
self.wrapped_getter_mut = other.wrapped_getter_mut;
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Userdata: Sized {
|
||||
fn name() -> String;
|
||||
|
||||
fn build<'a>(state: &State, builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()>;
|
||||
}
|
||||
|
||||
/// A handle to some userdata on the stack
|
||||
//#[derive(Clone)]
|
||||
pub struct AnyUserdata<'a> {
|
||||
pub(crate) unsafe_ud: UnsafeUserdata<'a>,
|
||||
state: &'a State,
|
||||
}
|
||||
|
||||
impl<'a> Clone for AnyUserdata<'a> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
state: self.state,
|
||||
unsafe_ud: self.unsafe_ud.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AnyUserdata<'a> {
|
||||
pub fn from_ref(state: &'a State, lref: LuaRef<'a>) -> Self {
|
||||
Self {
|
||||
state,
|
||||
unsafe_ud: UnsafeUserdata::from_ref(state, lref)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a borrow to the userdata.
|
||||
pub fn as_ref<T: Userdata + 'static>(&self) -> crate::Result<Ref<'a, T>> {
|
||||
unsafe {
|
||||
let cell = &*self.unsafe_ud.as_ptr_unchecked::<RefCell<T>>()?;
|
||||
Ok(cell.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the userdata.
|
||||
pub fn as_mut<T: Userdata + 'static>(&self) -> crate::Result<RefMut<'a, T>> {
|
||||
unsafe {
|
||||
let cell = &*self.unsafe_ud.as_ptr_unchecked::<RefCell<T>>()?;
|
||||
Ok(cell.borrow_mut())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable pointer of the [`RefCell`] of userdata **WITHOUT verifying the type of it**.
|
||||
///
|
||||
/// # Safety
|
||||
/// * You must be certain that the type `T` is the same type that this userdata has a handle to.
|
||||
/// There is a blind cast from `void*` to `T*`
|
||||
///
|
||||
/// If there is a possibility that these types do not match, use [`AnyUserdata::as_ptr`]
|
||||
/// which does verify the types.
|
||||
pub unsafe fn as_ptr_unchecked<T: Userdata + 'static>(&self) -> crate::Result<*mut RefCell<T>> {
|
||||
let cell = self.unsafe_ud.as_ptr_unchecked::<RefCell<T>>()?;
|
||||
Ok(cell)
|
||||
}
|
||||
|
||||
/// Returns a mutable pointer of the [`RefCell`] storing the userdata.
|
||||
///
|
||||
/// This function ensures that the type of the userdata this struct has a handle to is the
|
||||
/// same as `T`. If it isn't, a `UserdataMismatch` error will be returned.
|
||||
pub unsafe fn as_ptr<T: Userdata + 'static>(&self) -> crate::Result<*mut RefCell<T>> {
|
||||
let _g = StackGuard::new(self.state);
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
self.unsafe_ud.lref.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
return Err(crate::Error::MissingMetatable);
|
||||
}
|
||||
|
||||
self.state.get_userdata_metatable::<T>()
|
||||
.push_to_lua_stack(self.state)?;
|
||||
|
||||
if lua::lua_rawequal(s, -2, -1) == 1 {
|
||||
drop(_g);
|
||||
let cell = self.unsafe_ud.as_ptr_unchecked::<RefCell<T>>()?;
|
||||
Ok(cell)
|
||||
} else {
|
||||
Err(crate::Error::UserdataMismatch)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the name of the userdata by accessing the metatable
|
||||
pub fn name(&self) -> crate::Result<String> {
|
||||
unsafe {
|
||||
self.state.ensure_stack(3)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
|
||||
self.unsafe_ud.lref.push_to_lua_stack(self.state)?;
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
return Err(crate::Error::MissingMetatable);
|
||||
}
|
||||
|
||||
lua::lua_pushliteral(s, "__name");
|
||||
lua::lua_rawget(s, -2);
|
||||
|
||||
ensure_type(self.state, lua::LUA_TSTRING, -1)?;
|
||||
|
||||
let cstr = CStr::from_ptr(lua::lua_tostring(s, -1));
|
||||
let cstr = cstr.to_str()
|
||||
// on panic, this should be considered a bug
|
||||
.expect("Metatable name has invalid utf8 bytes!");
|
||||
|
||||
Ok(cstr.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the metatable of this userdata
|
||||
pub fn get_metatable(&'a self) -> crate::Result<Table<'a>> {
|
||||
unsafe {
|
||||
self.state.ensure_stack(2)?;
|
||||
let _g = StackGuard::new(self.state);
|
||||
|
||||
//self.unsafe_ud.lref.push_to_lua_stack(self.state)?;
|
||||
self.push_to_lua_stack(self.state)?;
|
||||
let s = self.state.state_ptr();
|
||||
|
||||
if lua::lua_getmetatable(s, -1) == 0 {
|
||||
Err(crate::Error::MissingMetatable)
|
||||
} else {
|
||||
let mut t = Table::from_lua_stack(self.state)?;
|
||||
t.mt_marker = true;
|
||||
|
||||
Ok(t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets something from the userdata.
|
||||
///
|
||||
/// Will trigger a call to the `__index` metamethod. Use [`AnyUserdata::raw_get`] if you
|
||||
/// don't want to call it.
|
||||
pub fn get<K, V>(&'a self, key: K) -> crate::Result<V>
|
||||
where
|
||||
K: AsLua<'a>,
|
||||
V: FromLua<'a>,
|
||||
{
|
||||
let mt = self.get_metatable()?;
|
||||
mt.get::<K, V>(key)
|
||||
}
|
||||
|
||||
/// Gets something from the userdata. Will **not** trigger a call to the `__index` metamethod.
|
||||
pub fn raw_get<K, V>(&'a self, key: K) -> crate::Result<V>
|
||||
where
|
||||
K: AsLua<'a>,
|
||||
V: FromLua<'a>,
|
||||
{
|
||||
let mt = self.get_metatable()?;
|
||||
mt.raw_get::<K, V>(key)
|
||||
}
|
||||
|
||||
/// Execute a method on this userdata. This finds a function with `name` and executes it
|
||||
/// with the userdata as the first argument.
|
||||
pub fn execute_method<A, R>(&'a self, name: &str, args: A) -> crate::Result<R>
|
||||
where
|
||||
A: IntoLuaVec<'a>,
|
||||
R: FromLua<'a>,
|
||||
{
|
||||
let name = name.to_string();
|
||||
let mt = self.get_metatable()?;
|
||||
let f = mt.get::<_, Function>(name)?;
|
||||
|
||||
let mut args = args.into_lua_value_vec(self.state)?;
|
||||
args.push_front(self.clone().as_lua(self.state)?);
|
||||
|
||||
f.exec(args)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromLuaStack<'a> for AnyUserdata<'a> {
|
||||
unsafe fn from_lua_stack(state: &'a State) -> crate::Result<Self> {
|
||||
ensure_type(state, lua::LUA_TUSERDATA, -1)?;
|
||||
|
||||
Ok(AnyUserdata {
|
||||
state,
|
||||
unsafe_ud: UnsafeUserdata::from_lua_stack(state)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PushToLuaStack<'a> for AnyUserdata<'a> {
|
||||
unsafe fn push_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
||||
self.unsafe_ud.lref.push_to_lua_stack(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsLua<'a> for AnyUserdata<'a> {
|
||||
fn as_lua(&self, _lua: &'a State) -> crate::Result<Value<'a>> {
|
||||
Ok(Value::Userdata(self.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromLua<'a> for AnyUserdata<'a> {
|
||||
fn from_lua(_lua: &State, val: Value<'a>) -> crate::Result<Self> {
|
||||
val.into_userdata()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Userdata + 'static> FromLua<'a> for Ref<'a, T> {
|
||||
fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result<Self> {
|
||||
let ud = val.into_userdata()?;
|
||||
ud.as_ref::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Userdata + 'static> FromLua<'a> for RefMut<'a, T> {
|
||||
fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result<Self> {
|
||||
let ud = val.into_userdata()?;
|
||||
ud.as_mut::<T>()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue