Create UserdataRefMut, create tests for UserdataRef and UserdataRefMut
This commit is contained in:
parent
80b9a4ef35
commit
25f4116278
|
@ -40,6 +40,27 @@
|
||||||
},
|
},
|
||||||
"args": [],
|
"args": [],
|
||||||
"cwd": "${workspaceFolder}"
|
"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};
|
use crate::{MetaMethod, State, Userdata, UserdataBuilder};
|
||||||
|
|
||||||
pub struct Vec2 {
|
pub struct Vec2 {
|
||||||
x: f32,
|
pub x: f32,
|
||||||
y: f32,
|
pub y: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Userdata for Vec2 {
|
impl Userdata for Vec2 {
|
||||||
|
@ -28,6 +28,18 @@ impl Userdata for Vec2 {
|
||||||
y: ly + ry,
|
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>,)| {
|
.meta_method(MetaMethod::Add, |lua, lhs: &Vec2, (rhs,): (Ref<Vec2>,)| {
|
||||||
let lx = lhs.x;
|
let lx = lhs.x;
|
||||||
let ly = lhs.y;
|
let ly = lhs.y;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{cell::Ref, mem, ops::Deref};
|
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> {
|
enum Borrow<'a, T> {
|
||||||
Wrapped(Ref<'a, T>),
|
Wrapped(Ref<'a, T>),
|
||||||
|
@ -64,10 +64,18 @@ impl<'a, T: Userdata + 'static> Userdata for UserdataRef<'a, T> {
|
||||||
Ok(ud_ptr.cast::<()>())
|
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() {
|
if builder.wrapped_getter.set(Box::new(getter)).is_err() {
|
||||||
panic!("Somehow the wrapped getter has already been set");
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,3 +84,85 @@ impl<'a, T: Userdata + 'static> Userdata for UserdataRef<'a, T> {
|
||||||
name
|
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};
|
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)]
|
#[allow(unused_imports)]
|
||||||
use borrow::*;
|
use borrow::*;
|
||||||
|
|
||||||
|
pub mod borrow_mut;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use borrow_mut::*;
|
||||||
|
|
||||||
|
|
||||||
/// An enum representing all Lua MetaMethods
|
/// An enum representing all Lua MetaMethods
|
||||||
/// https://gist.github.com/oatmealine/655c9e64599d0f0dd47687c1186de99f
|
/// https://gist.github.com/oatmealine/655c9e64599d0f0dd47687c1186de99f
|
||||||
pub enum MetaMethod {
|
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 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 struct UserdataBuilder<'a, T> {
|
||||||
pub(crate) name: String,
|
pub(crate) name: String,
|
||||||
|
@ -110,6 +117,7 @@ pub struct UserdataBuilder<'a, T> {
|
||||||
pub(crate) meta_methods: 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: 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>,
|
_marker: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
@ -123,6 +131,7 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
||||||
functions: HashMap::new(),
|
functions: HashMap::new(),
|
||||||
meta_methods: HashMap::new(),
|
meta_methods: HashMap::new(),
|
||||||
wrapped_getter: Arc::new(OnceCell::new()),
|
wrapped_getter: Arc::new(OnceCell::new()),
|
||||||
|
wrapped_getter_mut: Arc::new(OnceCell::new()),
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,24 +144,22 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
||||||
{
|
{
|
||||||
let wrapped = self.wrapped_getter.clone();
|
let wrapped = self.wrapped_getter.clone();
|
||||||
let wrapped: Arc<OnceCell<Box<dyn Fn(AnyUserdata<'_>) -> Result<*const (), crate::Error>>>> = unsafe { mem::transmute(wrapped) };
|
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 wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||||
let val = val.pop_front().unwrap();
|
let val = val.pop_front().unwrap();
|
||||||
let this = val.as_userdata().unwrap(); // if this panics, its a bug
|
let this = val.as_userdata().unwrap(); // if this panics, its a bug
|
||||||
|
|
||||||
if let Some(getter) = wrapped.get() {
|
if let Some(getter) = wrapped.get() {
|
||||||
let this_ptr = match getter(this.clone()) {
|
let this_ptr = Self::result_to_bad_arg(
|
||||||
Ok(v) => v,
|
getter(this.clone()),
|
||||||
Err(e) => {
|
&ud_name,
|
||||||
return Err(crate::Error::BadArgument {
|
&fn_name,
|
||||||
func: Some(fn_name.deref().clone()),
|
1,
|
||||||
arg_index: 1,
|
Some("self")
|
||||||
arg_name: Some("self".to_string()),
|
)?;
|
||||||
error: Arc::new(e),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let this_ptr = this_ptr.cast::<T>();
|
let this_ptr = this_ptr.cast::<T>();
|
||||||
let this = unsafe { &*this_ptr };
|
let this = unsafe { &*this_ptr };
|
||||||
|
|
||||||
|
@ -173,22 +180,43 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
||||||
V: FromLua<'a>,
|
V: FromLua<'a>,
|
||||||
T: Userdata + 'static
|
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 wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||||
let lua_val = val.pop_front().unwrap();
|
let lua_val = val.pop_front().unwrap();
|
||||||
let this = lua_val.as_userdata().unwrap(); // if this panics, its a bug
|
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 lua_val = val.pop_front().unwrap();
|
||||||
let v_arg = V::from_lua(lua, lua_val)?;
|
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)
|
f(lua, this.deref_mut(), v_arg).as_lua(lua)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
self.field_setters.insert(name.to_string(), Box::new(wrap));
|
self.field_setters.insert(name.to_string(), Box::new(wrap));
|
||||||
|
|
||||||
self
|
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 {
|
res.map_err(|e| match e {
|
||||||
crate::Error::ValueVecError { value_idx, error } => {
|
crate::Error::ValueVecError { value_idx, error } => {
|
||||||
let full_name = format!("{}.{}", ud_name, fn_name);
|
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
|
pub fn function<F, R, A>(&mut self, name: &str, f: F) -> &mut Self
|
||||||
where
|
where
|
||||||
F: Fn(&'a State, A) -> crate::Result<R> + 'static,
|
F: Fn(&'a State, A) -> crate::Result<R> + 'static,
|
||||||
A: FromLuaVec<'a>,
|
A: FromLuaVec<'a>,
|
||||||
R: AsLua<'a>,
|
R: AsLua<'a>,
|
||||||
{
|
{
|
||||||
|
let ud_name = self.name.clone();
|
||||||
let fn_name = name.to_string();
|
let fn_name = name.to_string();
|
||||||
let wrap = move |lua: &'a State, val: ValueVec<'a>| {
|
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),
|
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))
|
f(lua, args).and_then(|r| r.as_lua(lua))
|
||||||
};
|
};
|
||||||
|
@ -226,20 +264,83 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
||||||
R: AsLua<'a>,
|
R: AsLua<'a>,
|
||||||
T: Userdata + 'static
|
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 fn_name = name.to_string();
|
||||||
|
|
||||||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||||
let this_val = val.pop_front().unwrap();
|
let this_val = val.pop_front().unwrap();
|
||||||
let this = this_val.as_userdata().unwrap(); // if this panics, its a bug
|
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::arg_result_to_bad_arg(
|
||||||
let args = Self::result_to_bad_arg(
|
|
||||||
A::from_lua_value_vec(lua, val),
|
A::from_lua_value_vec(lua, val),
|
||||||
&this_name, &fn_name
|
&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))
|
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.functions.insert(name.to_string(), Box::new(wrap));
|
||||||
|
|
||||||
|
@ -254,16 +355,16 @@ impl<'a, T: Userdata> UserdataBuilder<'a, T> {
|
||||||
R: AsLua<'a>,
|
R: AsLua<'a>,
|
||||||
T: Userdata + 'static
|
T: Userdata + 'static
|
||||||
{
|
{
|
||||||
|
let ud_name = self.name.clone();
|
||||||
let fn_name = name.as_ref().to_string();
|
let fn_name = name.as_ref().to_string();
|
||||||
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
let wrap = move |lua: &'a State, mut val: ValueVec<'a>| {
|
||||||
let this_val = val.pop_front().unwrap();
|
let this_val = val.pop_front().unwrap();
|
||||||
let this = this_val.as_userdata().unwrap(); // if this panics, its a bug
|
let this = this_val.as_userdata().unwrap(); // if this panics, its a bug
|
||||||
let this = this.as_ref::<T>()?;
|
let this = this.as_ref::<T>()?;
|
||||||
|
|
||||||
let this_name = T::name();
|
let args = Self::arg_result_to_bad_arg(
|
||||||
let args = Self::result_to_bad_arg(
|
|
||||||
A::from_lua_value_vec(lua, val),
|
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))
|
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.functions = other.functions;
|
||||||
self.meta_methods = other.meta_methods;
|
self.meta_methods = other.meta_methods;
|
||||||
self.wrapped_getter = other.wrapped_getter;
|
self.wrapped_getter = other.wrapped_getter;
|
||||||
|
self.wrapped_getter_mut = other.wrapped_getter_mut;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue