8 个版本

使用旧版 Rust 2015

0.1.3 2024年7月16日
0.1.2 2018年10月20日
0.1.1 2017年8月17日
0.1.0 2016年12月22日
0.0.1 2015年1月3日

#307开发工具 中排名

Download history 282/week @ 2024-04-26 381/week @ 2024-05-03 308/week @ 2024-05-10 376/week @ 2024-05-17 359/week @ 2024-05-24 394/week @ 2024-05-31 351/week @ 2024-06-07 414/week @ 2024-06-14 336/week @ 2024-06-21 308/week @ 2024-06-28 277/week @ 2024-07-05 373/week @ 2024-07-12 297/week @ 2024-07-19 564/week @ 2024-07-26 293/week @ 2024-08-02 251/week @ 2024-08-09

每月 1,448 次下载
用于 13 软件包(直接使用 3 个)

MIT 协议

470KB
13K SLoC

C 13K SLoC // 0.1% comments Rust 381 SLoC // 0.0% comments

hlua

该库是 Lua 5.2 的高级绑定。您无法访问 Lua 栈,只能读取/写入变量(包括回调)和执行 Lua 代码。

Build Status

如何安装?

将以下内容添加到您项目的 Cargo.toml 文件中

[dependencies]
hlua = "0.3"

如何使用?

extern crate hlua;
use hlua::Lua;

Lua 结构体是该库的主要元素。它表示一个可以执行 Lua 代码的上下文。

let mut lua = Lua::new();     // mutable is mandatory

您可以在此处查看文档.

读取和写入变量

lua.set("x", 2);
lua.execute::<()>("x = x + 1").unwrap();
let x: i32 = lua.get("x").unwrap();  // x is equal to 3

可以使用 setget 函数读取和写入 Lua 上下文的全局变量。函数 get 返回一个 Option<T> 并复制值。

可以读取和写入的基本类型有:i8i16i32u8u16u32f32f64boolString。可以写入但不能读取 &str

如果您愿意,也可以通过实现 PushLuaRead 特性来添加其他类型。

执行 Lua

let x: u32 = lua.execute("return 6 * 2;").unwrap();    // equals 12

execute 函数接受一个 &str 并返回一个 Result<T, ExecutionError>,其中 T: LuaRead

您还可以调用 execute_from_reader,它接受一个 std::io::Read 参数。例如,您可以轻松执行文件内容,如下所示

lua.execute_from_reader::<()>(File::open(&Path::new("script.lua")).unwrap())

编写函数

为了编写一个函数,您必须将其包装在 hlua::functionX 中,其中 X 是参数的数量。这目前是 Rust 推断系统的限制。

fn add(a: i32, b: i32) -> i32 {
    a + b
}

lua.set("add", hlua::function2(add));
lua.execute::<()>("local c = add(2, 4)");   // calls the `add` function above
let c: i32 = lua.get("c").unwrap();   // returns 6

在 Lua 中,函数与常规变量完全相同。

您可以编写常规函数以及闭包

lua.set("mul", hlua::function2(|a: i32, b: i32| a * b));

请注意,Lua 上下文的生存期必须等于或短于闭包的生存期。这是在编译时强制执行的。

let mut a = 5i;

{
    let mut lua = Lua::new();

    lua.set("inc", || a += 1);    // borrows 'a'
    for i in (0 .. 15) {
        lua.execute::<()>("inc()").unwrap();
    }
} // unborrows `a`

assert_eq!(a, 20)
错误处理

如果您的 Rust 函数返回一个包含错误的 Result 对象,则将触发 Lua 错误。

操作 Lua 表

可以通过读取 LuaTable 对象来操作 Lua 表。这可以通过读取 LuaTable 对象轻松实现。

let mut table: hlua::LuaTable<_> = lua.get("a").unwrap();

然后您可以使用 .iter() 函数遍历该表。请注意,迭代器返回的值是一个 Option<(键,值)>,当键或值无法转换为请求的类型时,Option 为空。标准 Iterator 特性提供的 filter_map 函数在处理这种情况时非常有用。

for (key, value) in table.iter().filter_map(|e| e) {
    ...
}

您还可以检索和修改单个索引

let x = table.get("a").unwrap();
table.set("b", "hello");

调用 Lua 函数

您可以通过读取 functions_read::LuaFunction 来调用 Lua 函数。

lua.execute::<()>("
    function get_five() 
        return 5
    end");

let get_five: hlua::LuaFunction<_> = lua.get("get_five").unwrap();
let value: i32 = get_five.call().unwrap();
assert_eq!(value, 5);

此对象包含对 Lua 的可变引用,因此当存在 get_five 变量时,您不能读取或修改 Lua 上下文中的任何内容。目前无法存储函数,但将来可能会实现。

读取和写入 Rust 容器

(注意:目前无法读取所有容器,见下文)

可以一次性读取和写入整个 Rust 容器

lua.set("a", [ 12, 13, 14, 15 ]);
let hashmap: HashMap<i32, f64> = [1., 2., 3.].into_iter().enumerate().map(|(k, v)| (k as i32, *v as f64)).collect();
lua.set("v", hashmap);

如果容器包含单个元素,则索引将是数字。例如,在上面的代码中,12 将位于索引 113 位于索引 2,等等。

如果容器包含两个元素的元组,则第一个被视为键,第二个被视为值。

这可以用来创建 API

fn foo() { }
fn bar() { }

lua.set("mylib", [
    ("foo", hlua::function0(foo)),
    ("bar", hlua::function0(bar))
]);

lua.execute::<()>("mylib.foo()");

可以读取 Vec<AnyLuaValue>

        let mut lua = Lua::new();

        lua.execute::<()>(r#"v = { 1, 2, 3 }"#).unwrap();

        let read: Vec<_> = lua.get("v").unwrap();
        assert_eq!(
            read,
            [1., 2., 3.].iter()
                .map(|x| AnyLuaValue::LuaNumber(*x)).collect::<Vec<_>>());

如果表表示稀疏数组,具有非数字键或索引从 1 开始,则 .get() 将返回 None,因为 Rust 的 Vec 不支持这些功能。

可以读取 HashMap<AnyHashableLuaValue, AnyLuaValue>

let mut lua = Lua::new();

lua.execute::<()>(r#"v = { [-1] = -1, ["foo"] = 2, [2.] = 42 }"#).unwrap();

let read: HashMap<_, _> = lua.get("v").unwrap();
assert_eq!(read[&AnyHashableLuaValue::LuaNumber(-1)], AnyLuaValue::LuaNumber(-1.));
assert_eq!(read[&AnyHashableLuaValue::LuaString("foo".to_owned())], AnyLuaValue::LuaNumber(2.));
assert_eq!(read[&AnyHashableLuaValue::LuaNumber(2)], AnyLuaValue::LuaNumber(42.));
assert_eq!(read.len(), 3);

用户数据

(注意:目前此API非常不稳定)

当你将函数暴露给Lua时,你可能希望读取或写入更复杂的数据对象。这被称为用户数据

为此,你应该为你的类型实现PushCopyReadConsumeRead。这通常是通过将调用重定向到userdata::push_userdata来完成的。

struct Foo;

impl<L> hlua::Push<L> for Foo where L: hlua::AsMutLua<'lua> {
    fn push_to_lua(self, lua: L) -> hlua::PushGuard<L> {
        lua::userdata::push_userdata(self, lua,
            |mut metatable| {
                // you can define all the member functions of Foo here
                // see the official Lua documentation for metatables
                metatable.set("__call", hlua::function0(|| println!("hello from foo")))
            })
    }
}

fn main() {
    let mut lua = lua::Lua::new();
    lua.set("foo", Foo);
    lua.execute::<()>("foo()");       // prints "hello from foo"
}

贡献

欢迎贡献!

依赖项

~0.4–360KB