{"id":13494679,"url":"https://github.com/satoren/kaguya","last_synced_at":"2025-05-16T01:05:29.995Z","repository":{"id":2487998,"uuid":"46660899","full_name":"satoren/kaguya","owner":"satoren","description":"C++ binding to Lua","archived":false,"fork":false,"pushed_at":"2025-01-04T06:02:40.000Z","size":1561,"stargazers_count":350,"open_issues_count":28,"forks_count":71,"subscribers_count":28,"default_branch":"main","last_synced_at":"2025-04-08T12:04:29.724Z","etag":null,"topics":["binding","lua"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/satoren.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE_1_0.txt","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":"2015-11-22T13:04:05.000Z","updated_at":"2025-03-26T05:48:21.000Z","dependencies_parsed_at":"2025-01-26T19:01:18.290Z","dependency_job_id":"37d534da-c68e-4510-8ac5-a9e524c895e4","html_url":"https://github.com/satoren/kaguya","commit_stats":{"total_commits":825,"total_committers":11,"mean_commits":75.0,"dds":"0.030303030303030276","last_synced_commit":"9d77cad73846f5d8481f3f7e86e8c53c4891c2fb"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satoren%2Fkaguya","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satoren%2Fkaguya/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satoren%2Fkaguya/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/satoren%2Fkaguya/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/satoren","download_url":"https://codeload.github.com/satoren/kaguya/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254448579,"owners_count":22072764,"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":["binding","lua"],"created_at":"2024-07-31T19:01:27.151Z","updated_at":"2025-05-16T01:05:25.979Z","avatar_url":"https://github.com/satoren.png","language":"C++","funding_links":[],"categories":["C++","Scripting"],"sub_categories":[],"readme":"# Kaguya\nC++ binding to Lua\n\nLicensed under [Boost Software License](http://www.boost.org/LICENSE_1_0.txt)\n\n\n## Requirements\n- Lua 5.1 to 5.3 (recommended: 5.3)\n- C++03 compiler with boost library or C++11 compiler(gcc 4.8+,clang 3.4+,MSVC2015) without boost.\n\n### Tested Environment\n[![test](https://github.com/satoren/kaguya/actions/workflows/test.yml/badge.svg)](https://github.com/satoren/kaguya/actions/workflows/cmake.yml)\n\n## Introduction\nKaguya is a Lua binding library for C++\n- header-file only\n- seamless access to lua elements\n\n## Usage\nadd \"kaguya/include\" directory to \"header search path\" of your project.\n\nOr generate single header file and add it to your project.\n```\ncd  utils\npython generate_one_header.py \u003e ../kaguya.hpp\n```\n\n### Create Lua context\n```c++\n#include \"kaguya/kaguya.hpp\"\nint main()\n{\n  kaguya::State state;\n  state.dofile(\"/path/to/script.lua\");\n}\n```\n\n### Or use an existing lua state\n```c++\nextern \"C\" int luaopen_modulename(lua_State *L)\n{\n\tkaguya::State state(l);\n\tkaguya::LuaTable module = state.newTable();\n\tmodule[\"function\"] = kaguya::function(somefunction);\n\treturn module.push();//number of return lib\n}\n```\n\n### Running Lua code\n```c++\nkaguya::State state;\nstate(\"a = 'test'\");//load and execute from string\nstate.dofile(\"path/to/luascript.lua\");//load and execute from file\n\nkaguya::LuaFunction f1 = state.loadfile(\"path/to/luascript.lua\");//load file without executing it\nf1();//execute\nkaguya::LuaFunction f2 = state.loadstring(\"a = 'test'\");//load string without executing it\nf2();//execute\n```\n\n### Accessing values\n```c++\nkaguya::State state;\nstate(\"a = \\\"test\\\"\");\nstd::string a_value = state[\"a\"];\nassert(a_value == \"test\");\n\nstate[\"tbl\"] = kaguya::NewTable();//tbl ={};\nstate[\"tbl\"][\"value\"] = 1;//tbl.value = 1 in lua\n\nstate[\"tbl\"] = kaguya::TableData{ 23,\"test\",{\"key\",\"value\"}}; //using initializer list(C++11)\nstate(\"assert(tbl[1] == 23)\");\nstate(\"assert(tbl[2] == 'test')\");\nstate(\"assert(tbl['key'] == 'value')\");\n```\n\n### Retain Lua value from C++\nLuaRef type is like a Variant type.\nYou can use it for holding a Lua-value in native code.\n```c++\nkaguya::State state;\nstate[\"a\"] = \"test\";\nkaguya::LuaRef a = state[\"a\"];\nassert(a == \"test\");\n\nstate[\"tbl\"] = kaguya::NewTable();//tbl ={};\nkaguya::LuaTable tbl = state[\"tbl\"];//holding Lua Table\ntbl[\"value\"] = 1;//tbl.value = 1 in lua\nstate(\"assert(tbl.value == 1)\");\n```\n\n## Call lua function\n```c++\nint ret = state[\"math\"][\"abs\"](-32);//call math.abs of Lua function\nassert(ret == 32);\n//or\nauto ret = state[\"math\"][\"abs\"].call\u003cint\u003e(-32);//call math.abs of Lua function\nassert(ret == 32);\n```\n\n### Multiple Results from Lua\n```c++\nstate(\"multresfun =function() return 1,2,4 end\");//registering multiple results function\nint a, b, c;\nkaguya::tie(a, b, c) = state[\"multresfun\"]();\nassert(a == 1 \u0026\u0026 b == 2 \u0026\u0026 c == 4 );\n//or\nstd::tuple\u003cint,int,int\u003e result_tuple = state[\"multresfun\"].call\u003cstd::tuple\u003cint,int,int\u003e\u003e();\nTEST_EQUAL(std::get\u003c0\u003e(result_tuple), 1);\nTEST_EQUAL(std::get\u003c1\u003e(result_tuple), 2);\nTEST_EQUAL(std::get\u003c2\u003e(result_tuple), 4);\n```\n\n### Registering Classes\n```c++\nstruct ABC\n{\n\tABC():v_(0) {}\n\tABC(int value) :v_(value) {}\n\tint value()const { return v_; }\n\tvoid setValue(int v) { v_ = v; }\n\tvoid overload1() {std::cout \u003c\u003c \"call overload1\"\u003c\u003cstd::endl; }\n\tvoid overload2(int) {std::cout \u003c\u003c \"call overload2\"\u003c\u003cstd::endl; }\nprivate:\n\tint v_;\n};\nstate[\"ABC\"].setClass(kaguya::UserdataMetatable\u003cABC\u003e()\n\t.setConstructors\u003cABC(),ABC(int)\u003e()\n\t.addFunction(\"get_value\", \u0026ABC::value)\n\t.addFunction(\"set_value\", \u0026ABC::setValue)\n\t.addOverloadedFunctions(\"overload\", \u0026ABC::overload1, \u0026ABC::overload2)\n\t.addStaticFunction(\"nonmemberfun\", [](ABC* self,int){return 1;})//c++11 lambda function\n\t);\n```\n\n```lua\n--Lua\nabc = ABC.new()--call default constructor\nassert(0 == abc:get_value())\nabc = ABC.new(42)--call (int) constructor\nassert(42 == abc:get_value())\nabc:set_value(30)\nassert(30 == abc:get_value())\nabc:overload() -- call overload1\nabc:overload(1) --call overload2\n```\n#### Registering inheritance\n```c++\nstruct Base\n{\n\tint a;\n};\nstruct Base2\n{\n\tint a2;\n};\nstruct Derived:Base\n{\n\tint b;\n};\nstruct MultipleInheritance:Base,Base2\n{\n\tint b;\n};\nint base_function(Base* b) {\n\tb-\u003ea = 1;\n\treturn b-\u003ea;\n}\n//\nkaguya::State state;\nstate[\"Base\"].setClass(kaguya::UserdataMetatable\u003cBase\u003e()\n\t.addFunction(\"a\", \u0026Base::a)\n\t);\nstate[\"Derived\"].setClass(kaguya::UserdataMetatable\u003cDerived, Base\u003e()\n\t.addFunction(\"b\", \u0026Derived::b)\n\t);\n\n//can use kaguya::MultipleBase\u003cBaseTypes...\u003e for multiple inheritance class\nstate[\"MultipleInheritance\"].setClass(kaguya::UserdataMetatable\u003cMultipleInheritance, kaguya::MultipleBase\u003cBase, Base2\u003e \u003e()\n\t.addFunction(\"b\", \u0026MultipleInheritance::b)\n\t);\n\nstate[\"base_function\"] = \u0026base_function;\nDerived derived;\nstate[\"base_function\"](\u0026derived);//Base arguments function\nstate(\"assert(1 == derived:a())\");//accessing Base member\n```\n\n#### Registering object instance\n```c++\nstate[\"ABC\"].setClass(kaguya::UserdataMetatable\u003cABC\u003e()\n\t.setConstructors\u003cABC(),ABC(int)\u003e()\n\t.addFunction(\"get_value\", \u0026ABC::value)\n\t.addFunction(\"set_value\", \u0026ABC::setValue)\n\t);\nABC abc(43);\n//register object pointer\nstate[\"abc\"] = \u0026abc;\nstate(\"assert(43 == abc:get_value())\");\n//or copy instance\nstate[\"copy_abc\"] = abc;\nstate(\"assert(43 == copy_abc:get_value())\");\n//or registering shared instance\nstate[\"shared_abc\"] = kaguya::standard::shared_ptr\u003cABC\u003e(new ABC(43));//kaguya::standard::shared_ptr is std::shared_ptr or boost::shared_ptr.\nstate(\"assert(43 == shared_abc:get_value())\");\n```\n#### Object lifetime\n```c++\nstate[\"Base\"].setClass(kaguya::UserdataMetatable\u003cBase\u003e());\nBase base;\n\n//registering pointer. lifetime is same base\nstate[\"b\"] = \u0026base;\nstate[\"b\"] = kaguya::standard::ref(base);\n\n//registering copy instance. copied instance lifetime is handling in lua vm(garbage collection).\nstate[\"b\"] = base;\nstate[\"b\"] = static_cast\u003cBase const\u0026\u003e(base);\n\n```\n### Registering function\n```c++\nvoid c_free_standing_function(int v){std::cout \u003c\u003c\"c_free_standing_function called:\" \u003c\u003c v \u003c\u003c std::endl;}\nstate[\"fun\"] = \u0026c_free_standing_function;\nstate[\"fun\"](54); //c_free_standing_function called:54\nstate(\"fun(22)\");//c_free_standing_function called:22\n\nstate[\"lambda\"] = kaguya::function([]{std::cout \u003c\u003c \"lambda called\" \u003c\u003c std::endl;});//C++11 lambda\nstate(\"lambda()\");//lambda called\n\n\nstate[\"overload\"] = kaguya::overload(\n\t[](int) {std::cout \u003c\u003c \"int version\" \u003c\u003c std::endl; },\n\t[](const std::string\u0026) {std::cout \u003c\u003c \"string version\" \u003c\u003c std::endl; },\n\t[]() {std::cout \u003c\u003c \"no arg version\" \u003c\u003c std::endl; }\n);\nstate(\"overload()\");//no args version\nstate(\"overload(2)\");//int version\nstate(\"overload('2')\");//string version\n\n```\n#### Registering function with default arguments\n\n```c++\n//free function\nint defargfn(int a = 3, int b = 2, int c = 1)\n{\n\treturn a*b*c;\n}\n\nKAGUYA_FUNCTION_OVERLOADS(defargfn_wrapper, defargfn,0,3)\nstate[\"defarg\"] = kaguya::function(defargfn_wrapper());\nstate.dostring(\"assert(defarg() == 6)\");\nstate.dostring(\"assert(defarg(6) == 12)\");\nstate.dostring(\"assert(defarg(6,5) == 30)\");\nstate.dostring(\"assert(defarg(2,2,2) == 8)\");\n\n//member function\nstruct TestClass\n{\n\tint defargfn(int a = 3, int b = 2, int c = 1)\n\t{\n\t\treturn a*b*c;\n\t}\n};\nKAGUYA_MEMBER_FUNCTION_OVERLOADS(defargfn_wrapper, TestClass, defargfn, 0, 3)\nstate[\"TestClass\"].setClass(kaguya::UserdataMetatable\u003cTestClass\u003e()\n\t.setConstructors\u003cTestClass()\u003e()\n\t.addFunction(\"defarg\", defargfn_wrapper())\n);\nstate.dostring(\"test = TestClass.new()\");\nstate.dostring(\"assert(test:defargfn() == 6)\");\nstate.dostring(\"assert(test:defargfn(6) == 12)\");\nstate.dostring(\"assert(test:defargfn(6,5) == 30)\");\nstate.dostring(\"assert(test:defargfn(2,2,2) == 8)\");\n```\n\n#### Variadic arguments function\n```c++\nstate[\"va_fun\"] = kaguya::function([](kaguya::VariadicArgType args) {for (auto v : args) { std::cout \u003c\u003c v.get\u003cstd::string\u003e() \u003c\u003c \",\"; }std::cout \u003c\u003c std::endl; });//C++11 lambda\nstate(\"va_fun(3,4,6,\\\"text\\\",6,444)\");//3,4,6,text,6,444,\n\n```\n\n#### Multiple Results to Lua\nIf return type of function is tuple, it returns multiple results to Lua\n```c++\nstate[\"multireturn\"] = kaguya::function([]() { return std::tuple\u003cint, int\u003e(32, 34); });\nstate(\"print(multireturn())\");//32    34\n```\n\n#### Nil values\nLuas `nil` converts to `nullptr` or 0 for pointer types, can be checked for with `isNilref()` and is different than the integer `0`.\nWhen you want to pass `nil` to lua either pass `nullptr`/`(void*)0` or `kaguya::NilValue`.\n```c++\nstate[\"value\"] = kaguya::NilValue();\n//or state[\"value\"] = nullptr;\n//or state[\"value\"] = (void*) 0;\nstate(\"assert(value == nil)\");\nstate(\"assert(value ~= 0)\");\nassert(state[\"value\"].isNilref());\nassert(state[\"value\"] == kaguya::NilValue());\nassert(state[\"value\"] == nullptr);\n\nstate[\"value\"] = 0;\nstate(\"assert(value ~= nil)\");\nstate(\"assert(value == 0)\");\nassert(!state[\"value\"].isNilref());\nassert(state[\"value\"] != kaguya::NilValue());\nassert(state[\"value\"] != nullptr);\n```\n\n#### Coroutine\n```c++\nkaguya::LuaThread cor = state.newThread();\nstate(\"corfun = function(arg)\"\n\"coroutine.yield(arg) \"\n\"coroutine.yield(arg*2) \"\n\"coroutine.yield(arg*3) \"\n\"return arg*4 \"\n\" end\");//define corouine function\n\nkaguya::LuaFunction corfun = state[\"corfun\"];//lua function get\n\n//exec coroutine with function and argument\nstd::cout \u003c\u003c int(cor(corfun, 3)) \u003c\u003c std::endl;//3\nstd::cout \u003c\u003c int(cor()) \u003c\u003c std::endl;//6\n//resume template argument is result type\nstd::cout \u003c\u003c cor.resume\u003cint\u003e() \u003c\u003c std::endl;//9\nstd::cout \u003c\u003c int(cor()) \u003c\u003c std::endl;//12\n\nkaguya::LuaThread cor2 = state.newThread();\n//3,6,9,12,\nwhile(!cor2.isThreadDead())\n{\n\tstd::cout \u003c\u003c cor2.resume\u003cint\u003e(corfun, 3) \u003c\u003c \",\";\n}\n```\n\n\n### Automatic type conversion\nstd::map and std::vector will be converted to a lua-table by default\n```c++\nkaguya::State s;\nstd::vector\u003cint\u003e vect = { 2,4,6,1 };\ns[\"vect\"] = vect;\ns(\"print(type(vect))\");// table\ns(\"for i,v in ipairs(vect) do print(v) end\");\n```\noutput:\n```\ntable\n1 2\n2 4\n3 6\n4 1\n```\n```c++\nkaguya::State s;\nstd::map\u003cstd::string, int\u003e map = { { \"apple\",3 },{ \"dog\",5 },{\"cat\",124},{ \"catfood\",644 } };\ns[\"map\"] = map;\ns(\"print(type(map))\");// table\ns(\"for i,v in pairs(map) do print(i,v) end\");\n```\noutput:\n```\ntable\ncatfood 644\ndog     5\ncat     124\napple   3\n```\n\n#### Type conversion customization\nIf you want to customize the type conversion from/to lua, specialize kaguya::lua_type_traits\n\nexample: (this is already implemented for std::string per default)\n```c++\ntemplate\u003c\u003e  struct lua_type_traits\u003cstd::string\u003e {\n\ttypedef std::string get_type;\n\ttypedef const std::string\u0026 push_type;\n\n\tstatic bool strictCheckType(lua_State* l, int index)\n\t{\n\t\treturn lua_type(l, index) == LUA_TSTRING;\n\t}\n\tstatic bool checkType(lua_State* l, int index)\n\t{\n\t\treturn lua_isstring(l, index) != 0;\n\t}\n\tstatic get_type get(lua_State* l, int index)\n\t{\n\t\tsize_t size = 0;\n\t\tconst char* buffer = lua_tolstring(l, index, \u0026size);\n\t\treturn std::string(buffer, size);\n\t}\n\tstatic int push(lua_State* l, push_type s)\n\t{\n\t\tlua_pushlstring(l, s.c_str(), s.size());\n\t\treturn 1;\n\t}\n};\n  ```\n\n#### Handling Errors\nEncountered lua errors will be written to the console by default, but you can change this:\n``` c++\nvoid HandleError(int errCode, const char * szError)\n{  //customize your error handling, eg. write to file...\n}\nkaguya::State l;\nl.setErrorHandler(HandleError);\nl.dofile(\"./scripts/custom.lua\"); // eg. accessing a non-existing file will invoke HandleError above\n```\n\n## run test\n```\nmkdir build\ncd build\ncmake ..\nmake\nctest\n```\nIf you don't want to use the default (system) library, add these 3 options to the cmake command\n```\ncmake -DLUA_INCLUDE_DIRS=path/to/lua/header/dir -DLUA_LIBRARY_DIRS=/abspath/to/lua/library/dir -DLUA_LIBRARIES=lualibname\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsatoren%2Fkaguya","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsatoren%2Fkaguya","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsatoren%2Fkaguya/lists"}