luau 0.732.0

Safe lifetime-bound Rust embedding API for the Luau runtime
#![cfg(feature = "macros")]

use luau::{AnyUserdata, Error, FromLua, Lua, ObjectLike, Table, Userdata};

mod userdata_macro {
    pub(super) mod methods;
    pub(super) mod properties;
}

#[derive(Clone, Debug, Userdata, FromLua)]
struct MacroCounter {
    value: i32,
    #[luau(set)]
    secret: String,
}

#[test]
fn derived_userdata_composes_impls_and_lending_arguments() -> Result<(), Error> {
    let lua = Lua::new()?;
    let proxy = lua.create_proxy::<MacroCounter>()?;
    lua.globals()?.set("Counter", proxy)?;

    let (counter, other): (AnyUserdata<'_>, AnyUserdata<'_>) = lua
        .load(
            r#"
            local counter = Counter(10, "first")
            local other = Counter.new(5, "second")

            assert(counter.value == 10)
            counter.value = 12
            counter.secret = "changed"
            assert(counter.secret == nil)
            assert(counter.doubled == 24)
            assert(Counter.KIND == "counter")
            assert(Counter.metadata.category == "number")
            counter.positive = 7
            assert(counter.positive == 7)
            local description = counter:describe("value", "raw", other, nil)
            assert(description == "value:3:7:5:none", description)

            return counter, other
            "#,
        )
        .call(())?;

    assert_eq!(counter.borrow::<MacroCounter>()?.value, 7);
    assert_eq!(counter.borrow::<MacroCounter>()?.secret, "changed");

    let cloned = lua.unpack::<MacroCounter>(luau::Value::Userdata(other.try_clone()?))?;
    assert_eq!(cloned.value, 5);

    let table = lua.create_table()?;
    table.set("answer", 42)?;
    let returned: Table<'_> = counter.call_method("identity", table)?;
    assert_eq!(returned.get::<i32>("answer")?, 42);

    assert_eq!(counter.call_method::<i32>("take", ())?, 7);
    assert!(matches!(
        counter.borrow::<MacroCounter>(),
        Err(Error::UserdataDestructed)
    ));

    Ok(())
}