A binding between C++11 and Lua language

Overview

lua-intf

lua-intf is a binding between C++11 and Lua language, it provides three different set of API in one package:

  • LuaBinding, Export C++ class or function to Lua script
  • LuaRef, High level API to access Lua object
  • LuaState, Low level API as simple wrapper for Lua C API

lua-intf has no dependencies other than Lua and C++11. And by default it is headers-only library, so there is no makefile or other install instruction, just copy the source, include LuaIntf.h, and you are ready to go.

lua-intf is inspired by vinniefalco's LuaBridge work, but has been rewritten to take advantage of C++11 features.

Lua and C++ error handling

By default LuaIntf expect the Lua library to build under C++, this will allow Lua library to throw exception upon error, and make sure C++ objects on stack to be destructed correctly. For more info about error handling issues, please see:

http://lua-users.org/wiki/ErrorHandlingBetweenLuaAndCplusplus

If you really want to use Lua library compiled under C and want to live with longjmp issues, you can define LUAINTF_LINK_LUA_COMPILED_IN_CXX to 0 before including lua-intf headers:

#define LUAINTF_LINK_LUA_COMPILED_IN_CXX 0
#include "LuaIntf/LuaIntf.h"

Compile Lua library in C++

Most distributions of precompiled Lua library are compiled under C, if you need Lua library compiled under C++, you probably need to compile it by yourself. It is actually very easy to build Lua library under C++, first get a copy of source code of the Lua library:

curl http://www.lua.org/ftp/lua-5.3.0.tar.gz -o lua-5.3.0.tar.gz
tar xf lua-5.3.0.tar.gz
cd lua-5.3.0

To compile on Linux:

make linux MYCFLAGS="-x c++" CC="g++"

To compile on Mac OSX:

make macosx MYCFLAGS="-x c++" MYLDFLAGS="-lc++"

To compile on Windows with MINGW and MSYS:

make mingw MYCFLAGS="-x c++" CC="g++"

And then install to your chosen directory in <path>:

make install INSTALL_TOP=<path>

Export C++ class or function to Lua script

You can easily export C++ class or function for Lua script, consider the following C++ class:

    class Web
    {
    public:
        // base_url is optional
        Web(const std::string& base_url);
        ~Web();

        static void go_home();

        static std::string home_url();
        static void set_home_url(const std::string& url);

        std::string url() const;
        void set_url(const std::string& url);
        std::string resolve_url(const std::string& uri);

        // doing reload if uri is empty
        std::string load(const std::string& uri);
    };

You can export the Web class by the following code:

    LuaBinding(L).beginClass<Web>("Web")
        .addConstructor(LUA_ARGS(_opt<std::string>))
        .addStaticProperty("home_url", &Web::home_url, &Web::set_home_url)
        .addStaticFunction("go_home", &Web::go_home)
        .addProperty("url", &Web::url, &Web::set_url)
        .addFunction("resolve_url", &Web::resolve_url)
        .addFunction("load", &Web::load, LUA_ARGS(_opt<std::string>))
        .addStaticFunction("lambda", [] {
            // you can use C++11 lambda expression here too
            return "yes";
        })
    .endClass();

To access the exported Web class in Lua:

    local w = Web()								-- auto w = Web("");
    w.url = "http://www.yahoo.com"				-- w.set_url("http://www.yahoo.com");
    local page = w:load()						-- auto page = w.load("");
    page = w:load("http://www.google.com")		-- page = w.load("http://www.google.com");
    local url = w.url							-- auto url = w.url();

Module and class

C++ class or functions exported are organized by module and class. The general layout of binding looks like:

    LuaBinding(L)
        .beginModule(string module_name)
            .addFactory(function* func)

            .addConstant(string constant_name, VALUE_TYPE value)

            .addVariable(string property_name, VARIABLE_TYPE* var, bool writable = true)
            .addVariableRef(string property_name, VARIABLE_TYPE* var, bool writable = true)

            .addProperty(string property_name, FUNCTION_TYPE getter, FUNCTION_TYPE setter)
            .addProperty(string property_name, FUNCTION_TYPE getter)

            .addFunction(string function_name, FUNCTION_TYPE func)

            .beginModule(string sub_module_name)
                ...
            .endModule()

            .beginClass<CXX_TYPE>(string class_name)
                ...
            .endClass()

            .beginExtendClass<CXX_TYPE, SUPER_CXX_TYPE>(string sub_class_name)
                ...
            .endClass()
        .endModule()

        .beginClass<CXX_TYPE>(string class_name)
            .addFactory(FUNCTION_TYPE func)		// you can only have one addFactory or addConstructor
            .addConstructor(LUA_ARGS(...))

            .addConstant(string constant_name, VALUE_TYPE value)

            .addStaticVariable(string property_name, VARIABLE_TYPE* var, bool writable = true)
            .addStaticVariableRef(string property_name, VARIABLE_TYPE* var, bool writable = true)

            .addStaticProperty(string property_name, FUNCTION_TYPE getter, FUNCTION_TYPE setter)
            .addStaticProperty(string property_name, FUNCTION_TYPE getter)

            .addStaticFunction(string function_name, FUNCTION_TYPE func)

            .addVariable(string property_name, CXX_TYPE::FIELD_TYPE* var, bool writable = true)
            .addVariableRef(string property_name, CXX_TYPE::FIELD_TYPE* var, bool writable = true)

            .addProperty(string property_name, CXX_TYPE::FUNCTION_TYPE getter, CXX_TYPE::FUNCTION_TYPE setter)
            .addProperty(string property_name, CXX_TYPE::FUNCTION_TYPE getter, CXX_TYPE::FUNCTION_TYPE getter_const, CXX_TYPE::FUNCTION_TYPE setter)
            .addProperty(string property_name, CXX_TYPE::FUNCTION_TYPE getter)

            .addPropertyReadOnly(string property_name, CXX_TYPE::FUNCTION_TYPE getter, CXX_TYPE::FUNCTION_TYPE getter_const)
            .addPropertyReadOnly(string property_name, CXX_TYPE::FUNCTION_TYPE getter)

            .addFunction(string function_name, CXX_TYPE::FUNCTION_TYPE func)
        .endClass()

        .beginExtendClass<CXX_TYPE, SUPER_CXX_TYPE>(string sub_class_name)
            ...
        .endClass()

A module binding is like a package or namespace, it can also contain other sub-module or class. A module can have the following bindings:

  • factory function - bind to global or static C++ functions, or forward to sub-class constructor or sub-module factory
  • constant - bind to constant value
  • variable - bind to global or static variable, the valued pushed to lua is by-value, can be read-only
  • variable reference - bind to global or static variable, the valued pushed to lua is by-reference, can be read-only
  • property - bind to getter and setter functions, can be read-only
  • function - bind to global or static function

A class binding is modeled after C++ class, it models the const-ness correctly, so const object can not access non-const functions. It can have the following bindings:

  • constructor - bind to class constructor
  • factory function - bind to global or static function that return the newly created object
  • constant - bind to constant value, constant is static
  • static variable - bind to global or static variable, the valued pushed to lua is by-value, can be read-only
  • static variable reference - bind to global or static variable, the valued pushed to lua is by-reference, can be read-only
  • static property - bind to global or static getter and setter functions, can be read-only
  • static function - bind to global or static function
  • member variable - bind to member fields, the valued pushed to lua is by-value, can be read-only
  • member variable reference - bind to member fields, the valued pushed to lua is by-reference, can be read-only
  • member property - bind to member getter and setter functions, you can bind const and non-const version of getters, can be read-only
  • member function - bind to member functions

For module and class, you can have only one constructor or factory function. To access the factory or constructor in Lua script, you call the module or class name like a function, for example the above Web class:

    local w = Web("http://www.google.com")

The static or module variable, property and constant is accessible by module/class name, it is just like table field:

    local url = Web.home_url
    Web.home_url = "http://www.google.com"

The static function can be called by the following, note the '.' syntax and class name:

    Web.go_home()

The member variable and property is associated with object, so it is accessible by variable:

    local session = Web("http://www.google.com")
    local url = session.url
    session.url = "http://www.google.com"

The member function can be called by the following, note the ':' syntax and object name:

    session:load("http://www.yahoo.com")

Integrate with Lua module system

The lua module system don't register modules in global variables. So you'll need to pass a local reference to LuaBinding. For example:

    extern "C" int luaopen_modname(lua_State* L)
    {
        LuaRef mod = LuaRef::createTable(L);
        LuaBinding(mod)
            ...;
        mod.pushToStack();
        return 1;
    }

C++ object life-cycle

lua-intf store C++ object via Lua userdata, and it stores the object in the following ways:

  • By value, the C++ object is stored inside userdata. So when Lua need to gc the userdata, the memory is automatically released. lua-intf will make sure the C++ destructor is called when that happened. C++ constructor or function returns object struct will create this kind of Lua object.

  • By pointer, only the pointer is stored inside userdata. So when Lua need to gc the userdata, the object is still alive. The object is owned by C++ code, it is important the registered function does not return pointer to newly allocated object that need to be deleted explicitly, otherwise there will be memory leak. C++ function returns pointer or reference to object will create this kind of Lua object.

  • By shared pointer, the shared pointer is stored inside userdata. So when Lua need to gc the userdata, the shared pointer is destructed, that usually means Lua is done with the object. If the object is still referenced by other shared pointer, it will keep alive, otherwise it will be deleted as expected. C++ function returns shared pointer will create this kind of Lua object. A special version of addConstructor will also create shared pointer automatically.

Using shared pointer

If both C++ and Lua code need to access the same object, it is usually better to use shared pointer in both side, thus avoiding memory leak. You can use any kind of shared pointer class, as long as it provides:

  • operator ->
  • operator *
  • operator bool
  • default constructor
  • copy constructor

Before you can use it, you need to register it with lua-intf, take std::shared_ptr for example:

    namespace LuaIntf
    {
        LUA_USING_SHARED_PTR_TYPE(std::shared_ptr)
    }

For constructing shared pointer inside Lua userdata, you can register the constructor by adding LUA_SP macro and the actual shared pointer type, for example:

    LuaBinding(L).beginClass<Web>("web")
        .addConstructor(LUA_SP(std::shared_ptr<Web>), LUA_ARGS(_opt<std::string>))
        ...
    .endClass();

Using custom deleter

If custom deleter is needed instead of the destructor, you can register the constructor with deleter by adding LUA_DEL macro, for example:

     class MyClass
     {
     public:
          MyClass(int, int);
          void release();
     };

     struct MyClassDeleter
     {
         void operator () (MyClass* p)
         {
             p->release();
         }
     };

    LuaBinding(L).beginClass<MyClass>("MyClass")
        .addConstructor(LUA_DEL(MyClassDeleter), LUA_ARGS(int, int))
        ...
    .endClass();

Using STL-style container

By default lua-intf does not add conversion for container types, however, you can enable support for container type with the following:

    namespace LuaIntf
    {
        LUA_USING_LIST_TYPE(std::vector)
        LUA_USING_MAP_TYPE(std::map)
    }

For non-template or non-default template container type, you can use:

    class non_template_int_list
    { ... };

    template <typename T, typename A, typename S>
    class custom_template_list<T, A, S>
    { ... };

    namespace LuaIntf
    {
        LUA_USING_LIST_TYPE_X(non_template_int_list)

        // you need to use LUA_COMMA for , to workaround macro limitation
        LUA_USING_LIST_TYPE_X(custom_template_list<T LUA_COMMA A LUA_COMMA S>,
            typename T, typename A, typename S)
    }

Function calling convention

C++ function exported to Lua can follow one of the two calling conventions:

  • Normal function, the return value will be the value seen on the Lua side.

  • Lua lua_CFunction convention, that the first argument is lua_State* and the return type is int. And just like lua_CFunction you need to manually push the result onto Lua stack, and return the number of results pushed.

lua-intf extends lua_CFunction convention by allowing more arguments besides lua_State*, the following functions will all follow the lua_CFunction convention:

    // regular lua_CFunction convention
    int func_1(lua_state* L);

    // lua_CFunction convention, but allow arg1, arg2 to map to arguments
    int func_2(lua_state* L, const std::string& arg1, int arg2);

    // this is *NOT* lua_CFunction
    // the L can be placed anywhere, and it is stub to capture lua_State*,
    // and do not contribute to actual Lua arguments
    int func_3(const std::string& arg1, lua_state* L);

    class Object
    {
    public:
        // class method can follow lua_CFunction convention too
        int func_1(lua_state* L);

        // class lua_CFunction convention, but allow arg1, arg2 to map to arguments
        int func_2(lua_state* L, const std::string& arg1, int arg2);
    };

    // the following can also be lua_CFunction convention if it is added as class functions
    // note the first argument must be the pointer type of the registered class
    int obj_func_1(Object* obj, lua_state* L);
    int obj_func_2(Object* obj, lua_state* L, const std::string& arg1, int arg2);

For every function registration, lua-intf also support C++11 std::function type, so you can use std::bind or lambda expression if needed. You can use lambda expression freely without giving full std::function declaration; std::bind on the other hand, must be declared:

    LuaBinding(L).beginClass<Web>("Web")
        .addStaticFunction("lambda", [] {
            // you can use C++11 lambda expression here too
            return "yes";
        })
        .addStaticFunction<std::function<std::string()>>("bind",
            std::bind(&Web::url, other_web_object))
    .endClass();

If your C++ function is overloaded, pass &function is not enough, you have to explicitly cast it to proper type:

    static int test(string, int);
    static string test(string);

    LuaBinding(L).beginModule("utils")

        // this will bind int test(string, int)
        .addFunction("test_1", static_cast<int(*)(string, int)>(&test))

        // this will bind string test(string), by using our LUA_FN macro
        // LUA_FN(RETURN_TYPE, FUNC_NAME, ARG_TYPES...)
        .addFunction("test_2", LUA_FN(string, test, string))

    .endModule();

Function argument modifiers

By default the exported functions expect every argument to be mandatory, if the argument is missing or not compatible with the expected type, the Lua error will be raised. You can change the function passing requirement by adding argument passing modifiers in LUA_ARGS, lua-intf supports the following modifiers:

  • _opt<TYPE>, specify the argument is optional; if the argument is missing, the value is created with default constructor

  • _def<TYPE, DEF_NUM, DEF_DEN = 1>, specify the argument is optional; if the argument is missing, the default value is used as DEF_NUM / DEF_DEN

  • _out<TYPE&>, specify the argument is for output only; the output value will be pushed after the normal function return value, and in argument order if there is multiple output

  • _ref<TYPE&>, specify the argument is mandatory and for input/output; the output value will be pushed after the normal function return value, and in argument order if there is multiple output

  • _ref_opt<TYPE&>, combine _ref<TYPE&> and _opt<TYPE>

  • _ref_def<TYPE&, DEF_NUM, DEF_DEN = 1>, combine _ref<TYPE&> and _def<TYPE, DEF_NUM, DEF_DEN = 1>

  • If none of the above modifiers are used, the argument is mandatory and for input only

All output modifiers require the argument to be reference type, using pointer type for output is not supported. The reason _def<TYPE, DEF_NUM, DEF_DEN = 1> requires DEF_NUM and DEF_DEN is to workaround C++ limitation. The C++ template does not allow floating point number as non-type argument, in order specify default value for float, you have to specify numerator and denominator pair (the denominator is 1 by default). For example:

    struct MyString
    {
        std::string indexOf(const std::string& str, int pos);
        std::string desc(float number);
        ...
    };

    #define _def_float(f) _def<float, long((f) * 1000000), 1000000>

    LuaBinding(L).beginClass<MyString>("mystring")

        // this will make pos = 1 if it is not specified in Lua side
        .addFunction("indexOf", &MyString::indexOf, LUA_ARGS(std::string, _def<int, 1>))

        // this will make number = 1.333 = (4 / 3) if it is not specified in Lua side
        // because C++ does not allow float as non-type template parameter
        // you have to use ratio to specify floating numbers 1.333 = (4 / 3)
        // LUA_ARGS(_def<float, 1.33333f>) will result in error
        .addFunction("indexOf", &MyString::desc, LUA_ARGS(_def<float, 4, 3>))

        // you can define your own macro to make it easier to specify float
        // please see _def_float for example
        .addFunction("indexOf2", &MyString::desc, LUA_ARGS(_def_float(1.3333f)))
    .endClass();

Return multiple results for Lua

It is possible to return multiple results by telling which argument is for output, for example:

    static std::string match(const std::string& src, const std::string& pat, int pos, int& found_pos);

    LuaBinding(L).beginModule("utils")

        // this will return (string) (found_pos)
        .addFunction("match", &match, LUA_ARGS(std::string, std::string, _def<int, 1>, _out<int&>))

    .endModule();

Yet another way to return multiple results is to use std::tuple:

    static std::tuple<std::string, int> match(const std::string& src, const std::string& pat, int pos);

    LuaBinding(L).beginModule("utils")

        // this will return (string) (found_pos)
        .addFunction("match", &match)

    .endModule();

And you can always use lua_CFunction to manually push multiple results by yourself.

Lua for-loop iteration function

lua-intf provides a helper class CppFunctor to make it easier to implement for-loop iteration function for Lua. To use it, user need to inherit CppFunctor, and override run method and optional destructor. Then call pushToStack to create the functor object on Lua stack.

    class MyIterator : public CppFunctor
    {
        MyIterator(...)
        {
            ...
        }

        virtual ~MyIterator()
        {
            ...
        }

        // the for-loop will call this function for each step until it return 0
        virtual int run(lua_State* L) override
        {
            ...
            // return the number of variables for each step of for-loop
            // or return 0 to end the for-loop
            return 2;
        }
    }

    int xpairs(lua_State* L)
    {
        return CppFunctor::make<MyIterator>(L, ...); // ... is constructor auguments
    }

To register the for-loop iteration function:

    LuaBinding(L).beginModule("utils")

        .addFunction("xpairs", &xpairs)

    .endModule();

To use the iteration function in Lua code:

    for x, y in utils.xpairs(...) do
        ...
    end

Custom type mapping

It is possible to add primitive type mapping to the lua-intf, all you need to do is to add template specialization to LuaTypeMapping<Type>. You need to:

  • provide void push(lua_State* L, const Type& v)
  • provide Type get(lua_State* L, int index)
  • provide Type opt(lua_State* L, int index, const Type& def)

For example, to add std::wstring mapping to Lua string:

    namespace LuaIntf
    {

    template <>
    struct LuaTypeMapping <std::wstring>
    {
        static void push(lua_State* L, const std::wstring& str)
        {
            if (str.empty()) {
                lua_pushliteral(L, "");
            } else {
                std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
                std::string buf = conv.to_bytes(str);
                lua_pushlstring(L, buf.data(), buf.length());
            }
        }

        static std::wstring get(lua_State* L, int index)
        {
            size_t len;
            const char* p = luaL_checklstring(L, index, &len);
            std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
            return conv.from_bytes(p, p + len);
        }

        static std::wstring opt(lua_State* L, int index, const std::wstring& def)
        {
            return lua_isnoneornil(L, index) ? def : get(L, index);
        }
    };

    } // namespace LuaIntf

After that, you are able to push std::wstring onto or get std::wstring from Lua stack directly:

    std::wstring s = ...;
    Lua::push(L, s);

    ...

    s = Lua::pop<std::wstring>(L);

High level API to access Lua object

LuaRef is designed to provide easy access to Lua object, and in most case you don't have to deal with Lua stack like the low level API. For example:

    lua_State* L = ...;
    lua_getglobal(L, "module");
    lua_getfield(L, -1, "method");
    lua_pushintteger(L, 1);
    lua_pushstring(L, "yes");
    lua_pushboolean(L, true);
    lua_call(L, 3, 0);

The above code can be rewritten as:

    LuaRef func(L, "module.method");
    func(1, "yes", true);

Table access is as simple:

    LuaRef table(L, "my_table");
    table["value"] = 15;
    int value = table.get<int>("value");

    for (auto& e : table) {
        std::string key = e.key<std::string>();
        LuaRef value = e.value<LuaRef>();
        ...
    }

And you can mix it with the low level API:

    lua_State* L = ...;
    LuaRef v = ...;
    lua_getglobal(L, "my_method");
    Lua::push(L, 1);					// the same as lua_pushinteger
    Lua::push(L, v);					// push v to lua stack
    Lua::push(L, true);					// the same as lua_pushboolean
    lua_call(L, 3, 2);
    LuaRef r(L, -2); 					// map r to lua stack index -2

You can use the std::tuple for multiple return values:

    LuaRef func(L, "utils.match");
    std::string found;
    int found_pos;
    std::tie(found, found_pos) = func.call<std::tuple<std::string, int>>("this is test", "test");

Low level API as simple wrapper for Lua C API

LuaState is a simple wrapper of one-to-one mapping for Lua C API, consider the following code:

    lua_State* L = ...;
    lua_getglobal(L, "module");
    lua_getfield(L, -1, "method");
    lua_pushintteger(L, 1);
    lua_pushstring(L, "yes");
    lua_pushboolean(L, true);
    lua_call(L, 3, 0);

It can be effectively rewritten as:

    LuaState lua = L;
    lua.getGlobal("module");
    lua.getField(-1, "method");
    lua.push(1);
    lua.push("yes");
    lua.push(true);
    lua.call(3, 0);

This low level API is completely optional, and you can still use the C API, or mix the usage. LuaState is designed to be a lightweight wrapper, and has very little overhead (if not as fast as the C API), and mostly can be auto-casting to or from lua_State*. In the lua-intf, LuaState and lua_State* are inter-changeable, you can pick the coding style you like most.

LuaState does not manage lua_State* life-cycle, you may take a look at LuaContext class for that purpose.

Comments
  • Add possibility for function wrapping

    Add possibility for function wrapping

    Hi, I would like to bind to instance function with wrapper method:

    void MyWrapper_Method(ClassInstance* instance, int test)
    {
    }
    
    .addWrapperFunction("test", &MyWrapper_Method)
    

    I have done this into CppBindClass.h

    template <typename FN>
        CppBindClass<T>& addWrapperFunction(const char* name, const FN& proc)
        {
            static_assert(!std::is_function<FN>::value,
                "function pointer is needed, please prepend & to function name");
            using CppProc = CppBindMethod<FN>;
            setMemberFunction(name, LuaRef::createFunction(state(), &CppProc::call, CppProc::function(proc)), true);
            return *this;
        }
    

    Thanks

    invalid question 
    opened by amerkoleci 11
  • Support std function as parameters

    Support std function as parameters

    Hi, I would like to bind to a class method that accepts std function as parameter, how can I achieve this?

    LuaGlue has support for this, https://github.com/Tomasu/LuaGlue

    https://github.com/Tomasu/LuaGlue/blob/master/include/LuaGlue/StackTemplates/StdFunction.h

    Thanks

    enhancement 
    opened by amerkoleci 10
  • Support for user aligned types

    Support for user aligned types

    I would like to patch LuaIntf to support user aligned types. At the moment, the alignment of types is ignored as a result of the way placement new works. User aligned types are common in games where SIMD instructions are useful. I worked around this for a while by patching LuaIntf to allocate user aligned types directly via new, and just store their pointers in the user data. However, I think it would probably be better to use something like alignof to dynamically allocate extra memory and offset it so as to avoid the additional memory allocation.

    enhancement 
    opened by krisr 9
  • Problem with multiple results std:tuple from Lua function

    Problem with multiple results std:tuple from Lua function

    Hello, Steve. Can you give me a hint?

    CPP:

    LuaIntf::LuaRef require(context->state(), "require");
    require("main");
    LuaIntf::LuaRef main(context->state(), "main");
    std::string str;
    int errcode;
    std::tie(errcode, str) = main.call<std::tuple<int,std::string>>();
    

    main.lua:

    function main()
        return 1, "test"
    end
    

    MinGW 4.9.1 32bit under Win8 with Lua5.3

    Unfortunately, I got a lua error: bad argument #1 (number expected, got function)...

    bug 
    opened by chenjiansysu 7
  • Objects associated by reference to a Lua variable have weird behaviour.

    Objects associated by reference to a Lua variable have weird behaviour.

    Modification of variables/calls to functions get routed to the C++ object, but when the C++ object is destroyed (e.g. falling out of scope) the Lua variable remains valid and the variables are still valid.

    question 
    opened by ghost 7
  • Visual Studio

    Visual Studio "14" support

    I know the "C++11" means that this project do not support Visual Studio. But Visual Studio "14" (current CTP4) is much better now. It's only need a little change to work with VS14 . Will you accept It?^_^ I'll post the linux/gcc,mac/clang compatibility of this chane later. :)

    patch: CppArg.h -typedef typename Traits::Type Type; -typedef typename Traits::ValueType ValueType; -typedef typename Traits::HolderType HolderType; +typedef Traits::Type Type; +typedef Traits::ValueType ValueType; +typedef Traits::HolderType HolderType;

    enhancement 
    opened by greyhu 7
  • addVariable results in copy on read

    addVariable results in copy on read

    It appears addVariable always results in a copy of the variable being created before it is pushed on the stack. This is problematic for class types for two reasons: it results in extra work and memory, and it does not support class types which are missing copy constructors.

    I'll take a stab at changing the behavior for class types, but I wanted to call it to your attention first in case I am potentially misreading the code or misusing the API.

    enhancement 
    opened by krisr 7
  • Problem pushing local value onto the stack

    Problem pushing local value onto the stack

    Hi

    I'm trying to bind my vector math(vec2, vec3, vec4) classes. Specifically multiplication between a vector and a scalar. I've encountered a problem and also have one question. The problem is that when I try to push the result of the multiplication, it seems the result is pushed by pointer to the object although the object is a local variable inside a function:

    template <typename T>
    int vec_mul(T *a, lua_State *L, LuaRef b)
    {    
        T res(0.0f);
    
        if (b.type() == LuaTypeID::NUMBER)
        {
            res = *a * b.toValue<float>();
        }
    
        Lua::push(L, res);
        return 1;
    }
    

    and for my binding of vec3 for example:

    .beginClass<vec3>("vec3")
        .addConstructor(LUA_ARGS(float, float, float))
        .addVariable("x", &vec3::x)
        .addVariable("y", &vec3::y)
        .addVariable("z", &vec3::z)
        ...
        .addFunction("__mul", &vec_mul<vec3>)
        ...
    

    It seems that the variable res is pushed by pointer. If I change it to:

    Lua::push(L, res * 1.0f);
    

    It works properly since res * 1.0f is now an rvalue. Is there a way to force pushing by value instead of by pointer?

    As for my question, how can I support both pre and post multiplication by a scalar? The above code handles post multiplication but pre multiplication means Lua calls the __mul function with the first parameter being a number and the second parameter the vector

    Thanks.

    bug 
    opened by ibachar 6
  • Access derived class' methods from a base class object

    Access derived class' methods from a base class object

    Sample classes:

    class Base {};
    
    class Derived : public Base {
    public:
       void foo();
    };
    
    // Their binding code
    
    LuaIntf::LuaBinding(L).beginClass<Base>("Base")
    .endClass();
    
    LuaIntf::LuaBinding(L).beginExtendClass<Derived, Base>("Derived")
        .addFunction("foo", &Derived::foo)
    .endClass();
    

    Let's say I have an object of class Derived, but the pointer that keeps track of it is of type Base:

    Derived *a = new Derived();
    // ...
    Base *b = a;
    

    I notice that if I push b to lua, I will not be able to call foo inside the script:

    Lua::setGlobal(L, "b", b);
    
    b:foo() -- This fails
    

    Is it possible to get it to work? (I think it's duck typing) Thank you very much. :)

    question 
    opened by hasyimibhar 6
  • Pass nil from Lua to C++

    Pass nil from Lua to C++

    Hi,

    I'm having problems passing nils from Lua to my C++ code. For instance if I register a function

    void f(int *i)
    {
    }
    

    and then bind it

    module.addFunction("f", &f);
    

    then when calling it from Lua

    module.f(nil)
    

    I get Lua error expect userdata, got nil. Is there anything I'm doing wrong or is feature not supported?

    question 
    opened by 0xc0dec 5
  • Svar: Consider using a unified binding across languages

    Svar: Consider using a unified binding across languages

    opened by zdzhaoyong 0
  • mutithread error handle

    mutithread error handle

    I set a lua function as a callback in C++.

    In a child thread ,I call a "run_in_main_thread" function , to call this callback in main thread. (because this callback can not be called in child thread ).

    the problem is , when this callback cause some errors , the catch code In CppBindingModule.h doesn't trigger.

     struct CppBindMethodBase{
        static int call(lua_State* L)
         {
             try {
                 assert(lua_isuserdata(L, lua_upvalueindex(1)));
                 const FN& fn = *reinterpret_cast<const FN*>(lua_touserdata(L, lua_upvalueindex(1)));
                assert(fn);
                CppArgTuple<P...> args;
               CppArgTupleInput<P...>::get(L, IARG, args);
                int n = CppInvokeMethod<FN, R, typename CppArg<P\>::HolderType...>::push(L, fn, args);
                return n + CppArgTupleOutput<P...>::push(L, args);
             } catch (std::exception& e) {
    
                //!!!  when error accur, this catch code didnot run. !!!
                return luaL_error(L, e.what());
    
             }
         }
     }
    

    e.g: my callback is:

    function callback()
         error(1)
    end
    

    ps:

    when I called this same callback in main thread ,the catch code worked.

    Any idea why this happen? I am not familiar with these mutithread things between lua and C++,any detailed description is really appreciated !

    opened by dogeFu 0
  • How to start with the wrapper?

    How to start with the wrapper?

    Hello,

    for the last 2 days I've been trying to figure out how I can use custom C++ library from within Lua and stumbled upon this wrapper, which looks like it does what I need it to do.

    So I have this basic library with 1 class:

    #pragma once
    
    #include <string>
    using namespace std;
    
    class myClass
    {
    private:
    	int num;
    	string str;
    
    public:
    	myClass(int, string);
    
    	void setInt(int);
    	void setString(string);
    
    	int getInt() { return num; }
    	string getString() { return str; }
    };
    
    #include "Header.h"
    
    myClass::myClass(int i, string str) : num(i), str(str)
    { }
    
    void myClass::setInt(int i)
    { this->num = i; }
    
    void myClass::setString(string str)
    { this->str = str; }
    

    I obviously use it in C++ like this

    #include <iostream>
    #include <Header.h>
    using namespace std;
    
    int main()
    {
    	myClass mc(3, "hello");
    	cout << mc.getInt() << endl << mc.getString() << endl;
    
    	mc.setInt(5);
    	mc.setString("world");
    	cout << mc.getInt() << endl << mc.getString() << endl;
    
    	return 0;
    }
    

    is there any way (and if so, how?) to use it from within Lua in a similar way? like this:

    local cl = myClass(3, "hello");
    print(cl.getInt(), cl.getString());
    
    cl.setInt(5);
    cl.setString("world");
    print(cl.getInt(), cl.getString());
    

    Does the library has to be compiled as a static, or dynamic library? Do I only include the wrapper and Link the class as shown in the readme? How does the Lua find the linked library then? With C++ I have to link it while compiling, providing a path to the lib. How does this work with Lua?

    I'm sorry if this is stupid question, but I've used Lua only for game scripting so far, never really used it with binding to any language, therefore I have no idea how to work with the wrapper provided. Any help is highly appreciated!

    opened by 1337SEnergy 7
  • Bunch of warnings with /W4 in Visual C++

    Bunch of warnings with /W4 in Visual C++

    Hi!

    I'm compiling my project with high warning level (/W4) on Visual C++ and getting bunch of warning for unused arguments of methods inside of guts of your library.

    warning C4100: 'args': unreferenced formal parameter external\luaintf\impl\cppinvoke.h(203): note: while compiling class template member function 'SpritePtr LuaIntf::CppDispatchClassMethod<T,false,FN,R,std::tuple<>,0>::call(T *,const FN &,TUPLE &)'

    Can you do something with that? My internal perfectionist suffers from these warnings :)

    PS. Thank you for your excellent library.

    opened by mrDIMAS 0
  • LUA_FN issues

    LUA_FN issues

    未定义标识符 (unable to identify identifier) .addFunction("setTileGID", LUA_FN(void, setTileGID, uint32_t, Vec2))

    I wanna just register a overload function, the error showed up

    opened by wjcking 0
Owner
Steve K. Chiu
Steve K. Chiu
libmagic binding for lua.

lua-libmagic libmagic binding for lua. see man libmagic for more details. Dependencies libmagic: https://github.com/file/file Installation luarocks in

Masatoshi Fukunaga 2 Jan 14, 2022
Advanced version of lutok C++/Lua binding

Lutok2 C++/Lua binding helper for Lua 5.1 and LuaJIT 2.x+. Dependencies To use Lutok2 successfully you'll need: A standards-compliant C++11 complier L

Mário Kašuba 9 Jul 19, 2022
C++ binding to Lua

Kaguya C++ binding to Lua Licensed under Boost Software License Requirements Lua 5.1 to 5.3 (recommended: 5.3) C++03 compiler with boost library or C+

null 317 Jan 4, 2023
A Sol-inspired minimalist Lua binding for Zig.

zoltan A Sol-inspired minimalist Lua binding for Zig. Features Supports Zig 0.9.0 Lua tables table creation from Zig get/set/create methods possible k

null 79 Dec 4, 2022
lua binding for Software implementation in C of the FIPS 198 Keyed-Hash Message Authentication Code HMAC

lua-hmac Compute the SHA-224, SHA-256, SHA-384, and SHA-512 message digests and the Hash-based Message Authentication Code (HMAC). this module is Lua

Masatoshi Fukunaga 3 Dec 3, 2022
rlua -- High level bindings between Rust and Lua

rlua -- High level bindings between Rust and Lua

Amethyst Foundation 1.4k Jan 2, 2023
The Lua development repository, as seen by the Lua team. Mirrored irregularly

The Lua development repository, as seen by the Lua team. Mirrored irregularly

Lua 6.4k Jan 5, 2023
A dependency free, embeddable debugger for Lua in a single file (.lua or .c)

debugger.lua A simple, embedabble debugger for Lua 5.x, and LuaJIT 2.x. debugger.lua is a simple, single file, pure Lua debugger that is easy to integ

Scott Lembcke 600 Dec 31, 2022
Signed - a 3D modeling and construction language based on Lua and SDFs. Signed will be available for macOS and iOS and is heavily optimized for Metal.

Signed - A 3D modeling language Abstract Signed is a Lua based 3D modeling language, it provides a unique way to create high quality 3D content for yo

Markus Moenig 90 Nov 21, 2022
⚔️ A tool for cross compiling shaders. Convert between GLSL, HLSL, Metal Shader Language, or older versions of GLSL.

A cross compiler for shader languages. Convert between SPIR-V, GLSL / GLSL ES, HLSL, Metal Shader Language, or older versions of a given language. Cross Shader wraps glslang and SPIRV-Cross, exposing a simpler interface to transpile shaders.

Alain Galvan 207 Dec 30, 2022
The Lua programming language with CMake based build

README for Lua 5.1 See INSTALL for installation instructions. See HISTORY for a summary of changes since the last released version. What is Lua? Lua i

The Lua Language distribution [Archived] 1.4k Dec 30, 2022
C# bindings for Sokol using Sokol's binding generator

C# bindings for Sokol using Sokol's binding generator

Michal Strehovský 29 Jan 4, 2023
CRC32 slice-by-16 implementation in JS with an optional native binding to speed it up even futher

CRC32 slice-by-16 implementation in JS with an optional native binding to speed it up even futher. When used with Webpack/Browserify etc, it bundles the JS version.

Mathias Buus 8 Aug 4, 2021
A C++ binding for the OpenGL API, generated using the gl.xml specification.

glbinding is a cross-platform C++ binding for the OpenGL API. glbinding leverages C++11 features like enum classes, lambdas, and variadic templates, i

CG Internals 758 Dec 13, 2022
Go binding to ImageMagick's MagickWand C API

Go Imagick Go Imagick is a Go bind to ImageMagick's MagickWand C API. We support two compatibility branches: master (tag v2.x.x): 6.9.1-7 <= ImageMagi

Go Graphics community 1.5k Dec 29, 2022
This is a simple version of Apex-Legends-SDK since so many people having struggles with python binding

This is a simple version of Apex-Legends-SDK since so many people having struggles with python binding

skidword64 43 Nov 30, 2022
A run-time C++ library for working with units of measurement and conversions between them and with string representations of units and measurements

Units What's new Some of the CMake target names have changed in the latest release, please update builds appropriately Documentation A library that pr

Lawrence Livermore National Laboratory 112 Dec 14, 2022
This repository is used for automatic calibration between high resolution LiDAR and camera in targetless scenes.

livox_camera_calib livox_camera_calib is a robust, high accuracy extrinsic calibration tool between high resolution LiDAR (e.g. Livox) and camera in t

HKU-Mars-Lab 491 Dec 29, 2022