From b0902967d1614af59bfb72387cafdff77e2ae794 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Sun, 11 Feb 2024 09:59:28 -0500 Subject: [PATCH] Code cleanup --- src/userdata/{unsafe_ud.rs => any.rs} | 165 +++++--- src/userdata/builder.rs | 283 ++++++++++++++ src/userdata/mod.rs | 516 +------------------------- 3 files changed, 399 insertions(+), 565 deletions(-) rename src/userdata/{unsafe_ud.rs => any.rs} (53%) create mode 100755 src/userdata/builder.rs diff --git a/src/userdata/unsafe_ud.rs b/src/userdata/any.rs similarity index 53% rename from src/userdata/unsafe_ud.rs rename to src/userdata/any.rs index e067bd6..b4b0e4e 100755 --- a/src/userdata/unsafe_ud.rs +++ b/src/userdata/any.rs @@ -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(&self) -> crate::Result<&'a T> { + pub fn as_ref(&self) -> crate::Result> { 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::() - .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::(); - Ok(t) - } else { - return Err(crate::Error::UserdataMismatch); - } + let cell = self.as_ptr::()?; + let cell = cell.as_ref().unwrap(); + Ok(cell.borrow()) } } /// Returns a mutable reference to the userdata. - pub fn as_mut(&self) -> crate::Result<&'a mut T> { + pub fn as_mut(&self) -> crate::Result> { 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::() - .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::(); - Ok(t) - } else { - Err(crate::Error::UserdataMismatch) - } + let cell = self.as_ptr::()?; + 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(&self) -> crate::Result<*mut T> { + pub unsafe fn as_ptr_unchecked(&self) -> crate::Result<*mut RefCell> { 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(&self) -> crate::Result<*mut T> { + pub unsafe fn as_ptr(&self) -> crate::Result<*mut RefCell> { 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> { + 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(&'a self, key: K) -> crate::Result + where + K: AsLua<'a>, + V: FromLua<'a>, + { + let mt = self.get_metatable()?; + mt.get::(key) + } + + /// Gets something from the userdata. Will **not** trigger a call to the `__index` metamethod. + pub fn raw_get(&'a self, key: K) -> crate::Result + where + K: AsLua<'a>, + V: FromLua<'a>, + { + let mt = self.get_metatable()?; + mt.raw_get::(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 self, name: &str, args: A) -> crate::Result + 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 { 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> { 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 { val.into_userdata() } -} */ \ No newline at end of file +} + +impl<'a, T: Userdata + 'static> FromLua<'a> for Ref<'a, T> { + fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result { + let ud = val.into_userdata()?; + ud.as_ref::() + } +} + +impl<'a, T: Userdata + 'static> FromLua<'a> for RefMut<'a, T> { + fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result { + let ud = val.into_userdata()?; + ud.as_mut::() + } +} \ No newline at end of file diff --git a/src/userdata/builder.rs b/src/userdata/builder.rs new file mode 100755 index 0000000..121ab3c --- /dev/null +++ b/src/userdata/builder.rs @@ -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) -> crate::Result>>; +pub type UserdataGetterFn<'a> = Arc) -> crate::Result<*const ()>>>>; +pub type UserdataMutGetterFn<'a> = Arc) -> crate::Result<*mut ()>>>>; + +pub struct UserdataBuilder<'a, T> { + pub(crate) name: String, + pub(crate) field_getters: HashMap>, + pub(crate) field_setters: HashMap>, + pub(crate) functions: HashMap>, + pub(crate) meta_methods: HashMap>, + + pub(crate) wrapped_getter: Arc) -> crate::Result<*const ()>>>>, + pub(crate) wrapped_getter_mut: Arc) -> crate::Result<*mut ()>>>>, + + _marker: PhantomData, +} + +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(&mut self, name: &str, f: F) -> &mut Self + where + F: Fn(&'a State, &T) -> crate::Result + 'static, + R: AsLua<'a>, + T: Userdata + 'static + { + let wrapped = self.wrapped_getter.clone(); + let wrapped: Arc) -> 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::(); + let this = unsafe { &*this_ptr }; + + f(lua, this).and_then(|r| r.as_lua(lua)) + } else { + let this = this.as_ref::()?; + 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(&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) -> 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::(); + let this = unsafe { this_ptr.as_mut().unwrap() }; + + f(lua, this, v_arg).as_lua(lua) + } else { + let mut this = this.as_mut::()?; + + 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(res: crate::Result, ud_name: &str, fn_name: &str) -> crate::Result { + 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(res: crate::Result, ud_name: &str, fn_name: &str, arg_idx: i32, arg_name: Option<&str>) -> crate::Result { + 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(&mut self, name: &str, f: F) -> &mut Self + where + F: Fn(&'a State, A) -> crate::Result + '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(&mut self, name: &str, f: F) -> &mut Self + where + F: Fn(&'a State, &T, A) -> crate::Result + 'static, + A: FromLuaVec<'a>, + R: AsLua<'a>, + T: Userdata + 'static + { + let wrapped = self.wrapped_getter.clone(); + let wrapped: Arc) -> 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::(); + 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::()?; + + 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(&mut self, name: &str, f: F) -> &mut Self + where + F: Fn(&'a State, &mut T, A) -> crate::Result + 'static, + A: FromLuaVec<'a>, + R: AsLua<'a>, + T: Userdata + 'static + { + let wrapped = self.wrapped_getter_mut.clone(); + let wrapped: Arc) -> 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::(); + 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::()?; + + 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(&mut self, name: N, f: F) -> &mut Self + where + N: AsRef, + F: Fn(&'a State, &T, A) -> crate::Result + '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::()?; + + 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(&mut self, other: UserDataRegistry<'lua, S>) { + pub fn expand_with(&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; + } +} \ No newline at end of file diff --git a/src/userdata/mod.rs b/src/userdata/mod.rs index 5d1c23f..7e20bea 100755 --- a/src/userdata/mod.rs +++ b/src/userdata/mod.rs @@ -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) -> crate::Result>>; -pub type UserdataGetterFn<'a> = Arc) -> crate::Result<*const ()>>>>; -pub type UserdataMutGetterFn<'a> = Arc) -> crate::Result<*mut ()>>>>; - -pub struct UserdataBuilder<'a, T> { - pub(crate) name: String, - pub(crate) field_getters: HashMap>, - pub(crate) field_setters: HashMap>, - pub(crate) functions: HashMap>, - pub(crate) meta_methods: HashMap>, - - pub(crate) wrapped_getter: Arc) -> crate::Result<*const ()>>>>, - pub(crate) wrapped_getter_mut: Arc) -> crate::Result<*mut ()>>>>, - - _marker: PhantomData, -} - -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(&mut self, name: &str, f: F) -> &mut Self - where - F: Fn(&'a State, &T) -> crate::Result + 'static, - R: AsLua<'a>, - T: Userdata + 'static - { - let wrapped = self.wrapped_getter.clone(); - let wrapped: Arc) -> 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::(); - let this = unsafe { &*this_ptr }; - - f(lua, this).and_then(|r| r.as_lua(lua)) - } else { - let this = this.as_ref::()?; - 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(&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) -> 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::(); - let this = unsafe { this_ptr.as_mut().unwrap() }; - - f(lua, this, v_arg).as_lua(lua) - } else { - let mut this = this.as_mut::()?; - - 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(res: crate::Result, ud_name: &str, fn_name: &str) -> crate::Result { - 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(res: crate::Result, ud_name: &str, fn_name: &str, arg_idx: i32, arg_name: Option<&str>) -> crate::Result { - 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(&mut self, name: &str, f: F) -> &mut Self - where - F: Fn(&'a State, A) -> crate::Result + '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(&mut self, name: &str, f: F) -> &mut Self - where - F: Fn(&'a State, &T, A) -> crate::Result + 'static, - A: FromLuaVec<'a>, - R: AsLua<'a>, - T: Userdata + 'static - { - let wrapped = self.wrapped_getter.clone(); - let wrapped: Arc) -> 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::(); - 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::()?; - - 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(&mut self, name: &str, f: F) -> &mut Self - where - F: Fn(&'a State, &mut T, A) -> crate::Result + 'static, - A: FromLuaVec<'a>, - R: AsLua<'a>, - T: Userdata + 'static - { - let wrapped = self.wrapped_getter_mut.clone(); - let wrapped: Arc) -> 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::(); - 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::()?; - - 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(&mut self, name: N, f: F) -> &mut Self - where - N: AsRef, - F: Fn(&'a State, &T, A) -> crate::Result + '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::()?; - - 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(&mut self, other: UserDataRegistry<'lua, S>) { - pub fn expand_with(&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(&self) -> crate::Result> { - unsafe { - let cell = &*self.unsafe_ud.as_ptr_unchecked::>()?; - Ok(cell.borrow()) - } - } - - /// Returns a mutable reference to the userdata. - pub fn as_mut(&self) -> crate::Result> { - unsafe { - let cell = &*self.unsafe_ud.as_ptr_unchecked::>()?; - 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(&self) -> crate::Result<*mut RefCell> { - let cell = self.unsafe_ud.as_ptr_unchecked::>()?; - 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(&self) -> crate::Result<*mut RefCell> { - 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::() - .push_to_lua_stack(self.state)?; - - if lua::lua_rawequal(s, -2, -1) == 1 { - drop(_g); - let cell = self.unsafe_ud.as_ptr_unchecked::>()?; - Ok(cell) - } else { - Err(crate::Error::UserdataMismatch) - } - } - - /// Returns the name of the userdata by accessing the metatable - pub fn name(&self) -> crate::Result { - 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> { - 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(&'a self, key: K) -> crate::Result - where - K: AsLua<'a>, - V: FromLua<'a>, - { - let mt = self.get_metatable()?; - mt.get::(key) - } - - /// Gets something from the userdata. Will **not** trigger a call to the `__index` metamethod. - pub fn raw_get(&'a self, key: K) -> crate::Result - where - K: AsLua<'a>, - V: FromLua<'a>, - { - let mt = self.get_metatable()?; - mt.raw_get::(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 self, name: &str, args: A) -> crate::Result - 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 { - 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> { - Ok(Value::Userdata(self.clone())) - } -} - -impl<'a> FromLua<'a> for AnyUserdata<'a> { - fn from_lua(_lua: &State, val: Value<'a>) -> crate::Result { - 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 { - let ud = val.into_userdata()?; - ud.as_ref::() - } -} - -impl<'a, T: Userdata + 'static> FromLua<'a> for RefMut<'a, T> { - fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result { - let ud = val.into_userdata()?; - ud.as_mut::() - } } \ No newline at end of file