Create a helper Proxy struct for retriving proxied types as function arguments
This commit is contained in:
parent
7dc4380d5c
commit
845ddd4f80
125
src/table.rs
125
src/table.rs
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
use mlua_sys as lua;
|
use mlua_sys as lua;
|
||||||
|
|
||||||
use crate::{ensure_type, AsLua, FromLua, FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuard, State, Value};
|
use crate::{ensure_type, AsLua, FromLua, FromLuaStack, LuaRef, PushToLuaStack, Result, StackGuard, State, Value};
|
||||||
|
@ -324,14 +323,67 @@ impl<'a> AsLua<'a> for Table<'a> {
|
||||||
/// with minimizing the amount of calls to and from Rust.
|
/// with minimizing the amount of calls to and from Rust.
|
||||||
pub trait TableProxy: Sized {
|
pub trait TableProxy: Sized {
|
||||||
/// Create an instance of `Self` from the table
|
/// Create an instance of `Self` from the table
|
||||||
fn from_table<'a>(state: &'a State, table: Table<'a>) -> Result<Self>;
|
fn from_table<'a>(lua: &'a State, table: Table<'a>) -> Result<Self>;
|
||||||
/// Creates a Lua instance from `Self`
|
/// Creates a Lua instance from `Self`
|
||||||
fn as_table<'a>(&self, state: &'a State) -> Result<Table<'a>>;
|
fn as_table<'a>(&self, state: &'a State) -> Result<Table<'a>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A struct that wraps a Proxied value. It can be used to get
|
||||||
|
pub struct Proxy<T: TableProxy> {
|
||||||
|
data: Option<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: TableProxy> Proxy<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
data: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the data from the proxy, if there is no data, it will panic.
|
||||||
|
pub fn take(self) -> T {
|
||||||
|
self.data
|
||||||
|
.expect("the proxy was not provided any data")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the data from the proxy, returns `None` if the Proxy has no data.
|
||||||
|
pub fn try_take(self) -> Option<T> {
|
||||||
|
self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: TableProxy> From<T> for Proxy<T> {
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
Self {
|
||||||
|
data: Some(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// should proxying from lua be implicit by implementing this trait for T, instead of Proxy?
|
||||||
|
// it would make it easier, but its more difficult to tell if code is proxying from lua, or
|
||||||
|
// getting a borrow.
|
||||||
|
impl<'a, T: TableProxy> FromLua<'a> for Proxy<T> {
|
||||||
|
fn from_lua(lua: &'a State, val: Value<'a>) -> crate::Result<Self> {
|
||||||
|
let table = val.into_table()?;
|
||||||
|
let t = T::from_table(lua, table)?;
|
||||||
|
|
||||||
|
Ok(Self::from(t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: TableProxy> AsLua<'a> for Proxy<T> {
|
||||||
|
fn as_lua(&self, lua: &'a State) -> crate::Result<Value<'a>> {
|
||||||
|
self.data.as_ref()
|
||||||
|
.ok_or(crate::Error::Nil)
|
||||||
|
.and_then(|d| d.as_table(lua))
|
||||||
|
.map(|t| Value::Table(t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{tests::Vec2, Function, State, StdLibrary, Table, TableProxy};
|
use crate::{tests::Vec2, Function, Proxy, State, StdLibrary, Table, TableProxy};
|
||||||
|
|
||||||
impl TableProxy for Vec2 {
|
impl TableProxy for Vec2 {
|
||||||
fn from_table<'a>(_state: &'a crate::State, table: crate::Table<'a>) -> crate::Result<Self> {
|
fn from_table<'a>(_state: &'a crate::State, table: crate::Table<'a>) -> crate::Result<Self> {
|
||||||
|
@ -461,4 +513,71 @@ mod tests {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn table_proxy_value() -> crate::Result<()> {
|
||||||
|
let lua = State::new();
|
||||||
|
lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]);
|
||||||
|
|
||||||
|
let globals = lua.globals()?;
|
||||||
|
let add_fn = lua.create_function(|_, (a, b): (Proxy<Vec2>, Proxy<Vec2>)| {
|
||||||
|
let a = a.take();
|
||||||
|
let b = b.take();
|
||||||
|
|
||||||
|
let x = a.x + b.x;
|
||||||
|
let y = a.y + b.y;
|
||||||
|
|
||||||
|
Ok(Proxy::from(
|
||||||
|
Vec2 {
|
||||||
|
x,
|
||||||
|
y
|
||||||
|
}
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
globals.set("add_vec2", add_fn)?;
|
||||||
|
|
||||||
|
let res = lua.load(
|
||||||
|
"test.lua",
|
||||||
|
r#"
|
||||||
|
require("util")
|
||||||
|
|
||||||
|
Vec2 = { x = 0.0, y = 0.0 }
|
||||||
|
Vec2.__index = Vec2
|
||||||
|
Vec2.__name = "Vec2"
|
||||||
|
|
||||||
|
function Vec2:new(x, y)
|
||||||
|
local v = {}
|
||||||
|
setmetatable(v, Vec2)
|
||||||
|
|
||||||
|
v.x = x
|
||||||
|
v.y = y
|
||||||
|
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
|
||||||
|
function Vec2:__tostring()
|
||||||
|
return "Vec2(" .. self.x .. ", " .. self.y .. ")"
|
||||||
|
end
|
||||||
|
|
||||||
|
function do_math()
|
||||||
|
return Vec2:new(15, 20)
|
||||||
|
end
|
||||||
|
|
||||||
|
local v1 = Vec2:new(15, 20)
|
||||||
|
local v2 = Vec2:new(7, 10)
|
||||||
|
local v3 = add_vec2(v1, v2)
|
||||||
|
|
||||||
|
assert(v3.x == 22 and v3.y == 30, "The result from adding the values was incorrect!")
|
||||||
|
|
||||||
|
--print("v3 is " .. dump_table(v3))
|
||||||
|
--print("Added together, v3 is " .. tostring(v3))
|
||||||
|
"#)?.execute::<_, ()>(());
|
||||||
|
|
||||||
|
// pretty print the error
|
||||||
|
if let Err(err) = res {
|
||||||
|
panic!("{}", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue