llua 0.1.3

Low level bindings to Lua5.4
Documentation
#![cfg(feature = "vendored")]

use crate::*;

use alloc::rc::Rc;

struct Test {
    a: i32,
}

impl UserData for Test {
    fn methods(mt: &ValRef) {
        mt.register("inc", |this: &mut Self| this.a += 1);
    }

    fn getter(fields: &ValRef) {
        fields.register("a", |this: &Self| this.a);
    }

    fn setter(fields: &ValRef) {
        fields.register("a", |this: &mut Self, val: i32| this.a = val);
    }
}

impl UserData for Rc<Test> {
    fn key_to_cache(&self) -> *const () {
        self.as_ref() as *const _ as _
    }

    fn getter(fields: &ValRef) {
        fields.register("a", |this: &Self| this.a);
    }
}

#[test]
fn userdata() {
    let s = State::new();
    s.open_base();
    s.push(Test { a: 0 });
    let uv = s.val(-1);
    assert_eq!(uv.type_of(), Type::Userdata);
    s.global().set("uv", uv);
    let test_value = 0x11223344;
    s.global().set("test", RsFn::new(move || test_value));
    s.global().set("toiter", RsFn::new(|| BoxIter::new(0..3)));
    s.do_string(
        r#"
        local iter = toiter()
        assert(iter() == 0)
        assert(iter() == 1)
        assert(iter() == 2)
    "#,
    )
    .unwrap();

    s.do_string("assert(test() == 0x11223344)").unwrap();

    s.do_string("print(getmetatable(uv), type(uv))");
    s.do_string("assert(uv.a == 0)").unwrap();
    s.do_string("uv:inc(); assert(uv.a == 1)").unwrap();
    s.do_string("uv.a = 3; assert(uv.a == 3)").unwrap();

    let test = Rc::new(Test { a: 123 });
    s.global().set("uv", test.clone());
    s.global().set("uv1", test.clone());
    s.do_string("print(uv, uv1)");
    s.do_string("assert(uv == uv1)").unwrap();
    s.do_string("assert(uv.a == 123)").unwrap();
}

#[test]
fn serde() {
    use ::serde::{Deserialize, Serialize};

    #[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
    struct Test<'a> {
        str: &'a str,
        int: i32,
        flt: f64,
    }

    let s = State::new();
    s.open_base();
    let global = s.global();
    let test = Test {
        str: "abc",
        int: 333,
        flt: 123.0,
    };
    global.set("test", SerdeValue(test.clone()));
    s.do_string("print(test)");
    let t = global.getopt::<_, SerdeValue<Test>>("test").unwrap().0;
    assert_eq!(test, t);

    global.set("test", 1234);
    let t = global.getopt::<_, CRegVal>("test").unwrap();
    global.set("test", SerdeValue(t));
    s.do_string("print('regval', test)").unwrap();
}

#[test]
fn binding() {
    let s = State::new();
    s.open_libs();
    s.init_llua_global();

    s.do_string(
        r"
        testpath = os.getexe()
        local meta = os.path.meta(testpath)
        print(testpath, meta)
        assert(meta.size == meta:len())
        assert(not meta.readonly)
        assert(meta:is_file())
    ",
    )
    .unwrap();
}

#[no_mangle]
extern "C" fn llua_open_libs(_: &State) {}

#[cfg(feature = "regex")]
#[test]
fn regex_binding() {
    let s = State::new();
    s.open_libs();
    s.init_llua_global();

    s.do_string(
        r"
        local re = require 'regex'
        local cap = re.new[[(\w+)\s+(\w+)]]:capture 'abc def'
        assert(cap[1] == 'abc')
        assert(cap[2] == 'def')
    ",
    )
    .unwrap();
}

#[cfg(feature = "thread")]
#[test]
fn test_thread() {
    let s = State::new();
    s.open_libs();
    s.init_llua_global();
    s.do_file("tests/thread.lua").unwrap();
}