use lua_rs_derive::{lua_methods, LuaUserData};
use lua_rs_runtime::Lua;
struct Engine {
_frame: u64,
}
#[derive(LuaUserData)]
#[lua(methods)]
struct ScriptApp {
engine: Engine,
pub tick: i64,
}
#[lua_methods]
impl ScriptApp {
pub fn step(&mut self) -> i64 {
self.engine._frame += 1;
self.tick += 1;
self.tick
}
}
#[test]
fn private_non_clone_field_is_opaque_but_methods_work() {
let lua = Lua::new();
lua.globals()
.set(
"app",
ScriptApp {
engine: Engine { _frame: 0 },
tick: 0,
},
)
.unwrap();
let engine_is_nil: bool = lua.load("return app.engine == nil").eval().unwrap();
assert!(engine_is_nil, "private field must not be exposed");
let after: i64 = lua.load("app:step(); return app:step()").eval().unwrap();
assert_eq!(after, 2);
let tick: i64 = lua.load("return app.tick").eval().unwrap();
assert_eq!(tick, 2);
}
#[derive(LuaUserData)]
#[lua(methods)]
#[repr(transparent)]
struct Counter(i64);
#[lua_methods]
impl Counter {
pub fn bump(&mut self, by: i64) -> i64 {
self.0 += by;
self.0
}
pub fn get(&self) -> i64 {
self.0
}
}
#[test]
fn tuple_newtype_is_opaque_handle_with_methods() {
let lua = Lua::new();
lua.globals().set("c", Counter(10)).unwrap();
let got: i64 = lua.load("c:bump(5); return c:get()").eval().unwrap();
assert_eq!(got, 15);
let pos_is_nil: bool = lua
.load("return c[0] == nil and c[1] == nil")
.eval()
.unwrap();
assert!(pos_is_nil, "tuple struct must expose no positional fields");
}
#[derive(LuaUserData)]
struct Record {
pub x: f64,
pub name: String,
}
#[test]
fn public_fields_still_auto_expose_and_round_trip() {
let lua = Lua::new();
lua.globals()
.set(
"r",
Record {
x: 1.5,
name: "init".to_string(),
},
)
.unwrap();
let x: f64 = lua.load("return r.x").eval().unwrap();
assert_eq!(x, 1.5);
let name: String = lua.load("return r.name").eval().unwrap();
assert_eq!(name, "init");
lua.load("r.x = 9.0; r.name = 'updated'").exec().unwrap();
let x: f64 = lua.load("return r.x").eval().unwrap();
assert_eq!(x, 9.0);
let name: String = lua.load("return r.name").eval().unwrap();
assert_eq!(name, "updated");
}
#[derive(LuaUserData)]
struct Legacy {
#[lua(field)]
hidden: i64,
pub shown: i64,
}
#[test]
fn lua_field_force_exposes_a_private_field() {
let lua = Lua::new();
lua.globals()
.set("o", Legacy { hidden: 7, shown: 3 })
.unwrap();
let hidden: i64 = lua.load("return o.hidden").eval().unwrap();
assert_eq!(hidden, 7, "#[lua(field)] should force-expose a private field");
let shown: i64 = lua.load("return o.shown").eval().unwrap();
assert_eq!(shown, 3);
lua.load("o.hidden = 100").exec().unwrap();
let hidden: i64 = lua.load("return o.hidden").eval().unwrap();
assert_eq!(hidden, 100);
}