Create UserdataRefMut, create tests for UserdataRef and UserdataRefMut
This commit is contained in:
parent
80b9a4ef35
commit
25f4116278
|
@ -40,6 +40,27 @@
|
|||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug a specific unit tests in executable 'lua-ffi'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--package=lua-ffi",
|
||||
"userdata::borrow::tests::ud_methods_borrow",
|
||||
"--",
|
||||
"--exact"
|
||||
]/* ,
|
||||
"filter": {
|
||||
"name": "lua-ffi",
|
||||
"kind": "bin"
|
||||
} */
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
16
src/tests.rs
16
src/tests.rs
|
@ -3,8 +3,8 @@ use std::cell::Ref;
|
|||
use crate::{MetaMethod, State, Userdata, UserdataBuilder};
|
||||
|
||||
pub struct Vec2 {
|
||||
x: f32,
|
||||
y: f32,
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
impl Userdata for Vec2 {
|
||||
|
@ -28,6 +28,18 @@ impl Userdata for Vec2 {
|
|||
y: ly + ry,
|
||||
})
|
||||
})
|
||||
.method_mut("mult", |_, this: &mut Vec2, scalar: f32| {
|
||||
this.x *= scalar;
|
||||
this.y *= scalar;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.method("mult_ret", |lua, this: &Vec2, scalar: f32| {
|
||||
lua.create_userdata(Vec2 {
|
||||
x: this.x * scalar,
|
||||
y: this.y * scalar,
|
||||
})
|
||||
})
|
||||
.meta_method(MetaMethod::Add, |lua, lhs: &Vec2, (rhs,): (Ref<Vec2>,)| {
|
||||
let lx = lhs.x;
|
||||
let ly = lhs.y;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{cell::Ref, mem, ops::Deref};
|
||||
|
||||
use crate::{AnyUserdata, Result, State, Userdata, UserdataBuilder};
|
||||
use crate::{AnyUserdata, Error, Result, State, Userdata, UserdataBuilder};
|
||||
|
||||
enum Borrow<'a, T> {
|
||||
Wrapped(Ref<'a, T>),
|
||||
|
@ -64,10 +64,18 @@ impl<'a, T: Userdata + 'static> Userdata for UserdataRef<'a, T> {
|
|||
Ok(ud_ptr.cast::<()>())
|
||||
};
|
||||
|
||||
let mut_getter: fn(AnyUserdata<'_>) -> Result<*mut ()> = move |_ud: AnyUserdata| {
|
||||
Err(Error::Runtime(format!("cannot mutably access '{}' when its behind a non mutable reference!", T::name())))
|
||||
};
|
||||
|
||||
if builder.wrapped_getter.set(Box::new(getter)).is_err() {
|
||||
panic!("Somehow the wrapped getter has already been set");
|
||||
}
|
||||
|
||||
if builder.wrapped_getter_mut.set(Box::new(mut_getter)).is_err() {
|
||||
panic!("Somehow the wrapped mutable getter has already been set");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -76,3 +84,85 @@ impl<'a, T: Userdata + 'static> Userdata for UserdataRef<'a, T> {
|
|||
name
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{borrow::Borrow, cell::{Ref, RefCell}};
|
||||
|
||||
use crate::{tests::Vec2, AnyUserdata, State, StdLibrary, Value};
|
||||
|
||||
use super::UserdataRef;
|
||||
|
||||
/// This test ensures that a Ref of userdata can be provided to Lua, and it that it can access fields on the userdata.
|
||||
#[test]
|
||||
fn ud_fields_borrow() -> crate::Result<()> {
|
||||
let lua = State::new();
|
||||
lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]);
|
||||
|
||||
let globals = lua.globals()?;
|
||||
|
||||
let v1 = RefCell::new(Vec2 { x: 50.0, y: 5.0 });
|
||||
let ud = lua.create_userdata(UserdataRef::from(v1.borrow()))?;
|
||||
globals.set("v1", ud)?;
|
||||
|
||||
let chunk = lua.load(
|
||||
"text.lua",
|
||||
r#"
|
||||
print("v1: (" .. v1.x .. ", " .. v1.y .. ")")
|
||||
"#)?;
|
||||
|
||||
for _ in 0..40 {
|
||||
let res = lua.execute_chunk::<_, Value>(&chunk, ());
|
||||
|
||||
if let Err(e) = res {
|
||||
panic!("{}", e);
|
||||
}
|
||||
|
||||
//println!("i = {}", i);
|
||||
globals.set("v1", Value::Nil)?;
|
||||
lua.gc_collect()?; // must collect here to drop the Ref
|
||||
|
||||
let mut t = v1.borrow_mut();
|
||||
t.x += 50.0;
|
||||
t.y += 5.0;
|
||||
drop(t);
|
||||
|
||||
let ud = lua.create_userdata(UserdataRef::from(v1.borrow()))?;
|
||||
globals.raw_set("v1", ud)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This test ensures that a raw borrow of userdata can be provided to Lua, and it that it can run non-mutating methods on the userdata.
|
||||
#[test]
|
||||
fn ud_methods_borrow() -> crate::Result<()> {
|
||||
let lua = State::new();
|
||||
lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]);
|
||||
|
||||
let globals = lua.globals()?;
|
||||
|
||||
let v1 = RefCell::new(Vec2 { x: 50.0, y: 5.0 });
|
||||
let ud = lua.create_userdata(UserdataRef::from(v1.borrow()))?;
|
||||
globals.set("v1", ud)?;
|
||||
|
||||
let chunk = lua.load(
|
||||
"text.lua",
|
||||
r#"
|
||||
v2 = v1:mult_ret(2.0)
|
||||
print("v2: (" .. v2.x .. ", " .. v2.y .. ")")
|
||||
"#)?;
|
||||
|
||||
let res = lua.execute_chunk::<_, Value>(&chunk, ());
|
||||
|
||||
if let Err(e) = res {
|
||||
panic!("{}", e);
|
||||
}
|
||||
|
||||
let v2 = globals.get::<_, Ref<Vec2>>("v2")?;
|
||||
assert_eq!(v2.x, 100.0);
|
||||
assert_eq!(v2.y, 10.0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
use std::{cell::RefMut, mem, ops::{Deref, DerefMut}};
|
||||
|
||||
use crate::{AnyUserdata, Result, State, Userdata, UserdataBuilder};
|
||||
|
||||
enum BorrowMut<'a, T> {
|
||||
Wrapped(RefMut<'a, T>),
|
||||
Raw(&'a mut T),
|
||||
}
|
||||
|
||||
impl<'a, T> Deref for BorrowMut<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
BorrowMut::Wrapped(w) => w,
|
||||
BorrowMut::Raw(w) => w,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> DerefMut for BorrowMut<'a, T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
match self {
|
||||
BorrowMut::Wrapped(w) => w,
|
||||
BorrowMut::Raw(w) => w,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UserdataRefMut<'a, T: Userdata> {
|
||||
borrow: BorrowMut<'a, T>,
|
||||
}
|
||||
|
||||
impl<'a, T: Userdata> From<&'a mut T> for UserdataRefMut<'static, T> {
|
||||
fn from(value: &'a mut T) -> Self {
|
||||
let ud = BorrowMut::Raw(value);
|
||||
|
||||
Self {
|
||||
borrow: unsafe {
|
||||
mem::transmute(ud)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Userdata> From<RefMut<'a, T>> for UserdataRefMut<'static, T> {
|
||||
fn from(value: RefMut<'a, T>) -> Self {
|
||||
let ud = BorrowMut::Wrapped(value);
|
||||
|
||||
Self {
|
||||
borrow: unsafe {
|
||||
mem::transmute(ud)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Userdata + 'static> Userdata for UserdataRefMut<'a, T> {
|
||||
fn build<'b>(state: &State, builder: &mut UserdataBuilder<'b, Self>) -> crate::Result<()> {
|
||||
let mut other = UserdataBuilder::<T>::new();
|
||||
T::build(state, &mut other)?;
|
||||
|
||||
builder.expand_with(other);
|
||||
|
||||
let getter: fn(AnyUserdata<'_>) -> Result<*const ()> = move |ud: AnyUserdata| {
|
||||
let ud_ptr = {
|
||||
let ud = ud.as_ref::<UserdataRefMut<T>>()?;
|
||||
|
||||
let ud_ptr: *const T = &*ud.borrow;
|
||||
ud_ptr
|
||||
};
|
||||
|
||||
Ok(ud_ptr.cast::<()>())
|
||||
};
|
||||
|
||||
let getter_mut: fn(AnyUserdata<'_>) -> Result<*mut ()> = move |ud: AnyUserdata| {
|
||||
let ud_ptr = {
|
||||
let mut ud = ud.as_mut::<UserdataRefMut<T>>()?;
|
||||
|
||||
let ud_ptr: *mut T = &mut *ud.borrow;
|
||||
ud_ptr
|
||||
};
|
||||
|
||||
Ok(ud_ptr.cast::<()>())
|
||||
};
|
||||
|
||||
if builder.wrapped_getter.set(Box::new(getter)).is_err() {
|
||||
panic!("Somehow the wrapped getter has already been set");
|
||||
}
|
||||
|
||||
if builder.wrapped_getter_mut.set(Box::new(getter_mut)).is_err() {
|
||||
panic!("Somehow the wrapped mutable getter has already been set");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn name() -> String {
|
||||
let name = format!("{}RefMut", T::name());
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::cell::RefCell;
|
||||
|
||||
use crate::{tests::Vec2, State, StdLibrary, Value};
|
||||
|
||||
use super::UserdataRefMut;
|
||||
|
||||
/// This test ensures that you can provide Lua a RefMut and it that it can set the fields on the userdata.
|
||||
#[test]
|
||||
fn ud_fields_borrow_mut() -> crate::Result<()> {
|
||||
let lua = State::new();
|
||||
lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]);
|
||||
|
||||
let globals = lua.globals()?;
|
||||
|
||||
let v1 = RefCell::new(Vec2 { x: 50.0, y: 5.0 });
|
||||
let ud = lua.create_userdata(UserdataRefMut::from(v1.borrow_mut()))?;
|
||||
globals.set("v1", ud)?;
|
||||
|
||||
let mut x = 50.0;
|
||||
let mut y = 5.0;
|
||||
|
||||
let chunk = lua.load(
|
||||
"text.lua",
|
||||
r#"
|
||||
v1.x = v1.x + 50
|
||||
v1.y = v1.y + 5
|
||||
print("v1: (" .. v1.x .. ", " .. v1.y .. ")")
|
||||
"#)?;
|
||||
|
||||
for _ in 0..40 {
|
||||
let res = lua.execute_chunk::<_, Value>(&chunk, ());
|
||||
|
||||
if let Err(e) = res {
|
||||
panic!("{}", e);
|
||||
}
|
||||
|
||||
//println!("i = {}", i);
|
||||
globals.set("v1", Value::Nil)?;
|
||||
lua.gc_collect()?; // must collect here to drop the RefMut
|
||||
|
||||
x += 50.0;
|
||||
y += 5.0;
|
||||
|
||||
let t = v1.borrow();
|
||||
assert_eq!(x, t.x);
|
||||
assert_eq!(y, t.y);
|
||||
drop(t);
|
||||
|
||||
let ud = lua.create_userdata(UserdataRefMut::from(v1.borrow_mut()))?;
|
||||
globals.raw_set("v1", ud)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This test ensures that a RefMut of userdata can be provided to Lua, and it that it can run mutating methods on the userdata.
|
||||
#[test]
|
||||
fn ud_methods_borrow_mut() -> crate::Result<()> {
|
||||
let lua = State::new();
|
||||
lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]);
|
||||
|
||||
let globals = lua.globals()?;
|
||||
|
||||
let v1 = RefCell::new(Vec2 { x: 50.0, y: 5.0 });
|
||||
let ud = lua.create_userdata(UserdataRefMut::from(v1.borrow_mut()))?;
|
||||
globals.set("v1", ud)?;
|
||||
|
||||
let chunk = lua.load(
|
||||
"text.lua",
|
||||
r#"
|
||||
v1:mult(2.0)
|
||||
print("v1: (" .. v1.x .. ", " .. v1.y .. ")")
|
||||
"#)?;
|
||||
|
||||
let res = lua.execute_chunk::<_, Value>(&chunk, ());
|
||||
|
||||
if let Err(e) = res {
|
||||
panic!("{}", e);
|
||||
}
|
||||
|
||||
globals.set("v1", Value::Nil)?;
|
||||
lua.gc_collect()?; // must collect here to drop the RefMut
|
||||
|
||||
let t = v1.borrow();
|
||||
assert_eq!(100.0, t.x);
|
||||
assert_eq!(10.0, t.y);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use std::{cell::{OnceCell, Ref, RefCell, RefMut}, collections::HashMap, ffi::CStr, marker::PhantomData, mem, ops::{Deref, DerefMut}, sync::Arc};
|
||||
use std::{cell::{OnceCell, Ref, RefCell, RefMut}, collections::HashMap, ffi::CStr, marker::PhantomData, mem, ops::DerefMut, sync::Arc};
|
||||
|
||||
use crate::{ensure_type, AsLua, FromLua, FromLuaStack, FromLuaVec, Function, IntoLuaVec, LuaRef, PushToLuaStack, StackGuard, State, Table, Value, ValueVec};
|
||||
|
||||
|
@ -15,6 +15,11 @@ pub mod borrow;
|
|||
#[allow(unused_imports)]
|
||||
use borrow::*;
|
||||
|
||||
pub mod borrow_mut;
|
||||
#[allow(unused_imports)]
|
||||
use borrow_mut::*;
|
||||
|
||||
|
||||
/// An enum representing all Lua MetaMethods
|
||||
/// https://gist.github.com/oatmealine/655c9e64599d0f0dd47687c1186de99f
|
||||
pub enum MetaMethod {
|
||||
|
@ -101,6 +106,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,
|
||||
|
@ -110,6 +117,7 @@ pub struct UserdataBuilder<'a, T> {
|
|||
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>,
|
||||
}
|
||||
|
@ -123,6 +131,7 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
|||
functions: HashMap::new(),
|
||||
meta_methods: HashMap::new(),
|
||||
wrapped_getter: Arc::new(OnceCell::new()),
|
||||
wrapped_getter_mut: Arc::new(OnceCell::new()),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -135,24 +144,22 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
|||
{
|
||||
let wrapped = self.wrapped_getter.clone();
|
||||
let wrapped: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'_>) -> Result<*const (), crate::Error>>>> = unsafe { mem::transmute(wrapped) };
|
||||
let fn_name = Arc::new(name.to_string());
|
||||
|
||||
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 = match getter(this.clone()) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
return Err(crate::Error::BadArgument {
|
||||
func: Some(fn_name.deref().clone()),
|
||||
arg_index: 1,
|
||||
arg_name: Some("self".to_string()),
|
||||
error: Arc::new(e),
|
||||
});
|
||||
}
|
||||
};
|
||||
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 };
|
||||
|
||||
|
@ -173,22 +180,43 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
|||
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 mut this = this.as_mut::<T>()?;
|
||||
|
||||
let lua_val = val.pop_front().unwrap();
|
||||
let v_arg = V::from_lua(lua, lua_val)?;
|
||||
|
||||
f(lua, this.deref_mut(), v_arg).as_lua(lua)
|
||||
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 result_to_bad_arg<R>(res: crate::Result<R>, ud_name: &str, fn_name: &str) -> crate::Result<R> {
|
||||
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);
|
||||
|
@ -200,17 +228,27 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
|||
})
|
||||
}
|
||||
|
||||
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::result_to_bad_arg(
|
||||
let args = Self::arg_result_to_bad_arg(
|
||||
A::from_lua_value_vec(lua, val),
|
||||
&T::name(), &fn_name
|
||||
&ud_name, &fn_name
|
||||
)?;
|
||||
f(lua, args).and_then(|r| r.as_lua(lua))
|
||||
};
|
||||
|
@ -226,20 +264,83 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
|||
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
|
||||
//this.unsafe_ud.as_ptr_unchecked()
|
||||
let this = this.as_ref::<T>()?;
|
||||
|
||||
let this_name = T::name();
|
||||
let args = Self::result_to_bad_arg(
|
||||
let args = Self::arg_result_to_bad_arg(
|
||||
A::from_lua_value_vec(lua, val),
|
||||
&this_name, &fn_name
|
||||
&ud_name, &fn_name
|
||||
)?;
|
||||
|
||||
f(lua, &*this, args).and_then(|r| r.as_lua(lua))
|
||||
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));
|
||||
|
||||
|
@ -254,16 +355,16 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
|||
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 this_name = T::name();
|
||||
let args = Self::result_to_bad_arg(
|
||||
let args = Self::arg_result_to_bad_arg(
|
||||
A::from_lua_value_vec(lua, val),
|
||||
&this_name, &fn_name
|
||||
&ud_name, &fn_name
|
||||
)?;
|
||||
|
||||
f(lua, &*this, args).and_then(|r| r.as_lua(lua))
|
||||
|
@ -280,6 +381,7 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
|||
self.functions = other.functions;
|
||||
self.meta_methods = other.meta_methods;
|
||||
self.wrapped_getter = other.wrapped_getter;
|
||||
self.wrapped_getter_mut = other.wrapped_getter_mut;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue