Create TableProxy trait and some table tests

This commit is contained in:
SeanOMik 2024-02-10 21:00:58 -05:00
parent bed5091ecd
commit 7dc4380d5c
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
1 changed files with 161 additions and 1 deletions

View File

@ -279,6 +279,14 @@ impl<'a> Table<'a> {
Ok(())
}
pub fn try_into<T: TableProxy>(self) -> Result<T> {
T::from_table(self.state, self)
}
pub fn try_from<T: TableProxy + Sized>(state: &'a State, proxy: T) -> Result<Table<'a>> {
proxy.as_table(state)
}
}
impl<'a> PushToLuaStack<'a> for Table<'a> {
@ -298,7 +306,159 @@ impl<'a> FromLuaStack<'a> for Table<'a> {
}
impl<'a> FromLua<'a> for Table<'a> {
fn from_lua(_lua: &'a State, val: Value<'a>) -> crate::Result<Self> {
fn from_lua(_: &'a State, val: Value<'a>) -> crate::Result<Self> {
val.into_table()
}
}
impl<'a> AsLua<'a> for Table<'a> {
fn as_lua(&self, _: &'a State) -> crate::Result<Value<'a>> {
Ok(Value::Table(self.clone()))
}
}
/// This trait is used for proxying a Rust type to and from Lua as a Lua table. In Lua, you can
/// make a representation of your Rust type, then implement this trait on the Rust type. This
/// trait allows you to put your Rust type into Lua as the type you created in Lua, and you can
/// also retrieve an instance of your Rust type from an instance of the Lua type. This could help
/// 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>;
/// Creates a Lua instance from `Self`
fn as_table<'a>(&self, state: &'a State) -> Result<Table<'a>>;
}
#[cfg(test)]
mod tests {
use crate::{tests::Vec2, Function, State, StdLibrary, Table, TableProxy};
impl TableProxy for Vec2 {
fn from_table<'a>(_state: &'a crate::State, table: crate::Table<'a>) -> crate::Result<Self> {
let x: f32 = table.get("x")?;
let y: f32 = table.get("y")?;
Ok(Vec2 {
x,
y,
})
}
fn as_table<'a>(&self, state: &'a crate::State) -> crate::Result<crate::Table<'a>> {
let globals = state.globals()?;
let vec2: Table = globals.get("Vec2")?;
let new_fn: Function = vec2.get("new")?;
new_fn.exec((vec2, self.x, self.y))
}
}
#[test]
fn table_get() -> crate::Result<()> {
let lua = State::new();
lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]);
let res = lua.load(
"test.lua",
r#"
text = "Hello, World"
"#)?.execute::<_, ()>(());
// pretty print the error
if let Err(err) = res {
panic!("{}", err);
}
let globals = lua.globals()?;
let text: String = globals.get("text")?;
assert_eq!(text, "Hello, World".to_string());
Ok(())
}
#[test]
fn table_set() -> crate::Result<()> {
let lua = State::new();
lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]);
let globals = lua.globals()?;
globals.set("text", "Hello, World")?;
let res = lua.load(
"test.lua",
r#"
assert(text == "Hello, World", "The text was not set correctly")
"#)?.execute::<_, ()>(());
// pretty print the error
if let Err(err) = res {
panic!("{}", err);
}
Ok(())
}
#[test]
fn table_proxy() -> crate::Result<()> {
let lua = State::new();
lua.expose_libraries(&[StdLibrary::Debug, StdLibrary::Package]);
let res = lua.load(
"test.lua",
r#"
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
"#)?.execute::<_, ()>(());
// pretty print the error
if let Err(err) = res {
panic!("{}", err);
}
let globals = lua.globals()?;
let math_fn: Function = globals.get("do_math")?;
let lua_vec2: Table = math_fn.exec(())?;
let mut vec2 = Vec2::from_table(&lua, lua_vec2)?;
assert_eq!(vec2.x, 15.0);
assert_eq!(vec2.y, 20.0);
vec2.x *= 2.0;
vec2.y *= 2.0;
globals.set("pos", vec2.as_table(&lua)?)?;
let res = lua.load(
"test.lua",
r#"
-- Vec2 stuff is included from last chunk
assert(type(pos) == "table", "The global 'pos' is not a table like expected of 'as_table'!!")
print("pos is " .. tostring(pos))
"#)?.execute::<_, ()>(());
// pretty print the error
if let Err(err) = res {
panic!("{}", err);
}
Ok(())
}
}