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.
Add this to the Cargo.toml file of your project
[dependencies]
td_rlua = "0.1.0"externcrate 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.
letmut lua = Lua::new();// mutable is mandatorylua.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<T> 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.
let x:u32 = lua.exec_string("return 6 * 2;").unwrap();// equals 12The exec_string function takes a &str and returns a Option<T> where T: LuaRead.
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.
fnadd(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 abovelet 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:
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.
letmut a = 5i;{letmut 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)extern"C"fnerror_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 a Lua table can be done by reading a LuaTable object. This can be achieved easily by reading a LuaTable object.
let _:() = lua.exec_string("a = { 9, 8, 7 }").unwrap();letmut 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.
let _:() = lua.exec_string("a = { 9, 8, 7 }").unwrap();letmut table :LuaTable = lua.query("a").unwrap();for _ in0 .. 10{let table_content:Vec<Option<(u32,u32)>> = table.iter().collect();assert_eq!(table_content, vec![Some((1,9)),Some((2,8)),Some((3,7))]);}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
#[derive(Clone,Debug)]structFoo{a:i32,};impl<'a> td_rlua::LuaPushfor&'amutFoo{fnpush_to_lua(self,lua:*mut c_lua::lua_State) -> i32{
td_rlua::userdata::push_userdata(self, lua, |_|{})}}impl<'a> td_rlua::LuaReadfor&'amutFoo{fnlua_read_at_position(lua:*mut c_lua::lua_State,index:i32) -> Option<&'amutFoo>{
td_rlua::userdata::read_userdata(lua, index)}}let xx = &mutFoo{a:10,};
lua.set("a", xx);let get:&mutFoo = lua.query("a").unwrap();assert!(get.a == 10);
get.a = 100;let get:&mutFoo = lua.query("a").unwrap();assert!(get.a == 100);use lightuserdata you can change
impl<'a> td_rlua::LuaPushfor&'amutFoo{fnpush_to_lua(self,lua:*mut c_lua::lua_State) -> i32{
td_rlua::userdata::push_lightuserdata(self, lua, |_|{})}}custom lua call userdata need impl NewStruct
#[derive(Clone,Debug)]structTestLuaSturct{index:i32,}implNewStructforTestLuaSturct{fnnew() -> TestLuaSturct{println!("new !!!!!!!!!!!!!!");TestLuaSturct{index:19,}}fnname() -> &'staticstr{"TestLuaSturct"}}impl<'a>LuaReadfor&'amutTestLuaSturct{fnlua_read_at_position(lua:*mut c_lua::lua_State,index:i32) -> Option<&'amutTestLuaSturct>{
td_rlua::userdata::read_userdata(lua, index)}}now we can custom function
letmut lua = Lua::new();
lua.openlibs();fnone_arg(obj:&mutTestLuaSturct) -> i32{ obj.index = 10;5};fntwo_arg(obj:&mutTestLuaSturct,index:i32){ obj.index = index;};letmut value = td_rlua::LuaStruct::<TestLuaSturct>::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<i32> = lua.exec_string("return x:one_arg()");assert_eq!(val,Some(5));let obj :Option<&mutTestLuaSturct> = lua.query("x");assert_eq!(obj.unwrap().index,10);let val :Option<i32> = lua.exec_string("x:two_arg(121)");assert_eq!(val,None);let obj :Option<&mutTestLuaSturct> = lua.query("x");assert_eq!(obj.unwrap().index,121);let obj :Option<&mutTestLuaSturct> = lua.exec_string("return TestLuaSturct()");assert_eq!(obj.unwrap().index,19);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
letmut 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] end function get_b() return value[2] end ","hotfix");the project write refer to hlua, if you use lua5.2, you can use it.
Contributions are welcome!