{"id":13732246,"url":"https://github.com/soulik/lutok2","last_synced_at":"2026-01-11T02:25:43.998Z","repository":{"id":21807740,"uuid":"25130377","full_name":"soulik/lutok2","owner":"soulik","description":"Advanced version of lutok C++/Lua binding","archived":false,"fork":false,"pushed_at":"2016-12-28T20:43:12.000Z","size":53,"stargazers_count":9,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-05-02T20:13:52.833Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/soulik.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-10-12T20:00:03.000Z","updated_at":"2022-07-19T04:02:01.000Z","dependencies_parsed_at":"2022-08-20T00:00:26.502Z","dependency_job_id":null,"html_url":"https://github.com/soulik/lutok2","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soulik%2Flutok2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soulik%2Flutok2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soulik%2Flutok2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soulik%2Flutok2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/soulik","download_url":"https://codeload.github.com/soulik/lutok2/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":213757425,"owners_count":15634176,"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":[],"created_at":"2024-08-03T02:01:50.269Z","updated_at":"2026-01-11T02:25:43.953Z","avatar_url":"https://github.com/soulik.png","language":"C++","funding_links":[],"categories":["Scripting"],"sub_categories":[],"readme":"Lutok2\n======\n\nC++/Lua binding helper for Lua 5.1 and LuaJIT 2.x+.\n\nDependencies\n============\nTo use Lutok2 successfully you'll need:\n\n* A standards-compliant C++11 complier\n* Lua 5.1.x or LuaJIT 2.0.x+ include and library files\n\nUsage\n=====\nFirst of all, you'll need to add lutok2 *include* directory into list of include directories.\nTo use it, add following include line and you're good to go.\n\n```cpp\n#include \u003clutok2/lutok2.hpp\u003e\n```\n\nAll Lutok2 functions and classes are stored in *lutok2* namespace so you might actually want to use following two lines instead:\n\n```cpp\n#include \u003clutok2/lutok2.hpp\u003e\nusing namespace lutok2;\n```\n\nAPI\n===\nAPI of Lutok2 library is divided into two sections:\n* State - functions that manage Lua state, object interface registration\n* Stack - functions that manage Lua stack\n \nState\n-----\n* __new State()__ - creates a new empty Lua state.\n* __new State(lua_State * L)__ - create an interface to existing Lua state (mostly used with Lua libraries).\n* __~State()__ - closes Lua state if it's been created with `new State()` constructor.\n* __stack__ - pointer to Stack object.\n* __openLibs()__ - loads all standard Lua libraries into current State.\n* __loadFile(const std::string \u0026 fileName)__ - loads/compiles a file with Lua source and pushes compiled function into stack.\n* __loadString(const std::string \u0026 fileName)__ - loads/compiles a string with Lua source and pushes compiled function into stack.\n* __error(const char * fmt, ...)__ - invokes error with formated message in current Lua state.\n* __registerLib(const Module \u0026 members)__ - registers library functions. All functions are bound into Lua table which needs to be at top of the stack.\n* __registerLib(const Module \u0026 members, const std::string \u0026 name, const int nup=0)__ - registers library functions for specific library.\n* __\\\u003cclassname\\\u003eregisterInterface(const std::string \u0026 name)__ - registers a C++ class interface and pushes constructor function into stack. You should always use consistent class naming to avoid naming collisions.\n* __getInterface\\\u003cclassname\\\u003e(const std::string \u0026 name)__ - returns C++ class interface based on class name.\n\nStack\n-----\n### Stack manipulation\n* __getTop()__ - returns number of stack items (arguments).\n* __setTop()__ - sets stack position.\n* __upvalueIndex(const int index)__ - returns pseudo-index of upvalue at specific index.\n* __pop(int n=1)__ - pops n items from stack.\n* __insert(int index)__ - insert items to the top of the stack.\n* __replace(int index)__ - moves top item to specific location on the stack overwriting existing item.\n* __remove(int index)__ - removes item at specific location (shifts other elements to close the gap).\n* __getGlobal(const std::string \u0026 name)__ - pushes global variable into top of the stack.\n* __setGlobal(const std::string \u0026 name)__ - stores item at top of the stack into global environment.\n\n### Table manipulation\n* __newTable()__ - creates a new table and pushes it to the top of the stack.\n* __newTable(const int acount, const int nacount)__ - creates and preallocates a new table and pushes it to the top of the stack (acount - number of elements in sequence; nacount - number of other elements).\n* __getTable(const int index = -3)__ - retrieves element from table at specific location. It takes top item from stack and uses it a key.\n* __setTable(const int index = -3)__ - stores item into table at specific location. It takes the first two items from the top of the stack in this order: key, value.\n* __concat(const int count)__ - concatenates number of items at the top of the stack.\n* __rawGet(const int index = -3)__ - similar to `getTable`, skips `__index` metamethod invokation.\n* __rawGet(const int n, const int index = -3)__ - retrieves n-th element from a table at specific location. Skips `__index` metmethod invokation.\n* __rawSet(const int index = -3)__ - similar to `setTable`, skips `__newindex` metamethod invokation.\n* __rawSet(const int n, const int index = -3)__ - set n-th element in a table at specific location. Skips `__newindex` metmethod invokation.\n* __getField(const std::string \u0026 key, const int index = -2)__ - retrieves a named field value from a table at specific location.\n* __getField(const int key, const int index = -2)__ - retrieves an indexed field value from a table at specific location.\n* __setField(const std::string \u0026 key, const int index = -2)__ - stores element at the top of the stack into table field at specific location.\n* __setField\\\u003cbool\\\u003e(const std::string \u0026 key, bool value, const int index)__ - stores a boolean value into table field.\n* __setField\\\u003cint\\\u003e(const std::string \u0026 key, int value, const int index)__ - stores an integer value into table field.\n* __setField\\\u003cLUA_NUMBER\\\u003e(const std::string \u0026 key, LUA_NUMBER value, const int index)__ - stores a numeric value into table field (a number is usually represented by double data type).\n* __setField\\\u003cconst char *\\\u003e(const std::string \u0026 key, const char * value, const int index)__ - stores null-terminated string value into table field.\n* __setField\\\u003cconst std::string \u0026\\\u003e(const std::string \u0026 key, const std::string \u0026 value, const int index)__ - stores null-terminated string value into table field.\n* __setField\\\u003clua_CFunction\\\u003e(const std::string \u0026 key, lua_CFunction value, const int index)__ - stores C function into table field.\n* __setField\\\u003cFunction\\\u003e(const std::string \u0026 key, Function value, const int index)__ - stores C++ function into table field (you may use lambda function).\n* __setField\\\u003ccxx_function\\\u003e(const std::string \u0026 key, cxx_function value, const int index)__ - stores C++ function into table field.\n* __setField\\\u003cvoid *\\\u003e(const std::string \u0026 key, void * value, const int index)__ - stores pointer value into table field (it's stored as a lightuser data value).\n* __setFieldLString(const std::string \u0026 name, const std::string \u0026 value, size_t len, const int index=-1)__ - stores a string value with specific length into table field (a string doesn't have to be null-terminated).\n\n### Pushing values into stack\n* __push\\\u003cint\\\u003e(int value)__ - pushes integer into stack.\n* __push\\\u003cLUA_NUMBER\\\u003e(LUA_NUMBER value)__ - pushes a number into stack (usually, a number uses double data type). \n* __push\\\u003cbool\\\u003e(bool value)__ - pushes boolean value into stack.\n* __push\\\u003cconst char *\\\u003e(const char * value)__ - pushes null-terminated `char*` string into stack.\n* __push\\\u003cconst std::string \u0026\\\u003e(const std::string \u0026 value)__ - pushes null-terminated `std::string` string into stack.\n* __push\\\u003cvoid *\\\u003e(void * value)__ - pushes a pointer into stack (it's used as a lightuser data). \n* __push\\\u003clua_CFunction\\\u003e(lua_CFunction value)__ - pushes C function into stack.\n* __push\\\u003cFunction\\\u003e(Function value)__ - pushes a C++ function into stack. You may use lambda function in this case.\n* __push\\\u003cFunction\\\u003e(Function value, int n)__ - pushes a C++ function into stack with n upvalues. You may use lambda function in this case.\n* __push\\\u003ccxx_function\\\u003e(cxx_function value)__ - pushes a C++ function into stack.\n* __push\\\u003ccxx_function\\\u003e(cxx_function value, int n)__ - pushes a C++ function into stack with n upvalues.\n* __pushClosure(lua_CFunction fn, int n)__ - pushes C function into stack with n upvalues.\n* __pushLString(const std::string \u0026 value, size_t len)__ - pushes a string with specific length into stack (string doesn't have to be null-terminated).\n* __pushLString(const std::string \u0026 value)__ - pushes a string into stack (string doesn't have to be null-terminated). A string lLength is obtained from std::string object.\n* __pushVFString(const char * fmt, ...)__ - pushes a formated string into stack.\n* __pushLiteral(const std::string value)__ - pushes a literal value into stack.\n* __pushNil()__ - pushes a nil value into stack.\n* __pushValue(const int index)__ - pushes a value from specific location to the top the stack.\n\n### Getting values from stack\n* __to\\\u003cbool\\\u003e(const int index)__ - gets a boolean value from stack.\n* __to\\\u003cint\\\u003e(const int index)__ - gets an integer value from stack.\n* __to\\\u003cLUA_NUMBER\\\u003e(const int index)__ - gets a numeric value from stack (mostly represented with double data type).\n* __to\\\u003cconst std::string\\\u003e(const int index)__ - gets a string value from stack.\n* __to\\\u003cvoid *\\\u003e(const int index)__ - gets a lightuser data pointer from stack.\n* __toLString(const int index = -1)__ - gets a string value from stack (the string is not null-terminated).\n\n### Value manipulation\n* __objLen(const int index = -1)__ - returns value length at specific location.\n* __type(const int index = -1)__ - returns value type (use with Lua `LUA_Ttypename` constants).\n* __is\\\u003cLUA_Ttypename\\\u003e(const int index = -1)__ - returns true if there's a value with specified data type at specific location.\n* __typeName(const int index = -1)__ - returns string representation of value data type at specific location.\n* __newUserData(size_t size)__ - allocates specific amount (bytes) for full userdata. Userdata value is pushed to the stop of the stack.\n* __checkUserData(const int narg, const std::string\u0026 name)__ - checks and returns full userdata pointer with specific name. Otherwise throws an error and returns `nullptr`.\n* __getUserData(const int narg, const std::string\u0026 name)__ - similar to `checkUserData` except it doesn't throw an error message.\n\n### Meta tables\n* __getMetatable(const int index = -1)__ - pushes a metatable of a value at specific location.\n* __getMetatable(const std::string \u0026 name)__ - pushes a metatable with specific name into stack.\n* __setMetatable(const int index = -2)__ - sets metatable for a value at specific location. Metatable is retrieved from the top of the stack.\n* __newMetatable(const std::string \u0026 name)__ - pushes a new metatable with specific name into stack. \n* __getMetaField(const std::string \u0026 name, const int index = -1)__ - pushes specific metatable field from a value at specific location into stack.\n \n### Functions\n* __call(const int nargs, const int nresults)__ - calls a function at the top of the stack with `nargs` arguments and expects `nresults` values on return.\n* __pcall(const int nargs, const int nresults, const int errFunction = 0)__ - similar to `call` except you can defined error function from specific location and in case of error message it throws a runtime exception which you can manage with `catch`.\n\n### Lua registry\n* __ref(const int index = LUA_REGISTRYINDEX)__ - stores a value at the top of the stack into registry and returns integer reference number which you can use to identify stored item.\n* __unref(const int ref, const int index = LUA_REGISTRYINDEX)__ - removes a reference to a value specified with reference number.\n* __regValue(const int n)__ - retrieves item from Lua registry with specified reference number.\n \nExamples\n========\n\nLutok2 usage in a library\n---------------------------\n```cpp\n#include \u003clutok2/lutok2.hpp\u003e\nusing namespace lutok2;\n\n#if (BUILDING_MyLibrary || MyLibrary_EXPORTS) \u0026\u0026 HAVE_VISIBILITY\n#define MyLibrary_DLL_EXPORTED __attribute__((visibility(\"default\")))\n#elif (BUILDING_MyLibrary || MyLibrary_EXPORTS) \u0026\u0026 defined _MSC_VER\n#define MyLibrary_DLL_EXPORTED __declspec(dllexport)\n#elif defined _MSC_VER\n#define MyLibrary_DLL_EXPORTED __declspec(dllimport)\n#else\n#define MyLibrary_DLL_EXPORTED\n#endif\n\nnamespace MyLibrary {\n    class MyClass {\n    public:\n        std::string value;\n        int method(int param1){\n            return param1 + 1;\n        };\n    };\n    \n\tclass LuaMyClass : public Object\u003cMyClass\u003e {\n\tpublic:\n\t    // Define all properties and methods here\n\t\texplicit LuaMyClass(State * state) : Object\u003cMyClass\u003e(state){\n\t\t\tLUTOK_PROPERTY(\"value\", \u0026LuaMyClass::getValue, \u0026LuaMyClass::setValue);\n\t\t\tLUTOK_PROPERTY(\"valueGetterOnly\", \u0026LuaMyClass::getValue, \u0026LuaMyClass::nullMethod);\n\t\t\tLUTOK_PROPERTY(\"valueSetterOnly\", \u0026LuaMyClass::nullMethod, \u0026LuaMyClass::setValue);\n\t\t\tLUTOK_METHOD(\"method\", \u0026LuaMyClass::method);\n\t\t}\n\n\t\tMyClass * constructor(State \u0026 state, bool \u0026 managed);\n\t\tvoid destructor(State \u0026 state, MyClass * object);\n\n\t    int method(State \u0026 state, MyClass * object);\n\t    int getValue(State \u0026 state, MyClass * object);\n\t    int setValue(State \u0026 state, MyClass * object);\n\t};\n\n    int LuaMyClass::method(State \u0026 state, MyClass * object){\n        Stack * stack = state.stack; //a shortcut\n        if (stack-\u003eis\u003cLUA_TNUMBER\u003e(1)){\n            int param1 = stack-\u003eto\u003cint\u003e(1);\n            int result = object-\u003emethod(param1);\n            stack-\u003epush\u003cint\u003e(result);\n            return 1;\n        }else{\n            state.error(\"Expects a number\");\n            return 0;\n        }\n    }\n    \n    // Initialize object\n    MyClass * LuaMyClass::constructor(State \u0026 state, bool \u0026 managed){\n        MyClass * object = new MyClass;\n        object-\u003evalue = \"Unspecified value\";\n        return object;\n    }\n    \n    // Don't forget to release alloced memory inside of object\n    void LuaMyClass::destructor(State \u0026 state, MyClass * object){\n        delete object;\n    }\n    \n    int LuaMyClass::getValue(State \u0026 state, MyClass * object){\n        Stack * stack = state.stack; //a shortcut\n        stack-\u003epush\u003cconst std::string \u0026\u003e(object-\u003evalue);\n        return 1;\n    }\n    \n    int LuaMyClass::setValue(State \u0026 state, MyClass * object){\n        Stack * stack = state.stack; //a shortcut\n        if (stack-\u003eis\u003cLUA_TSTRING\u003e(1)){\n            const std::string inputValue = stack-\u003eto\u003cconst std::string\u003e(1);\n            object-\u003evalue = inputValue;\n        }\n        return 0;\n    }\n\n\t// Must be called with a table value on stack - because of setField\n\tvoid initLuaMyClass(State* state, Module\u0026 module){\n\t    Stack * stack = state-\u003estack; //a shortcut\n\t    state-\u003eregisterInterface\u003cLuaMyClass\u003e(\"MyLibrary_LuaMyClass\");\n\t    // Register LuaMyClass constructor in current table interface\n\t    stack-\u003esetField(\"LuaMyClass\")\n\t}\n\n\tint init(State \u0026 state){\n\t\treturn 0;\n\t}\n\t\n\tint processObject(State \u0026 state){\n        LuaMyClass * interfaceLuaMyClass = state.getInterface\u003cLuaMyClass\u003e(\"MyLibrary_LuaMyClass\");\n        // Retrieve MyClass object from Lua - in the 1st argument\n        MyClass * object = interfaceLuaMyClass-\u003eget(1);\n        if (object){\n            MyClass * newObject = new MyClass;\n            newObject-\u003evalue = object-\u003evalue;\n            /*  !!! IMPORTANT !!!\n                1. You need to set second argument (luaManaged value) to true to activate automatic object cleanup\n                which will call destructor on GC. Otherwise you risk memory leaks!\n                \n                2. If you're pushing objects that are managed by other classes, set this parameter to false.\n                GC will not call destructor when the Lua object is collected.\n                You can think of this as a light object reference.\n            */\n            bool luaManaged = true;\n            interfaceLuaMyClass-\u003epush(newObject, luaManaged);\n            return 1;\n        }else{\n            state.error(\"Expects a LuaMyClass object\");\n            return 0;\n        }\n\t}\n};\n\nextern \"C\" MyLibrary_DLL_EXPORTED int luaopen_MyLibrary(lua_State * L){\n\tState * state = new State(L);\n\tStack * stack = state-\u003estack;\n\tModule MyLibrary_module;\n\n\tstack-\u003enewTable();\n\t\n\tinitLuaMyClass(state, MyLibrary_module);\n\t\n\tMyLibrary_module[\"init\"] = MyLibrary::init;\n\tMyLibrary_module[\"processObject\"] = MyLibrary::processObject;\n\n\tstate-\u003eregisterLib(MyLibrary_module);\n\treturn 1;\n}\n\n```\n\nLutok2 usage in application\n---------------------------\n```cpp\n#include \"lutok2/lutok2.hpp\"\n\nusing namespace lutok2;\n\nint testFun(State \u0026 state){\n\tstate.loadString(\n\t\t\"print(\\\"Hello world from lambda function!\\\") \\\n\t\t\t\t\t\t\"\n\t\t\t\t\t\t);\n\tstate.stack-\u003ecall(0, 0);\n\treturn 0;\n}\n\nclass TestObj {\nprivate:\n\tstd::string value;\npublic:\n\tTestObj(const std::string \u0026 value){\n\t\tthis-\u003evalue = value;\n\t}\n\tstd::string getValue(){\n\t\treturn value;\n\t}\n\tvoid setValue(const std::string \u0026 value){\n\t\tthis-\u003evalue = value;\n\t}\n};\n\nclass LTestObj : public Object \u003c TestObj \u003e {\npublic:\n\texplicit LTestObj(State * state) : Object\u003cTestObj\u003e(state){\n\t\tLUTOK_PROPERTY(\"value\", \u0026LTestObj::getValue, \u0026LTestObj::setValue);\n\t\tLUTOK_METHOD(\"method\", \u0026LTestObj::method);\n\t}\n\tTestObj * constructor(State \u0026 state, bool \u0026 managed){\n\t\tTestObj * obj = nullptr;\n\t\tStack * stack = state.stack;\n\t\tif (stack-\u003eis\u003cLUA_TSTRING\u003e(1)){\n\t\t\tconst std::string value = stack-\u003eto\u003cconst std::string\u003e(1);\n\t\t\tobj = new TestObj(value);\n\t\t}\n\t\tmanaged = true;\n\t\treturn obj;\n\t}\n\tvoid destructor(State \u0026 state, TestObj * object){\n\t\tdelete object;\n\t}\n\tint operator_concat(State \u0026 state, TestObj * a, TestObj * b){\n\t\tpush(new TestObj(a-\u003egetValue() + b-\u003egetValue()), true);\n\t\treturn 1;\n\t}\n\n\tint getValue(State \u0026 state, TestObj * object){\n\t\tstate.stack-\u003epush\u003cconst std::string \u0026\u003e(object-\u003egetValue());\n\t\treturn 1;\n\t}\n\tint setValue(State \u0026 state, TestObj * object){\n\t\tconst std::string value = state.stack-\u003eto\u003cconst std::string\u003e(1);\n\t\tobject-\u003esetValue(value);\n\t\treturn 0;\n\t}\n\tint method(State \u0026 state, TestObj * object){\n\t\tstate.stack-\u003epush\u003cconst std::string \u0026\u003e(\"Hello\");\n\t\treturn 1;\n\t}\n};\n\n\nint main(char ** argv, int argc){\n\n\tState state;\n\tstate.openLibs();\n\n\tstate.stack-\u003epush\u003cFunction\u003e([](State \u0026 state) -\u003e int{\n\t\tstate.loadString(\n\t\t\t\"print(\\\"Hello world from lambda function!\\\") \\\n\t\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t\t);\n\t\tstate.stack-\u003ecall(0, 0);\n\t\treturn 0;\n\t});\n\tstate.stack-\u003esetGlobal(\"testing\");\n\n\tstate.registerInterface\u003cLTestObj\u003e(\"testObj\");\n\tstate.stack-\u003esetGlobal(\"testObj\");\n\n\ttry {\n\t\tstate.loadFile(\"test/test.lua\");\n\t\tstate.stack-\u003ecall(0, 0);\n\t}\n\tcatch (std::exception \u0026 e){\n\t\tprintf(\"Can't load test file: %s\", e.what());\n\t}\n\treturn 0;\n}\n```\n\nAuthors\n=======\n* Mário Kašuba \u003csoulik42@gmail.com\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoulik%2Flutok2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsoulik%2Flutok2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoulik%2Flutok2/lists"}