use luna_core::vm::{LuaUserdata, MetaMethod, UserdataMethods};
use luna_jit::Lua;
use std::time::SystemTime;
#[derive(Debug)]
struct Counter {
value: i64,
last_updated: SystemTime,
}
impl Counter {
fn new(initial: i64) -> Self {
Counter {
value: initial,
last_updated: SystemTime::now(),
}
}
}
impl LuaUserdata for Counter {
fn type_name() -> &'static str {
"Counter"
}
fn add_methods<M: UserdataMethods<Self>>(m: &mut M) {
m.add_method("get", |_vm, this, ()| Ok::<_, _>(this.value));
m.add_method_mut("incr", |_vm, this, (by,): (i64,)| {
this.value += by;
this.last_updated = SystemTime::now();
Ok::<_, _>(())
});
m.add_method_mut("set", |_vm, this, (v,): (i64,)| {
this.value = v;
this.last_updated = SystemTime::now();
Ok::<_, _>(())
});
m.add_meta_method(MetaMethod::ToString, |_vm, this, ()| {
Ok::<_, _>(format!("Counter({})", this.value))
});
}
}
fn main() {
let mut lua = Lua::new();
lua.open_base();
lua.vm()
.set_userdata("counter", Counter::new(100))
.expect("install counter");
let kind: String = lua.eval("return type(counter)").unwrap();
assert_eq!(kind, "userdata");
println!("1. type(counter) = {kind:?}");
let v: i64 = lua.eval("return counter:get()").unwrap();
assert_eq!(v, 100);
println!("2. counter:get() = {v}");
lua.eval_multi("counter:incr(50)").unwrap();
let v: i64 = lua.eval("return counter:get()").unwrap();
assert_eq!(v, 150);
println!("3. after counter:incr(50): counter:get() = {v}");
let s: String = lua.eval("return tostring(counter)").unwrap();
assert_eq!(s, "Counter(150)");
println!("4. tostring(counter) = {s:?}");
{
let c: &Counter = lua.vm().userdata_borrow("counter").unwrap();
assert_eq!(c.value, 150);
println!("5. host reads: counter.value = {}", c.value);
}
{
let c: &mut Counter = lua.vm().userdata_borrow_mut("counter").unwrap();
c.value = 999;
println!("6. host writes: counter.value = 999");
}
let v: i64 = lua.eval("return counter:get()").unwrap();
assert_eq!(v, 999);
println!("7. after host write: counter:get() = {v}");
{
let wrong: Option<&String> = lua.vm().userdata_borrow("counter");
assert!(wrong.is_none());
println!("8. wrong-type downcast: None (correctly typechecks)");
}
lua.vm().collect_garbage();
let v: i64 = lua.eval("return counter:get()").unwrap();
assert_eq!(v, 999);
println!("9. after GC: counter:get() = {v}");
println!("\nuserdata_demo: all checks passed.");
}