Code cleanup
This commit is contained in:
parent
6e787af0f0
commit
b0902967d1
|
@ -1,80 +1,48 @@
|
||||||
use std::ffi::CStr;
|
use std::{cell::{Ref, RefCell, RefMut}, ffi::CStr};
|
||||||
|
|
||||||
use crate::{ensure_type, FromLuaStack, LuaRef, PushToLuaStack, StackGuard, State, Userdata};
|
|
||||||
|
|
||||||
use mlua_sys as lua;
|
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>,
|
pub(crate) lref: LuaRef<'a>,
|
||||||
state: &'a State,
|
state: &'a State,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Clone for UnsafeUserdata<'a> {
|
impl<'a> Clone for AnyUserdata<'a> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
lref: self.lref.clone(),
|
|
||||||
state: self.state,
|
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 {
|
pub fn from_ref(state: &'a State, lref: LuaRef<'a>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
lref,
|
|
||||||
state,
|
state,
|
||||||
|
lref,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a borrow to the userdata.
|
/// 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 {
|
unsafe {
|
||||||
self.state.ensure_stack(3)?;
|
let cell = self.as_ptr::<T>()?;
|
||||||
let _g = StackGuard::new(self.state);
|
let cell = cell.as_ref().unwrap();
|
||||||
let s = self.state.state_ptr();
|
Ok(cell.borrow())
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference to the userdata.
|
/// 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 {
|
unsafe {
|
||||||
self.state.ensure_stack(3)?;
|
let cell = self.as_ptr::<T>()?;
|
||||||
let _g = StackGuard::new(self.state);
|
let cell = cell.as_mut().unwrap();
|
||||||
let s = self.state.state_ptr();
|
Ok(cell.borrow_mut())
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
/// * 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*`
|
/// 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.
|
/// 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)?;
|
self.state.ensure_stack(1)?;
|
||||||
let _g = StackGuard::new(self.state);
|
let _g = StackGuard::new(self.state);
|
||||||
let s = self.state.state_ptr();
|
let s = self.state.state_ptr();
|
||||||
|
@ -97,11 +65,11 @@ impl<'a> UnsafeUserdata<'a> {
|
||||||
Ok(cptr.cast())
|
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
|
/// 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.
|
/// 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 _g = StackGuard::new(self.state);
|
||||||
let s = self.state.state_ptr();
|
let s = self.state.state_ptr();
|
||||||
|
|
||||||
|
@ -148,33 +116,108 @@ impl<'a> UnsafeUserdata<'a> {
|
||||||
Ok(cstr.to_string())
|
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> {
|
unsafe fn from_lua_stack(state: &'a State) -> crate::Result<Self> {
|
||||||
ensure_type(state, lua::LUA_TUSERDATA, -1)?;
|
ensure_type(state, lua::LUA_TUSERDATA, -1)?;
|
||||||
|
|
||||||
Ok(UnsafeUserdata {
|
Ok(AnyUserdata {
|
||||||
lref: LuaRef::from_stack(state)?,
|
|
||||||
state,
|
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<()> {
|
unsafe fn push_to_lua_stack(&self, state: &'a State) -> crate::Result<()> {
|
||||||
self.lref.push_to_lua_stack(state)
|
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>> {
|
fn as_lua(&self, _lua: &'a State) -> crate::Result<Value<'a>> {
|
||||||
Ok(Value::Userdata(self.clone()))
|
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> {
|
fn from_lua(_lua: &State, val: Value<'a>) -> crate::Result<Self> {
|
||||||
val.into_userdata()
|
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};
|
pub mod any;
|
||||||
|
#[allow(unused_imports)]
|
||||||
use mlua_sys as lua;
|
pub use any::*;
|
||||||
|
|
||||||
pub mod unsafe_ud;
|
|
||||||
pub use unsafe_ud::*;
|
|
||||||
|
|
||||||
pub mod proxy;
|
pub mod proxy;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use proxy::*;
|
pub use proxy::*;
|
||||||
|
|
||||||
|
pub mod builder;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
pub use builder::*;
|
||||||
|
|
||||||
pub mod borrow;
|
pub mod borrow;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use borrow::*;
|
pub use borrow::*;
|
||||||
|
|
||||||
pub mod borrow_mut;
|
pub mod borrow_mut;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use borrow_mut::*;
|
pub use borrow_mut::*;
|
||||||
|
|
||||||
|
/// An enum representing Lua meta methods and fields
|
||||||
/// An enum representing all Lua MetaMethods
|
|
||||||
/// https://gist.github.com/oatmealine/655c9e64599d0f0dd47687c1186de99f
|
|
||||||
pub enum MetaMethod {
|
pub enum MetaMethod {
|
||||||
Add,
|
Add,
|
||||||
Sub,
|
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 {
|
pub trait Userdata: Sized {
|
||||||
fn name() -> String;
|
fn name() -> String;
|
||||||
|
|
||||||
fn build<'a>(state: &State, builder: &mut UserdataBuilder<'a, Self>) -> crate::Result<()>;
|
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