#[macro_use] extern crate hlist_macro; extern crate rlua; use std::f32; use rlua::*; fn examples() -> LuaResult<()> { // Create a Lua context with Lua::new(). Eventually, this will allow // further control on the lua std library, and will specifically allow // limiting Lua to a subset of "safe" functionality. let lua = Lua::new(); // You can get and set global variables. Notice that the globals table here // is a permanent reference to _G, and it is mutated behind the scenes as // lua code is loaded. This API is based heavily around internal mutation // (just like lua itself). let globals = lua.globals(); globals.set("string_var", "hello")?; globals.set("int_var", 42)?; assert_eq!(globals.get::<_, String>("string_var")?, "hello"); assert_eq!(globals.get::<_, i64>("int_var")?, 42); // You can load and evaluate lua code. The second parameter here gives the // chunk a better name when lua error messages are printed. lua.exec::<()>( r#" global = 'foo'..'bar' "#, Some("example code"), )?; assert_eq!(globals.get::<_, String>("global")?, "foobar"); assert_eq!(lua.eval::("1 + 1")?, 2); assert_eq!(lua.eval::("false == false")?, true); assert_eq!(lua.eval::("return 1 + 2")?, 3); // You can create and manage lua tables let array_table = lua.create_table(); array_table.set(1, "one")?; array_table.set(2, "two")?; array_table.set(3, "three")?; assert_eq!(array_table.len()?, 3); let map_table = lua.create_table(); map_table.set("one", 1)?; map_table.set("two", 2)?; map_table.set("three", 3)?; let v: i64 = map_table.get("two")?; assert_eq!(v, 2); // You can pass values like LuaTable back into Lua globals.set("array_table", array_table)?; globals.set("map_table", map_table)?; lua.eval::<()>( r#" for k, v in pairs(array_table) do print(k, v) end for k, v in pairs(map_table) do print(k, v) end "#, )?; // You can load lua functions let print: LuaFunction = globals.get("print")?; print.call::<_, ()>("hello from rust")?; // This API handles variadics using Heterogeneous Lists. This is one way to // call a function with multiple parameters: print.call::<_, ()>( hlist!["hello", "again", "from", "rust"], )?; // You can bind rust functions to lua as well let check_equal = lua.create_function(|lua, args| { // Functions wrapped in lua receive their arguments packed together as // LuaMultiValue. The first thing that most wrapped functions will do // is "unpack" this LuaMultiValue into its parts. Due to lifetime type // signature limitations, this cannot be done automatically from the // function signature, but this will be fixed with ATCs. Notice the use // of the hlist macros again. let hlist_pat![list1, list2] = lua.unpack::, Vec]>(args)?; // This function just checks whether two string lists are equal, and in // an inefficient way. Results are returned with lua.pack, which takes // any number of values and turns them back into LuaMultiValue. In this // way, multiple values can also be returned to Lua. Again, this cannot // be inferred as part of the function signature due to the same // lifetime type signature limitations. lua.pack(list1 == list2) }); globals.set("check_equal", check_equal)?; // You can also accept variadic arguments to rust callbacks. let join = lua.create_function(|lua, args| { let strings = lua.unpack::>(args)?.0; // (This is quadratic!, it's just an example!) lua.pack(strings.iter().fold("".to_owned(), |a, b| a + b)) }); globals.set("join", join)?; assert_eq!( lua.eval::( r#"check_equal({"a", "b", "c"}, {"a", "b", "c"})"#, )?, true ); assert_eq!( lua.eval::( r#"check_equal({"a", "b", "c"}, {"d", "e", "f"})"#, )?, false ); assert_eq!(lua.eval::(r#"join("a", "b", "c")"#)?, "abc"); // You can create userdata with methods and metamethods defined on them. // Here's a worked example that shows many of the features of this API // together #[derive(Copy, Clone)] struct Vec2(f32, f32); impl LuaUserDataType for Vec2 { fn add_methods(methods: &mut LuaUserDataMethods) { methods.add_method("magnitude", |lua, vec, _| { let mag_squared = vec.0 * vec.0 + vec.1 * vec.1; lua.pack(mag_squared.sqrt()) }); methods.add_meta_function(LuaMetaMethod::Add, |lua, params| { let hlist_pat![vec1, vec2] = lua.unpack::(params)?; lua.pack(Vec2(vec1.0 + vec2.0, vec1.1 + vec2.1)) }); } } let vec2_constructor = lua.create_function(|lua, args| { let hlist_pat![x, y] = lua.unpack::(args)?; lua.pack(Vec2(x, y)) }); globals.set("vec2", vec2_constructor)?; assert!(lua.eval::("(vec2(1, 2) + vec2(2, 2)):magnitude()")? - 5.0 < f32::EPSILON); Ok(()) } fn main() { examples().unwrap(); }