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 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.
|
||||
pub trait TableProxy: Sized {
|
||||
/// 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`
|
||||
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)]
|
||||
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 {
|
||||
fn from_table<'a>(_state: &'a crate::State, table: crate::Table<'a>) -> crate::Result<Self> {
|
||||
|
@ -461,4 +513,71 @@ mod tests {
|
|||
|
||||
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