#![cfg(feature = "macros")]
use luaur_rt::{FromLua as _, IntoLua as _, Lua, Result, UserData};
#[derive(Default, Clone, Debug, UserData)]
struct Rectangle {
length: u32,
#[lua]
width: u32,
#[lua(get, name = "version")]
version_ro: u32,
#[lua(skip)]
_internal: u64,
}
#[test]
fn test_rectangle_fields() -> Result<()> {
let lua = Lua::new();
let rect = Rectangle {
length: 5,
width: 10,
version_ro: 1,
_internal: 99,
};
lua.globals().set("rect", lua.create_userdata(rect)?)?;
lua.load(
r#"
-- default get + set fields
assert(rect.length == 5, "length should be 5")
assert(rect.width == 10, "width should be 10")
-- read-only renamed field
assert(rect.version == 1, "version should be 1")
local ok = pcall(function() rect.version = 2 end)
assert(not ok, "version should be read-only")
-- skipped field is invisible
assert(rect._internal == nil, "_internal should be nil")
assert(rect.version_ro == nil, "the original ident is not exposed; only the renamed 'version' is")
-- setters work and are observable
rect.length = 15
rect.width = 20
assert(rect.length == 15, "length should be updated to 15")
assert(rect.width == 20, "width should be updated to 20")
"#,
)
.exec()?;
let ud = lua.globals().get::<luaur_rt::AnyUserData>("rect")?;
let stored = ud.borrow::<Rectangle>()?;
assert_eq!(stored.length, 15);
assert_eq!(stored.width, 20);
assert_eq!(stored._internal, 99);
Ok(())
}
#[derive(Clone, Debug, UserData)]
struct Point(#[allow(dead_code)] i32, #[allow(dead_code)] i32);
#[derive(Clone, Debug, UserData)]
#[allow(dead_code)]
enum Color {
Red,
Green,
Blue,
}
#[test]
fn test_fieldless_userdata_derive() -> Result<()> {
let lua = Lua::new();
lua.globals().set("p", lua.create_userdata(Point(3, 4))?)?;
lua.globals().set("c", lua.create_userdata(Color::Green)?)?;
lua.load(
r#"
assert(type(p) == "userdata", "Point should be userdata")
assert(type(c) == "userdata", "Color should be userdata")
assert(p.x == nil, "Point exposes no fields")
"#,
)
.exec()?;
Ok(())
}
#[derive(Clone, Copy, Debug, PartialEq, luaur_rt::FromLua)]
struct MyValue(i32);
impl UserData for MyValue {}
#[test]
fn test_from_lua_derive() -> Result<()> {
let lua = Lua::new();
let ud = lua.create_userdata(MyValue(123))?;
lua.globals().set("v", &ud)?;
let f = lua.create_function(|_, v: MyValue| Ok(v.0 * 2))?;
lua.globals().set("double", f)?;
let doubled: i32 = lua.load("return double(v)").eval()?;
assert_eq!(doubled, 246);
let value: luaur_rt::Value = ud.into_lua(&lua)?;
let recovered = MyValue::from_lua(value, &lua)?;
assert_eq!(recovered, MyValue(123));
let err = MyValue::from_lua(luaur_rt::Value::Integer(7), &lua).unwrap_err();
assert!(
matches!(&err, luaur_rt::Error::FromLuaConversionError { to, .. } if to == "MyValue"),
"expected FromLuaConversionError to MyValue, got {err:?}"
);
Ok(())
}