Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/tickbh/td_rlua
Zero-cost high-level lua 5.3 wrapper for Rust
https://github.com/tickbh/td_rlua
ffi hotfix lua lua53 rust rust-lua
Last synced: 7 days ago
JSON representation
Zero-cost high-level lua 5.3 wrapper for Rust
- Host: GitHub
- URL: https://github.com/tickbh/td_rlua
- Owner: tickbh
- License: apache-2.0
- Created: 2016-03-31T09:43:09.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2024-04-10T06:56:58.000Z (7 months ago)
- Last Synced: 2024-10-12T04:26:54.543Z (23 days ago)
- Topics: ffi, hotfix, lua, lua53, rust, rust-lua
- Language: C
- Size: 398 KB
- Stars: 53
- Watchers: 9
- Forks: 14
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE-APACHE
Awesome Lists containing this project
- awesome-rust-cn - tickbh/td_rlua - cost high-level lua 5.3 wrapper for Rust [<img src="https://api.travis-ci.org/tickbh/td_rlua.svg?branch=master">](https://travis-ci.org/tickbh/td_rlua) (Development tools / FFI)
- awesome-rust - tickbh/td_rlua - cost high-level lua 5.3 wrapper for Rust [<img src="https://api.travis-ci.org/tickbh/td_rlua.svg?branch=master">](https://travis-ci.org/tickbh/td_rlua) (Development tools / FFI)
- awesome-rust - tickbh/td_rlua - cost high-level lua 5.3 wrapper for Rust (Development tools / FFI)
- awesome-rust-cn - tickbh/td_rlua
- awesome-rust-zh - tickbh/td_rlua - 适用于 Rust 的零成本高级 lua 5.3 包装[<img src="https://api.travis-ci.org/tickbh/td_rlua.svg?branch=master">](https://travis-ci.org/tickbh/td_rlua) (开发工具 / FFI)
- awesome-rust - tickbh/td_rlua - Zero-cost high-level lua 5.3 wrapper for Rust (Development tools / FFI)
- awesome-rust - tickbh/td_rlua - cost high-level lua 5.3 wrapper for Rust [<img src="https://api.travis-ci.org/tickbh/td_rlua.svg?branch=master">](https://travis-ci.org/tickbh/td_rlua) (开发工具 Development tools / 示例 FFI)
- fucking-awesome-rust - tickbh/td_rlua - Zero-cost high-level lua 5.3 wrapper for Rust (Development tools / FFI)
- fucking-awesome-rust - tickbh/td_rlua - Zero-cost high-level lua 5.3 wrapper for Rust (Development tools / FFI)
README
## td_rlua
This library is a high-level binding for Lua 5.3. You don't have access to the Lua stack, all you can do is read/write variables (including callbacks) and execute Lua code.
[![Build Status](https://api.travis-ci.org/tickbh/td_rlua.svg?branch=master)](https://travis-ci.org/tickbh/td_rlua)
### How to install it?
Add this to the `Cargo.toml` file of your project
```toml
[dependencies]
td_rlua = "0.1.0"
```### How to use it?
```rust
extern crate td_rlua;
use td_rlua::Lua;
```The `Lua` struct is the main element of this library. It represents a context in which you can execute Lua code.
```rust
let mut lua = Lua::new(); // mutable is mandatory
```#### Reading and writing variables
```rust
lua.set("x", 2);
let _: () = lua.exec_string("x = x + 1").unwrap();
let x: i32 = lua.query("x").unwrap();
assert_eq!(x, 3);
```Reading and writing global variables of the Lua context can be done with `set` and `query`.
The `query` function returns an `Option` and does a copy of the value.The base types that can be read and written are: `i8`, `i16`, `i32`, `u8`, `u16`, `u32`, `f32`, `f64`, `bool`, `String`. `&str` can be written but not read.
If you wish so, you can also add other types by implementing the `LuaPush` and `LuaRead` traits.
#### Executing Lua
```rust
let x: u32 = lua.exec_string("return 6 * 2;").unwrap(); // equals 12
```The `exec_string` function takes a `&str` and returns a `Option` where `T: LuaRead`.
#### Writing functions
In order to write a function, you must wrap it around `td_rlua::functionX` where `X` is the number of parameters. This is for the moment a limitation of Rust's inferrence system.
```rust
fn add(a: i32, b: i32) -> i32 {
a + b
}lua.set("add", td_rlua::function2(add));
let _: () = lua.exec_string("c = add(2, 4)").unwrap(); // calls the `add` function above
let c: i32 = lua.query("c").unwrap();
assert_eq!(c, 6);
```In Lua, functions are exactly like regular variables.
You can write regular functions as well as closures:
```rust
lua.set("mul", td_rlua::function2(|a: i32, b: i32| a * b));
```Note that the lifetime of the Lua context must be equal to or shorter than the lifetime of closures. This is enforced at compile-time.
```rust
let mut a = 5i;{
let mut lua = Lua::new();lua.set("inc", || a += 1); // borrows 'a'
for i in (0 .. 15) {
let _: () = lua.exec_string("inc()").unwrap();
}
} // unborrows `a`assert_eq!(a, 20)
```##### Error handling
```rust
extern "C" fn error_handle(lua: *mut c_lua::lua_State) -> libc::c_int {
let err = unsafe { c_lua::lua_tostring(lua, -1) };
let err = unsafe { CStr::from_ptr(err) };
let err = String::from_utf8(err.to_bytes().to_vec()).unwrap();
println!("error:{}", err);
0
}
lua.register("error_handle", error_handle);
```Default in exec_string will call pcall, and set the error_function _G["error_handle"] so you can reset 'error_handle' function to you custom.
#### Manipulating Lua tables
Manipulating a Lua table can be done by reading a `LuaTable` object. This can be achieved easily by reading a `LuaTable` object.
```rust
let _:() = lua.exec_string("a = { 9, 8, 7 }").unwrap();
let mut table : LuaTable = lua.query("a").unwrap();let x: i32 = table.query(2).unwrap();
assert_eq!(x, 8);table.set(3, "hello");
let y: String = table.query(3).unwrap();
assert_eq!(y, "hello");let z: i32 = table.query(1).unwrap();
assert_eq!(z, 9);
```You can then iterate through the table with the `.iter()` function. Note that the value returned by the iterator is an `Option<(Key, Value)>`, the `Option` being empty when either the key or the value is not convertible to the requested type. The `filter_map` function (provided by the standard `Iterator` trait) is very useful when dealing with this.
```rust
let _:() = lua.exec_string("a = { 9, 8, 7 }").unwrap();
let mut table : LuaTable = lua.query("a").unwrap();
for _ in 0 .. 10 {
let table_content: Vec> = table.iter().collect();
assert_eq!(table_content, vec![ Some((1,9)), Some((2,8)), Some((3,7)) ]);
}
```#### User data
When you expose functions to Lua, you may wish to read or write more elaborate objects. This is called a **user data**.
To do so, you should implement the `LuaPush` for your types.
This is usually done by redirecting the call to `userdata::push_userdata`.
it will operate the ref of object
if you use `userdata::push_userdata` the userdata will copy one time, for lua gc manager
if you use `userdata::push_lightuserdata` the userdata life manager by rust, so none copy will occup```rust
#[derive(Clone, Debug)]
struct Foo {
a : i32,
};impl<'a> td_rlua::LuaPush for &'a mut Foo {
fn push_to_lua(self, lua: *mut c_lua::lua_State) -> i32 {
td_rlua::userdata::push_userdata(self, lua, |_|{})
}
}
impl<'a> td_rlua::LuaRead for &'a mut Foo {
fn lua_read_at_position(lua: *mut c_lua::lua_State, index: i32) -> Option<&'a mut Foo> {
td_rlua::userdata::read_userdata(lua, index)
}
}let xx = &mut Foo {
a : 10,
};
lua.set("a", xx);
let get: &mut Foo = lua.query("a").unwrap();
assert!(get.a == 10);
get.a = 100;let get: &mut Foo = lua.query("a").unwrap();
assert!(get.a == 100);
```
use lightuserdata you can change
```rust
impl<'a> td_rlua::LuaPush for &'a mut Foo {
fn push_to_lua(self, lua: *mut c_lua::lua_State) -> i32 {
td_rlua::userdata::push_lightuserdata(self, lua, |_|{})
}
}
```custom lua call userdata need impl NewStruct
```rust
#[derive(Clone, Debug)]
struct TestLuaSturct {
index : i32,
}impl NewStruct for TestLuaSturct {
fn new() -> TestLuaSturct {
println!("new !!!!!!!!!!!!!!");
TestLuaSturct {
index : 19,
}
}fn name() -> &'static str {
"TestLuaSturct"
}
}impl<'a> LuaRead for &'a mut TestLuaSturct {
fn lua_read_at_position(lua: *mut c_lua::lua_State, index: i32) -> Option<&'a mut TestLuaSturct> {
td_rlua::userdata::read_userdata(lua, index)
}
}
```now we can custom function
```rust
let mut lua = Lua::new();
lua.openlibs();
fn one_arg(obj : &mut TestLuaSturct) -> i32 { obj.index = 10; 5 };
fn two_arg(obj : &mut TestLuaSturct, index : i32) { obj.index = index;};let mut value = td_rlua::LuaStruct::::new(lua.state());
value.create().def("one_arg", td_rlua::function1(one_arg)).def("two_arg", td_rlua::function2(two_arg));let _ : Option<()> = lua.exec_string("x = TestLuaSturct()");
let val : Option = lua.exec_string("return x:one_arg()");
assert_eq!(val, Some(5));
let obj : Option<&mut TestLuaSturct> = lua.query("x");
assert_eq!(obj.unwrap().index, 10);
let val : Option = lua.exec_string("x:two_arg(121)");
assert_eq!(val, None);
let obj : Option<&mut TestLuaSturct> = lua.query("x");
assert_eq!(obj.unwrap().index, 121);let obj : Option<&mut TestLuaSturct> = lua.exec_string("return TestLuaSturct()");
assert_eq!(obj.unwrap().index, 19);
```
### HotFix
in runtime, if we need change some logic, we need restart the process, it may lose some memory data
so sometimes we need update the logic, add keep the memory data, so we need hotfix
```rust
let mut lua = Lua::new();
lua.openlibs();
lua.enable_hotfix();
let _ = lua.exec_func2("hotfix", r"
local value = {3, 4}
function get_a()
value[2] = 3
return value[1]
endfunction get_b()
return value[2]
end
", "hotfix");
```### Refer
the project write refer to [hlua]( https://github.com/tomaka/hlua), if you use lua5.2, you can use it.
### Contributing
Contributions are welcome!