{"id":13437881,"url":"https://github.com/tickbh/td_rlua","last_synced_at":"2025-05-07T17:50:24.712Z","repository":{"id":6229976,"uuid":"55138700","full_name":"tickbh/td_rlua","owner":"tickbh","description":"Zero-cost high-level lua 5.3 wrapper for Rust","archived":false,"fork":false,"pushed_at":"2024-04-10T06:56:58.000Z","size":408,"stargazers_count":52,"open_issues_count":0,"forks_count":14,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-16T07:47:41.824Z","etag":null,"topics":["ffi","hotfix","lua","lua53","rust","rust-lua"],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tickbh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-03-31T09:43:09.000Z","updated_at":"2025-01-24T04:36:49.000Z","dependencies_parsed_at":"2024-04-10T07:45:43.204Z","dependency_job_id":null,"html_url":"https://github.com/tickbh/td_rlua","commit_stats":{"total_commits":64,"total_committers":4,"mean_commits":16.0,"dds":0.53125,"last_synced_commit":"1eab991008995999c1cd289aa54fcee8896ceddd"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tickbh%2Ftd_rlua","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tickbh%2Ftd_rlua/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tickbh%2Ftd_rlua/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tickbh%2Ftd_rlua/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tickbh","download_url":"https://codeload.github.com/tickbh/td_rlua/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252931391,"owners_count":21827104,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ffi","hotfix","lua","lua53","rust","rust-lua"],"created_at":"2024-07-31T03:01:00.912Z","updated_at":"2025-05-07T17:50:24.688Z","avatar_url":"https://github.com/tickbh.png","language":"C","readme":"## td_rlua\n\nThis 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.\n\n[![Build Status](https://api.travis-ci.org/tickbh/td_rlua.svg?branch=master)](https://travis-ci.org/tickbh/td_rlua)\n\n### How to install it?\n\nAdd this to the `Cargo.toml` file of your project\n\n```toml\n[dependencies]\ntd_rlua = \"0.1.0\"\n```\n\n### How to use it?\n\n```rust\nextern crate td_rlua;\nuse td_rlua::Lua;\n```\n\nThe `Lua` struct is the main element of this library. It represents a context in which you can execute Lua code.\n\n```rust\nlet mut lua = Lua::new();     // mutable is mandatory\n```\n\n#### Reading and writing variables\n\n```rust\nlua.set(\"x\", 2);\nlet _: () = lua.exec_string(\"x = x + 1\").unwrap();\nlet x: i32 = lua.query(\"x\").unwrap();\nassert_eq!(x, 3);\n```\n\nReading and writing global variables of the Lua context can be done with `set` and `query`.\nThe `query` function returns an `Option\u003cT\u003e` and does a copy of the value.\n\nThe base types that can be read and written are: `i8`, `i16`, `i32`, `u8`, `u16`, `u32`, `f32`, `f64`, `bool`, `String`. `\u0026str` can be written but not read.\n\nIf you wish so, you can also add other types by implementing the `LuaPush` and `LuaRead` traits.\n\n#### Executing Lua\n\n```rust\nlet x: u32 = lua.exec_string(\"return 6 * 2;\").unwrap();    // equals 12\n```\n\nThe `exec_string` function takes a `\u0026str` and returns a `Option\u003cT\u003e` where `T: LuaRead`.\n\n#### Writing functions\n\nIn 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.\n\n```rust\nfn add(a: i32, b: i32) -\u003e i32 {\n    a + b\n}\n\nlua.set(\"add\", td_rlua::function2(add));\nlet _: () = lua.exec_string(\"c = add(2, 4)\").unwrap();   // calls the `add` function above\nlet c: i32 = lua.query(\"c\").unwrap();\nassert_eq!(c, 6);\n```\n\nIn Lua, functions are exactly like regular variables.\n\nYou can write regular functions as well as closures:\n\n```rust\nlua.set(\"mul\", td_rlua::function2(|a: i32, b: i32| a * b));\n```\n\nNote that the lifetime of the Lua context must be equal to or shorter than the lifetime of closures. This is enforced at compile-time.\n\n```rust\nlet mut a = 5i;\n\n{\n    let mut lua = Lua::new();\n\n    lua.set(\"inc\", || a += 1);    // borrows 'a'\n    for i in (0 .. 15) {\n        let _: () = lua.exec_string(\"inc()\").unwrap();\n    }\n} // unborrows `a`\n\nassert_eq!(a, 20)\n```\n\n##### Error handling\n\n```rust\nextern \"C\" fn error_handle(lua: *mut c_lua::lua_State) -\u003e libc::c_int {\n    let err = unsafe { c_lua::lua_tostring(lua, -1) };\n    let err = unsafe { CStr::from_ptr(err) };\n    let err = String::from_utf8(err.to_bytes().to_vec()).unwrap();\n    println!(\"error:{}\", err);\n    0\n}\nlua.register(\"error_handle\", error_handle);\n```\n\nDefault in exec_string will call pcall, and set the error_function _G[\"error_handle\"] so you can reset 'error_handle' function to you custom.\n\n#### Manipulating Lua tables\n\nManipulating a Lua table can be done by reading a `LuaTable` object. This can be achieved easily by reading a `LuaTable` object.\n\n```rust\nlet _:() = lua.exec_string(\"a = { 9, 8, 7 }\").unwrap();\nlet mut table : LuaTable = lua.query(\"a\").unwrap();\n\nlet x: i32 = table.query(2).unwrap();\nassert_eq!(x, 8);\n\ntable.set(3, \"hello\");\nlet y: String = table.query(3).unwrap();\nassert_eq!(y, \"hello\");\n\nlet z: i32 = table.query(1).unwrap();\nassert_eq!(z, 9);\n```\n\nYou can then iterate through the table with the `.iter()` function. Note that the value returned by the iterator is an `Option\u003c(Key, Value)\u003e`, 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.\n\n```rust\nlet _:() = lua.exec_string(\"a = { 9, 8, 7 }\").unwrap();\nlet mut table : LuaTable = lua.query(\"a\").unwrap();\nfor _ in 0 .. 10 {\n    let table_content: Vec\u003cOption\u003c(u32, u32)\u003e\u003e = table.iter().collect();\n    assert_eq!(table_content, vec![ Some((1,9)), Some((2,8)), Some((3,7)) ]);\n}\n```\n\n#### User data\n\nWhen you expose functions to Lua, you may wish to read or write more elaborate objects. This is called a **user data**.\n\nTo do so, you should implement the `LuaPush` for your types.\nThis is usually done by redirecting the call to `userdata::push_userdata`.\nit will operate the ref of object\nif you use `userdata::push_userdata` the userdata will copy one time, for lua gc manager\nif you use `userdata::push_lightuserdata` the userdata life manager by rust, so none copy will occup\n\n```rust\n#[derive(Clone, Debug)]\nstruct Foo {\n    a : i32,\n};\n\nimpl\u003c'a\u003e td_rlua::LuaPush for \u0026'a mut  Foo {\n    fn push_to_lua(self, lua: *mut c_lua::lua_State) -\u003e i32 {\n        td_rlua::userdata::push_userdata(self, lua, |_|{})\n    }\n}\nimpl\u003c'a\u003e td_rlua::LuaRead for \u0026'a mut  Foo {\n    fn lua_read_at_position(lua: *mut c_lua::lua_State, index: i32) -\u003e Option\u003c\u0026'a mut Foo\u003e {\n        td_rlua::userdata::read_userdata(lua, index)\n    }\n}\n\nlet xx  = \u0026mut Foo {\n    a : 10,\n};\nlua.set(\"a\", xx);\nlet get: \u0026mut Foo = lua.query(\"a\").unwrap();\nassert!(get.a == 10);\nget.a = 100;\n\nlet get: \u0026mut Foo = lua.query(\"a\").unwrap();\nassert!(get.a == 100);\n```\nuse lightuserdata you can change\n```rust\nimpl\u003c'a\u003e td_rlua::LuaPush for \u0026'a mut  Foo {\n    fn push_to_lua(self, lua: *mut c_lua::lua_State) -\u003e i32 {\n        td_rlua::userdata::push_lightuserdata(self, lua, |_|{})\n    }\n}\n```\n\ncustom lua call userdata need impl NewStruct\n```rust\n#[derive(Clone, Debug)]\nstruct TestLuaSturct {\n    index : i32,\n}\n\nimpl NewStruct for TestLuaSturct {\n    fn new() -\u003e TestLuaSturct {\n        println!(\"new !!!!!!!!!!!!!!\");\n        TestLuaSturct {\n            index : 19,\n        }\n    }\n\n    fn name() -\u003e \u0026'static str {\n        \"TestLuaSturct\"\n    }\n}\n\nimpl\u003c'a\u003e LuaRead for \u0026'a mut TestLuaSturct {\n    fn lua_read_at_position(lua: *mut c_lua::lua_State, index: i32) -\u003e Option\u003c\u0026'a mut TestLuaSturct\u003e {\n        td_rlua::userdata::read_userdata(lua, index)\n    }\n}\n```\n\nnow we can custom function\n\n```rust\nlet mut lua = Lua::new();\nlua.openlibs();\nfn one_arg(obj : \u0026mut TestLuaSturct) -\u003e i32 { obj.index = 10; 5 };\nfn two_arg(obj : \u0026mut TestLuaSturct, index : i32) { obj.index = index;};\n\nlet mut value = td_rlua::LuaStruct::\u003cTestLuaSturct\u003e::new(lua.state());\nvalue.create().def(\"one_arg\", td_rlua::function1(one_arg)).def(\"two_arg\", td_rlua::function2(two_arg));\n\nlet _ : Option\u003c()\u003e = lua.exec_string(\"x = TestLuaSturct()\");\nlet val : Option\u003ci32\u003e = lua.exec_string(\"return x:one_arg()\");\nassert_eq!(val, Some(5));\nlet obj : Option\u003c\u0026mut TestLuaSturct\u003e = lua.query(\"x\");\nassert_eq!(obj.unwrap().index, 10);\nlet val : Option\u003ci32\u003e = lua.exec_string(\"x:two_arg(121)\");\nassert_eq!(val, None);\nlet obj : Option\u003c\u0026mut TestLuaSturct\u003e = lua.query(\"x\");\nassert_eq!(obj.unwrap().index, 121);\n\nlet obj : Option\u003c\u0026mut TestLuaSturct\u003e = lua.exec_string(\"return TestLuaSturct()\");\nassert_eq!(obj.unwrap().index, 19);\n```\n### HotFix\nin runtime, if we need change some logic, we need restart the process, it may lose some memory data\nso sometimes we need update the logic, add keep the memory data, so we need hotfix\n```rust\nlet mut lua = Lua::new();\nlua.openlibs();\nlua.enable_hotfix();\nlet _ = lua.exec_func2(\"hotfix\", r\"\n    local value = {3, 4}\n    function get_a()\n        value[2] = 3\n        return value[1]\n    end\n\n    function get_b()\n        return value[2]\n    end\n    \", \"hotfix\");\n```\n\n### Refer\n\nthe project write refer to [hlua]( https://github.com/tomaka/hlua), if you use lua5.2, you can use it.\n\n### Contributing\n\nContributions are welcome!\n","funding_links":[],"categories":["Development tools","开发工具 Development tools","开发工具"],"sub_categories":["FFI","FFI FFI","示例 FFI"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftickbh%2Ftd_rlua","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftickbh%2Ftd_rlua","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftickbh%2Ftd_rlua/lists"}