Giter VIP home page Giter VIP logo

kaguya's Introduction

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++11 compiler(gcc 4.8+,clang 3.4+,MSVC2015) without boost.

Tested Environment

test

Introduction

Kaguya is a Lua binding library for C++

  • header-file only
  • seamless access to lua elements

Usage

add "kaguya/include" directory to "header search path" of your project.

Or generate single header file and add it to your project.

cd  utils
python generate_one_header.py > ../kaguya.hpp

Create Lua context

#include "kaguya/kaguya.hpp"
int main()
{
  kaguya::State state;
  state.dofile("/path/to/script.lua");
}

Or use an existing lua state

extern "C" int luaopen_modulename(lua_State *L)
{
	kaguya::State state(l);
	kaguya::LuaTable module = state.newTable();
	module["function"] = kaguya::function(somefunction);
	return module.push();//number of return lib
}

Running Lua code

kaguya::State state;
state("a = 'test'");//load and execute from string
state.dofile("path/to/luascript.lua");//load and execute from file

kaguya::LuaFunction f1 = state.loadfile("path/to/luascript.lua");//load file without executing it
f1();//execute
kaguya::LuaFunction f2 = state.loadstring("a = 'test'");//load string without executing it
f2();//execute

Accessing values

kaguya::State state;
state("a = \"test\"");
std::string a_value = state["a"];
assert(a_value == "test");

state["tbl"] = kaguya::NewTable();//tbl ={};
state["tbl"]["value"] = 1;//tbl.value = 1 in lua

state["tbl"] = kaguya::TableData{ 23,"test",{"key","value"}}; //using initializer list(C++11)
state("assert(tbl[1] == 23)");
state("assert(tbl[2] == 'test')");
state("assert(tbl['key'] == 'value')");

Retain Lua value from C++

LuaRef type is like a Variant type. You can use it for holding a Lua-value in native code.

kaguya::State state;
state["a"] = "test";
kaguya::LuaRef a = state["a"];
assert(a == "test");

state["tbl"] = kaguya::NewTable();//tbl ={};
kaguya::LuaTable tbl = state["tbl"];//holding Lua Table
tbl["value"] = 1;//tbl.value = 1 in lua
state("assert(tbl.value == 1)");

Call lua function

int ret = state["math"]["abs"](-32);//call math.abs of Lua function
assert(ret == 32);
//or
auto ret = state["math"]["abs"].call<int>(-32);//call math.abs of Lua function
assert(ret == 32);

Multiple Results from Lua

state("multresfun =function() return 1,2,4 end");//registering multiple results function
int a, b, c;
kaguya::tie(a, b, c) = state["multresfun"]();
assert(a == 1 && b == 2 && c == 4 );
//or
std::tuple<int,int,int> result_tuple = state["multresfun"].call<std::tuple<int,int,int>>();
TEST_EQUAL(std::get<0>(result_tuple), 1);
TEST_EQUAL(std::get<1>(result_tuple), 2);
TEST_EQUAL(std::get<2>(result_tuple), 4);

Registering Classes

struct ABC
{
	ABC():v_(0) {}
	ABC(int value) :v_(value) {}
	int value()const { return v_; }
	void setValue(int v) { v_ = v; }
	void overload1() {std::cout << "call overload1"<<std::endl; }
	void overload2(int) {std::cout << "call overload2"<<std::endl; }
private:
	int v_;
};
state["ABC"].setClass(kaguya::UserdataMetatable<ABC>()
	.setConstructors<ABC(),ABC(int)>()
	.addFunction("get_value", &ABC::value)
	.addFunction("set_value", &ABC::setValue)
	.addOverloadedFunctions("overload", &ABC::overload1, &ABC::overload2)
	.addStaticFunction("nonmemberfun", [](ABC* self,int){return 1;})//c++11 lambda function
	);
--Lua
abc = ABC.new()--call default constructor
assert(0 == abc:get_value())
abc = ABC.new(42)--call (int) constructor
assert(42 == abc:get_value())
abc:set_value(30)
assert(30 == abc:get_value())
abc:overload() -- call overload1
abc:overload(1) --call overload2

Registering inheritance

struct Base
{
	int a;
};
struct Base2
{
	int a2;
};
struct Derived:Base
{
	int b;
};
struct MultipleInheritance:Base,Base2
{
	int b;
};
int base_function(Base* b) {
	b->a = 1;
	return b->a;
}
//
kaguya::State state;
state["Base"].setClass(kaguya::UserdataMetatable<Base>()
	.addFunction("a", &Base::a)
	);
state["Derived"].setClass(kaguya::UserdataMetatable<Derived, Base>()
	.addFunction("b", &Derived::b)
	);

//can use kaguya::MultipleBase<BaseTypes...> for multiple inheritance class
state["MultipleInheritance"].setClass(kaguya::UserdataMetatable<MultipleInheritance, kaguya::MultipleBase<Base, Base2> >()
	.addFunction("b", &MultipleInheritance::b)
	);

state["base_function"] = &base_function;
Derived derived;
state["base_function"](&derived);//Base arguments function
state("assert(1 == derived:a())");//accessing Base member

Registering object instance

state["ABC"].setClass(kaguya::UserdataMetatable<ABC>()
	.setConstructors<ABC(),ABC(int)>()
	.addFunction("get_value", &ABC::value)
	.addFunction("set_value", &ABC::setValue)
	);
ABC abc(43);
//register object pointer
state["abc"] = &abc;
state("assert(43 == abc:get_value())");
//or copy instance
state["copy_abc"] = abc;
state("assert(43 == copy_abc:get_value())");
//or registering shared instance
state["shared_abc"] = kaguya::standard::shared_ptr<ABC>(new ABC(43));//kaguya::standard::shared_ptr is std::shared_ptr or boost::shared_ptr.
state("assert(43 == shared_abc:get_value())");

Object lifetime

state["Base"].setClass(kaguya::UserdataMetatable<Base>());
Base base;

//registering pointer. lifetime is same base
state["b"] = &base;
state["b"] = kaguya::standard::ref(base);

//registering copy instance. copied instance lifetime is handling in lua vm(garbage collection).
state["b"] = base;
state["b"] = static_cast<Base const&>(base);

Registering function

void c_free_standing_function(int v){std::cout <<"c_free_standing_function called:" << v << std::endl;}
state["fun"] = &c_free_standing_function;
state["fun"](54); //c_free_standing_function called:54
state("fun(22)");//c_free_standing_function called:22

state["lambda"] = kaguya::function([]{std::cout << "lambda called" << std::endl;});//C++11 lambda
state("lambda()");//lambda called


state["overload"] = kaguya::overload(
	[](int) {std::cout << "int version" << std::endl; },
	[](const std::string&) {std::cout << "string version" << std::endl; },
	[]() {std::cout << "no arg version" << std::endl; }
);
state("overload()");//no args version
state("overload(2)");//int version
state("overload('2')");//string version

Registering function with default arguments

//free function
int defargfn(int a = 3, int b = 2, int c = 1)
{
	return a*b*c;
}

KAGUYA_FUNCTION_OVERLOADS(defargfn_wrapper, defargfn,0,3)
state["defarg"] = kaguya::function(defargfn_wrapper());
state.dostring("assert(defarg() == 6)");
state.dostring("assert(defarg(6) == 12)");
state.dostring("assert(defarg(6,5) == 30)");
state.dostring("assert(defarg(2,2,2) == 8)");

//member function
struct TestClass
{
	int defargfn(int a = 3, int b = 2, int c = 1)
	{
		return a*b*c;
	}
};
KAGUYA_MEMBER_FUNCTION_OVERLOADS(defargfn_wrapper, TestClass, defargfn, 0, 3)
state["TestClass"].setClass(kaguya::UserdataMetatable<TestClass>()
	.setConstructors<TestClass()>()
	.addFunction("defarg", defargfn_wrapper())
);
state.dostring("test = TestClass.new()");
state.dostring("assert(test:defargfn() == 6)");
state.dostring("assert(test:defargfn(6) == 12)");
state.dostring("assert(test:defargfn(6,5) == 30)");
state.dostring("assert(test:defargfn(2,2,2) == 8)");

Variadic arguments function

state["va_fun"] = kaguya::function([](kaguya::VariadicArgType args) {for (auto v : args) { std::cout << v.get<std::string>() << ","; }std::cout << std::endl; });//C++11 lambda
state("va_fun(3,4,6,\"text\",6,444)");//3,4,6,text,6,444,

Multiple Results to Lua

If return type of function is tuple, it returns multiple results to Lua

state["multireturn"] = kaguya::function([]() { return std::tuple<int, int>(32, 34); });
state("print(multireturn())");//32    34

Nil values

Luas nil converts to nullptr or 0 for pointer types, can be checked for with isNilref() and is different than the integer 0. When you want to pass nil to lua either pass nullptr/(void*)0 or kaguya::NilValue.

state["value"] = kaguya::NilValue();
//or state["value"] = nullptr;
//or state["value"] = (void*) 0;
state("assert(value == nil)");
state("assert(value ~= 0)");
assert(state["value"].isNilref());
assert(state["value"] == kaguya::NilValue());
assert(state["value"] == nullptr);

state["value"] = 0;
state("assert(value ~= nil)");
state("assert(value == 0)");
assert(!state["value"].isNilref());
assert(state["value"] != kaguya::NilValue());
assert(state["value"] != nullptr);

Coroutine

kaguya::LuaThread cor = state.newThread();
state("corfun = function(arg)"
"coroutine.yield(arg) "
"coroutine.yield(arg*2) "
"coroutine.yield(arg*3) "
"return arg*4 "
" end");//define corouine function

kaguya::LuaFunction corfun = state["corfun"];//lua function get

//exec coroutine with function and argument
std::cout << int(cor(corfun, 3)) << std::endl;//3
std::cout << int(cor()) << std::endl;//6
//resume template argument is result type
std::cout << cor.resume<int>() << std::endl;//9
std::cout << int(cor()) << std::endl;//12

kaguya::LuaThread cor2 = state.newThread();
//3,6,9,12,
while(!cor2.isThreadDead())
{
	std::cout << cor2.resume<int>(corfun, 3) << ",";
}

Automatic type conversion

std::map and std::vector will be converted to a lua-table by default

kaguya::State s;
std::vector<int> vect = { 2,4,6,1 };
s["vect"] = vect;
s("print(type(vect))");// table
s("for i,v in ipairs(vect) do print(v) end");

output:

table
1 2
2 4
3 6
4 1
kaguya::State s;
std::map<std::string, int> map = { { "apple",3 },{ "dog",5 },{"cat",124},{ "catfood",644 } };
s["map"] = map;
s("print(type(map))");// table
s("for i,v in pairs(map) do print(i,v) end");

output:

table
catfood 644
dog     5
cat     124
apple   3

Type conversion customization

If you want to customize the type conversion from/to lua, specialize kaguya::lua_type_traits

example: (this is already implemented for std::string per default)

template<>  struct lua_type_traits<std::string> {
	typedef std::string get_type;
	typedef const std::string& push_type;

	static bool strictCheckType(lua_State* l, int index)
	{
		return lua_type(l, index) == LUA_TSTRING;
	}
	static bool checkType(lua_State* l, int index)
	{
		return lua_isstring(l, index) != 0;
	}
	static get_type get(lua_State* l, int index)
	{
		size_t size = 0;
		const char* buffer = lua_tolstring(l, index, &size);
		return std::string(buffer, size);
	}
	static int push(lua_State* l, push_type s)
	{
		lua_pushlstring(l, s.c_str(), s.size());
		return 1;
	}
};

Handling Errors

Encountered lua errors will be written to the console by default, but you can change this:

void HandleError(int errCode, const char * szError)
{  //customize your error handling, eg. write to file...
}
kaguya::State l;
l.setErrorHandler(HandleError);
l.dofile("./scripts/custom.lua"); // eg. accessing a non-existing file will invoke HandleError above

run test

mkdir build
cd build
cmake ..
make
ctest

If you don't want to use the default (system) library, add these 3 options to the cmake command

cmake -DLUA_INCLUDE_DIRS=path/to/lua/header/dir -DLUA_LIBRARY_DIRS=/abspath/to/lua/library/dir -DLUA_LIBRARIES=lualibname

kaguya's People

Contributors

aster2013 avatar flamefire avatar fliar avatar luzpaz avatar sahnvour avatar satoren avatar zmcj21 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kaguya's Issues

Detect a runtime error in a UserdataMetatable function call

I would like to detect runtime errors when I call a lua function. I tried this, (similar to https://github.com/satoren/kaguya/blob/master/test/test_06_state.cpp ) but no exception is thrown.

luaState.setErrorHandler(kaguya::ErrorHandler::throwDefaultError);
kaguya::LuaFunction way_function = luaState["way_function"];
kaguya::LuaRef ret = way_function(&sharedData.osmObject);

I have a deliberate error in the lua code which I would expect to say variable not defined:

function way_function(way)
	local highway = way:Find("highway")
	local waterway = way:Find("waterway")
	if highway~="" then
		way:Layer("transportation", false)
		way:Attribute("class", highway)
	end
	if waterway~="" then
		way:Layer("waterway", false)
		way:Attribute("class", waterway)
	end
	if building~="" then
		way:Layer("building", true)
	end
end

Any ideas?

how to bind the function from lua?

tbProject["BindNetStateChangeMsg"] = kaguya::function([](const std::function<void(int)>& func){
	g_NetStateChangeFunc = func;
});

if use this way, it will be error!

Template specialisation using return-type

I created the following class in C++ :

class BaseAttribute
{
    private:
    std::string data;
    public:
    BaseAttribute(std::string data);
    template <typename T> T get();
    template <> inline int get() {
            return std::stoi(data);
    }
    template <> inline double get() {
        return std::stod(data);
    }
    template <> inline bool get() {
        return (data == "True") ? true : false;
    }
    template <> inline std::string get() {
        return data;
        }
}

I used the following code to bind this class in Lua :

(*lua)["BaseAttribute"].setClass(kaguya::ClassMetatable<Data::BaseAttribute>()
    .addConstructor<std::string, std::string, std::string>()
    .addMember("get", static_cast<int(Data::BaseAttribute::*)()>(&Data::BaseAttribute::get))
    .addMember("get", static_cast<double(Data::BaseAttribute::*)()>(&Data::BaseAttribute::get))
    .addMember("get", static_cast<bool(Data::BaseAttribute::*)()>(&Data::BaseAttribute::get))
    .addMember("get", static_cast<std::string(Data::BaseAttribute::*)()>(&Data::BaseAttribute::get))
);

"lua" variable is a kaguya::State*

Now when I use this in Lua :

local myattr = BaseAttribute.new("54.6");
print(myattr.get());

It'll only use the version. Is there a way to specify the template implementation I want to use in Lua?
Like with a myattr.get<double>();

Error adding metatable to member std::vector

Example test code:

using TestVect  = vector<int>;

int getItem(TestVect &v, int i) { return v.at(i); }

struct TestStrcutWithVect {
    TestVect vect;
};

TEST(Add_metatable_to_member_vector) {
    kaguya::State s;
    s["Vect"].setClass(kaguya::ClassMetatable<TestVect>().addStaticMember("getItem", getItem));
    s["TestStrcutWithVect"].setClass(kaguya::ClassMetatable<TestStrcutWithVect>().addProperty(
        "vect", &TestStrcutWithVect::vect));

    TestStrcutWithVect test;
    test.vect.push_back(123);
    s["test"] = &test;
    s("i = test.vect:getItem(0)");

    EXPECT_THAT(s["i"], Eq(123));
}

Gives: [string "i = test.vect:getItem(0)"]:1: attempt to call method 'getItem' (a nil value) unknown file: error: C++ exception with description "nilis not __int64" thrown in the test body.

Following test also fails:

TEST(Pass_member_vector_to_free_function) {
    kaguya::State s;
   s["Vect"].setClass(kaguya::ClassMetatable<TestVect>());
    s["TestStrcutWithVect"].setClass(kaguya::ClassMetatable<TestStrcutWithVect>().addProperty(
        "vect", &TestStrcutWithVect::vect));
    s["getItem"] = getItem;

    TestStrcutWithVect test;
    test.vect.push_back(123);
    s["test"] = &test;
    s("i = getItem(test.vect, 0)");

    EXPECT_THAT(s["i"], Eq(123));
}

With message argument not matching:table,number candidated class std::vector<int,class std::allocator<int> >,int unknown file: error: C++ exception with description "nilis not __int64" thrown in the test body.

Same story with using TestVect = string;. But if I replace using TestVect = vector<int>; to struct TestVect : vector<int>{}; or using TestVect = array<int, 10>; all tests pass.

If vector isn't a member then metatable is added and followig test passes:

using TestVect  = vector<int>;

TEST(Add_metatable_to_vector) {
    kaguya::State s;
    s["Vect"].setClass(kaguya::ClassMetatable<TestVect>().addStaticMember("getItem", getItem));

    TestVect vect;
    vect.push_back(123);
    s["vect"] = &vect;
    s("i = vect:getItem(0)");

    EXPECT_THAT(s["i"], Eq(123));
}

Support default parameters

Is it somehow possible, to support default parameters without writing extra functions?
Like:

class Foo{
  void func(int param = 42){ std::cout << param; }
};

Currently those functions can be registered, but if the param is notpassed by Lua , it will be 0 instead of 42

how to use in multi so or dll

a.so export class A
lua require b.so have interface param 1 is A
how to get a point if use kaguya::get_pointer(L, nIndex, kaguya::types::typetag());
the metatable_name_key is not same so it will fail

New feature request.

Hi, Satoren, your kaguya is greater, now the Urho3D Lua API with kaguya is finished. thanks.

These is a class call StringHash in Urho3D, I have bind it to Lua as a user data. When I call some functions with StringHash arguments, I can do like this:

// C++
void SomeFunction(StringHash hash);

// Lua
SomeFunction(StringHash('This is a string'))

But sometimes I want to call like this:

// Lua
SomeFunction('This is a string')

Now I can not write a lua_type_traits<StringHash> specialization class, because kaguya forbid it.

Access subtables directly

Is there another way to access a subtable ?

I know you can do :

luavm["a"]["b"]["c"] = 10;

But is it possible to do something like :

std::string path = "a.b.c";
luavm.access(path);

?

function object cannot bind right?

Visua Studio 2015, Update 3, latest Kaguya

struct func_obj {
     int x;
     int operator()( int i ) { x = i; return i; }
};

int main (int argc, char*[] argv ) {
     kaguya::State state;
     // Fails Line 408, native_function.hpp
     // is_callable KAGUYA_STATIC_ASSERT assertion
     //state["f"] = kaguya::function( func_obj() );

     // works fine
     state["f"] = kaguya::function( [](int i){ func_obj o; return o(i); } );

     // also fine
     func_obj fo; 
     state["f"] = kaguya::function( [&](int i){ return fo(i); } );
}

Is something wrong with is_callable trait?

Fail to execute simple Lua code with kaguya

Hi,

I've tried to compile and run some simple code using kaguya.
I compiled the same code twice, first with my system binary and
libraries (64 bits archlinux up to date) and then with a toolchain
for 32 bits x86.

In both cases the compilation is successful, my problem is when I run
the version compiled with the toolchain I get an error : "attempt to index a nil value"
(which I don't get with the version compiled directly with my system).

I tried to replicate the code logic using only the lua C api and then compiled
it again with my system binary and libraries then with the toolchain. In this
case both binaries works as expected.

My system uses g++ 6.2.1 while the toolchain is using g++ 4.9.2 (both meeting kaguya
requirements). I'm compiling with the std=c++11 option.
My system uses lua 5.3.3 while the toolchain uses 5.2.2

Here is the code which get me the "attempt to index a nil value" error :

     #include "kaguya.hpp"
    
     kaguya::State luaState;
 
     auto scriptAdding2CppVariables = R"(
         return valA + valB
     )";
 
     // Loading script in Lua context.
     kaguya::LuaFunction luaFunc = luaState.loadstring(scriptAdding2CppVariables);
 
     auto a = 1;
     auto b = 2;
 
     // Exporting variables to Lua context (under the same they're used in the previous script).
     luaState["valA"] = a;
     luaState["valB"] = b;
 
     if (luaFunc() == a + b)
     {
         std::cout << "SUCCESS" << std::endl;
     }
     else
     {
         std::cout << "FAILED" << std::endl;
     }

And here is the equivalent with the C api which does not trigger any error.

     #ifdef __cplusplus
     #include <lua.hpp>
     #else
     # include <lua.h>
     # include <lualib.h>
     # include <lauxlib.h>
     #endif

     lua_State* state;

    auto scriptAdding2CppVariables = R"(
        function add (varA, varB)
            return varA + varB
        end
     )";

     /* initialize Lua */
     state = luaL_newstate();

     luaL_dostring(state, scriptAdding2CppVariables);
     lua_getglobal(state, "add");

     auto varA = 1;
     lua_pushnumber(state, varA);

     auto varB = 2;
     lua_pushnumber(state, varB);

     lua_call(state, 2, 1);

     /* call the add function */
     auto sum = (int)lua_tointeger(state, -1);
     lua_pop(state, 1);

     if(sum == varA + varB)
     {
           std::cout << "SUCCESS" << std::endl;
     }
     else
     {
          std::cout << "FAILED" << std::endl;
     }

     /* cleanup Lua */
     lua_close(state);

I've tried modifying scriptAdding2CppVariables (in the code version using kaguaya) to
"return 1 + 2" and removed the statements to export the variables a and b into the lua
context but I still get the same error. It leaves us with only 3 statements using lua.
Commenting the call to luaFunc() does stop the error from occurring.

If anyone could tell me why I got this behavior I'd be grateful.

Thanks

Kaguya in dump api mode? is it possible?

Hi, satoren:
When all of the c++ functions and classes register to Lua, is it possible run in dump mode, in this mode, it will output a API documentation. for example:

void TestFunction(int, int);
lua["Test"] = function(TestFunction);

in dump mode, it will output a line:

void Test(int, int);

as documentation.

'index' was not declared in this scope

I'm getting the following compiler error when trying to use the header-only lib:

kaguya/detail/lua_table_def.hpp: In member function 'typename kaguya::lua_type_traits<T>::get_type kaguya::LuaTableOrUserDataImpl<Derived>::getField(const KEY&) const':
kaguya/detail/lua_table_def.hpp:111:39: error: 'index' was not declared in this scope
    lua_type_traits<KEY>::push_(state, index);
                                       ^

And indeed when I look at the reported line, there is a variable index of which I can't find a declaration or definition. Should this be key instead?

Throw error on invalid return values

I have code like this:

std::vector<unsigned> GetValues()
{
    kaguya::LuaRef getValues= lua["getValues"];
    if(getValues.type() == LUA_TFUNCTION)
        return getValues();
    return std::vector<unsigned>();
}

And I want this code to throw an error or something so I can detect when the lua function returns invalid types. E.g. in this case the lua function returned a table of strings instead of numbers.

Problem is: I just get the empty vector and have no way to tell if the vector was actually empty or just had some wrong elements.

Compile failure for const-member functions

The compilation (with an older apple-crosscompiler) fails when instantiating int kaguya::nativefunction::FunctorType::FunInvoker<F>::invoke(lua_State*) [with F = Nation (LuaPlayerBase::*)()const] as this results in instantiation of kaguya::traits::is_object<Nation ()()const> which ultimately fails with 'const' qualifiers added to function type 'Team ()()const' [...] In instantiation of 'kaguya::traits::remove_const<Nation ()()const>'

I tried to change the traits to:

        using standard::remove_const;
        using standard::remove_volatile;
        using standard::remove_cv;
        using standard::is_pointer;

But that fails too: pointer to function type 'int () const' cannot have 'const' qualifier for is_pointer from kaguya::traits::is_object<int () const> from 'call' [with MemType = int () const, T = kaguya_test_util::TestClass]

You probably can replace all this by is_member_object_pointer http://www.boost.org/doc/libs/1_58_0/libs/type_traits/doc/html/boost_typetraits/reference/is_member_object_pointer.html

Error while passing base class smart pointer to function

    s["TestBase"].setClass(kaguya::ClassMetatable<TestBase>());
    s["TestDer"].setClass(kaguya::ClassMetatable<TestDer, TestBase>());

    s["func1"] = kaguya::function([&](std::shared_ptr<TestBase> b) { ... });
    s["d"] = std::make_shared<TestDer>();
    s("func1(d)");

Shows error argument not matching.

Is it possible setmetatable by class name?

Current these is only a function to set metatable for class.

class_userdata::setmetatable<ClassType>(lua_state* state);

Is it possible add another function so can set metatable by class name?

class_userdata::setmetatable(lua_state* state, const char* class_name);

How to handle Lua function in c++

Thanks for the great Lua binding !!

But I meet a problem:

class prototype

class Node : public Ref
{
public:
    void scheduleOnce(const std::function<void(float)>& callback, float delay, const std::string &key);
}

register code:

cc["Node"].setClass(kaguya::ClassMetatable<Node, Ref>()
                    .addMemberFunction("scheduleOnce", static_cast<void(Node::*)(const std::function<void(float)>& callback, float delay, const std::string &key)>(&Node::scheduleOnce))
                    );

Lua test code:

node:scheduleOnce(function(dt) print ("scheduleOnce") end, 1.0, "test")

error:

__luadraw__ error: maybe...Argument mismatch:PN7cocos2d6SpriteE,function,number,string   candidate is:
        PN7cocos2d4NodeE,NSt3__18functionIFvfEEE,f,NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE,

Am I missing something?

Passing classes by ref to function is broken

Like

s["to"] = kaguya::function([&](MyStruct & p) {  });

'initializing': cannot convert from 'const 'anonymous-namespace'::MyStruct ' to ''anonymous-namespace'::MyStruct &' Tests C:\cpplibs\lua\inst\include\kaguya\gen\native_function.inl 478

Nil support for smart pointers

Maybe add nil support to smart pointers? To be able write something like:

boost::shared_ptr<Test> pp;
s["foo"] = kaguya::function([&](boost::shared_ptr<Test> p) { pp=p;});
s("foo(nil)");
ASSERT(pp == nullptr);

I changed behavior for boost::shared_ptr using trait like this:

namespace kaguya {
template <typename T>
struct lua_type_traits<boost::shared_ptr<T>> {
    typedef const boost::shared_ptr<T> &push_type;
    typedef boost::shared_ptr<T> get_type;

    static bool checkType(lua_State *l, int index) {
        return object_wrapper(l, index, metatableName<get_type>()) != nullptr ||
               lua_type(l, index) == LUA_TNIL;
    }

    static bool strictCheckType(lua_State *l, int index) {
        return object_wrapper(l, index, metatableName<get_type>()) != nullptr;
    }

    static get_type get(lua_State *l, int index) {
        if (lua_type(l, index) == LUA_TNIL) {
            return nullptr;
        }
        const get_type *pointer = get_const_pointer(l, index, types::typetag<get_type>());
        if (!pointer) {
            throw LuaTypeMismatch("type mismatch!!");
        }
        return *pointer;
    }

    static int push(lua_State *l, push_type v) {
        typedef ObjectSmartPointerWrapper<boost::shared_ptr<T>> wrapper_type;
        void *storage = lua_newuserdata(l, sizeof(wrapper_type));
        new (storage) wrapper_type(v);
        class_userdata::setmetatable<T>(l);
        return 1;
    }
};
}

Is it correct implementation?

Write acess to substruct property

struct TestStructSub {
    float f_{};
};
struct TestStruct {
    TestStructSub s_;
};
...
add class kaguya::ClassMetatable<TestStructSub>()
                       .addProperty("f_", &TestStructSub::f_);
add class kaguya::ClassMetatable<TestStruct>()
        .addProperty("s_", &TestStruct::s_);
...
TestStruct ts;
s["ts"] = &ts;
s("ts.s_.f_ = 1");
ASSERT(ts.s_.f_ == 1); // fails, ts.s_.f_ == 0

Build error on macOS Sierra

Hi,
Kaguya don't work on macOS

/include/kaguya/object.hpp:86:11: error: no viable conversion from returned value of type '__bit_iterator<std::__1::vector<bool, std::__1::allocator<bool> >, true>' to function return type 'const void *' return &object_; ^~~~~~~~ /Users/arthapz/Downloads/ObEngine-master/extlibs/include/kaguya/object.hpp:63:3: note: in instantiation of member function 'kaguya::ObjectWrapper<std::__1::__bit_const_reference<std::__1::vector<bool, std::__1::allocator<bool> > > >::cget' requested here ObjectWrapper(Args&&... args) : object_(std::forward<Args>(args)...) {} ^ /Users/arthapz/Downloads/ObEngine-master/extlibs/include/kaguya/object.hpp:732:17: note: in instantiation of function template specialization 'kaguya::ObjectWrapper<std::__1::__bit_const_reference<std::__1::vector<bool, std::__1::allocator<bool> > > >::ObjectWrapper<std::__1::__bit_const_reference<std::__1::vector<bool, std::__1::allocator<bool> > > >' requested here new(storage) wrapper_type(std::forward<T>(v)); ^ /Users/arthapz/Downloads/ObEngine-master/extlibs/include/kaguya/type.hpp:66:16: note: in instantiation of function template specialization 'kaguya::util::object_push<std::__1::__bit_const_reference<std::__1::vector<bool, std::__1::allocator<bool> > > >' requested here return util::object_push(l,std::forward<NCRT>(v)); ^ /Users/arthapz/Downloads/ObEngine-master/extlibs/include/kaguya/utility.hpp:200:64: note: in instantiation of member function 'kaguya::lua_type_traits<std::__1::__bit_const_reference<std::__1::vector<bool, std::__1::allocator<bool> > >, void>::push' requested here int c = lua_type_traits<typename traits::decay<Arg>::type>::push(l, std::forward<Arg>(arg)); ^ /Users/arthapz/Downloads/ObEngine-master/extlibs/include/kaguya/utility.hpp:233:22: note: in instantiation of function template specialization 'kaguya::util::push_args<std::__1::__bit_const_reference<std::__1::vector<bool, std::__1::allocator<bool> > >>' requested here int count = util::push_args(state, std::forward<T>(v)); ^ /Users/arthapz/Downloads/ObEngine-master/extlibs/include/kaguya/lua_ref_table.hpp:497:11: note: (skipping 1 context in backtrace; use -ftemplate-backtrace-limit=0 to see all) util::one_push(l, *it); ^ /Users/arthapz/Downloads/ObEngine-master/extlibs/include/kaguya/utility.hpp:200:64: note: in instantiation of member function 'kaguya::lua_type_traits<std::__1::vector<bool, std::__1::allocator<bool> >, void>::push' requested here int c = lua_type_traits<typename traits::decay<Arg>::type>::push(l, std::forward<Arg>(arg)); ^ /Users/arthapz/Downloads/ObEngine-master/extlibs/include/kaguya/utility.hpp:233:22: note: in instantiation of function template specialization 'kaguya::util::push_args<std::__1::vector<bool, std::__1::allocator<bool> > &>' requested here int count = util::push_args(state, std::forward<T>(v)); ^ /Users/arthapz/Downloads/ObEngine-master/extlibs/include/kaguya/detail/lua_table_def.hpp:37:11: note: in instantiation of function template specialization 'kaguya::util::one_push<std::__1::vector<bool, std::__1::allocator<bool> > &>' requested here util::one_push(state, std::forward<V>(value)); ^ /Users/arthapz/Downloads/ObEngine-master/extlibs/include/kaguya/lua_ref_table.hpp:58:25: note: in instantiation of function template specialization 'kaguya::detail::table_proxy::set<std::__1::vector<bool, std::__1::allocator<bool> > &, std::__1::basic_string<char> &>' requested here detail::table_proxy::set(state_, table_index_, key_, std::forward<T>(src)); ^ /Users/arthapz/Downloads/ObEngine-master/src/GameObject.cpp:296:51: note: in instantiation of function template specialization 'kaguya::TableKeyReferenceProxy<std::__1::basic_string<char> >::operator=<std::__1::vector<bool, std::__1::allocator<bool> > &>' requested here (*m_objectScript)["cpp_param"][it->first] = allParam->at(it->first).second.as<std::vector<bool>>();

Global function as member function.

When a global function with first argument is Object& or Object*, Can I treat is as a member function for usertype. e.g.

float Length(Vector2& vec)
{
    return sqrtf(vec.x * vec.x + vec.y * vec.y);
}

In Lua:

local vec = Vector2:new(10, 10)
local length = vec:Length()

Now I can register it as a static function for usertype.

Document lua_type_traits

Please add documentation to lua_type_traits. I'm not really sure what the members mean, especially weakTypeTest and typeTest (their difference). Probably rename them (I guess weakTypeTest means: isConvertible and typeTest means isType)

Especially confusing is the implementation of template<> struct lua_type_traits<void> of which I assume is taken when a void* is pushed or retrieved. Is it actually possible to do state["value"] = (void*) 0xDEAD; and retrieve it? If so, can you outline what happens/which traits are used?

Support for Template Constructor / Members / Functions

Do you plan to add support for templates when adding constructor, members or functions to a ClassMetatable ?
It works when you specify the type but could it be possible to leave the type empty and let Lua use any type ?

Performance while function call

In genrated code like

template<typename T1>
inline FunEvaluator LuaRef::operator()(T1 t1)
{
  value_type typ = type();
  if(typ != TYPE_FUNCTION && typ != TYPE_THREAD){except::typeMismatchError(state_, "is not function");return FunEvaluator(state_);}
  int argstart = lua_gettop(state_);
  lua_type_traits<T1>::push(state_,standard::forward<T1>(t1));
  int argnum = lua_gettop(state_) - argstart;
  std::vector<LuaRef> args;
  args.reserve(argnum);
  for (int i = 0; i < argnum; ++i)
    args.push_back(LuaRef(state_, StackTop()));
  std::reverse(args.begin(), args.end());
  return FunEvaluator(state_,*this,args);
}

change last line to return FunEvaluator(state_,*this, std::move(args));. It prevents vector copying and gives non-negligible perf increase while func calling. May be there are other places where such optimization can be made.

UserdataMetatable enable custom gc function.

Sometimes user want to custom __gc function for some userdata, for example:
I have a RefCounted object, when GC, it may call following function.

void RefCountedGC(RefCounted* obj)
{
    obj->ref --;
    if (obj->ref == 0)
        delete obj;
}

So it is better add a argument to UserdataMetatable enable user custom the gc funciton.

UserdataMetatable(bool registerGC= true)
{
    if (registerGC)
    {
        addStaticFunction("__gc", &class_userdata::destructor<ObjectWrapperBase>);
    }

Wrapper for Lua error throwing

As it is possible to call C++ functions from Lua and it is possible that this goes wrong, there should be a method to throw lua errors.

2 cases:

  1. Lua calls a function, but the argument is of the wrong type. I assume (correct me here) this wrapper will directly call the error handler here. So there is no way to catch this with Luas pcall
  2. The argument passed to the function is wrong (after the wrapper calls the C++ function) e.g. an index is out of bounds. For getters it might be reasonable to return nil but if e.g. this is a valid return value too or it is an execution function that you don't want to just 'do nothing' it is better to throw an error, that lua can catch and that will be passed to the error handler otherwise.

However I did not find a function for calling lua_error in the wrapper (besides of course executing state("error('Foo bar!!!')"))

Is there something for this? If not could it be added? What about the io.openFile like behaviour that it returns the file or nil and an error message? Can this be done easily with kaguya?

A few questions about functions

Hey I wanted to ask a few questions ...

When I try to call a lua function from my test lua script the application crashes, but the examples works
without any issue, same for getting a variable from my script.
int ret = state["math"]["abs"](-32); works
but

function getvalue(x)
return x
end

int ret = state["getvalue"](5);
doesn't :(

well ...

        state("multresfun =function() return 1,2,4 end");//registering multiple results function
    int a, b, c;
        kaguya::tie(a, b, c) = state["multresfun"]();

works, but he same called from lua file doesn't :(
So, do I do something wrong or forgot something ?!

My next question is how can I register a function in C++ and call it like

function mycppfunction
 bla bla bla
end

That's it so far.
Your lua binding is awesome :) I love it ! :D
Shiny and clean :D 👍

Thanks :)

Wrong object lifetime in move operators

I have a loop like this:

struct Foo{ int bar; Foo(int bar):bar(bar){}};

for(int i=0; i<5; i++){
    Foo foo = Foo(i);
    state["Foo" + std::to_string(i)] = foo;
}

If I then access the state["Foo2"] I get wrong results because kaguya stores a pointer to the local foo instance.

I traced it a bit (VS) and found, that it goes through the move assignment operator which finally stores a pointer to the value, instead of the value.

Changing the line to state["Foo" + std::to_string(i)] = static_cast<Foo const&>(foo); fixes this. However the examples suggest, that both should be the same.

Do I misunderstand this or is this a bug?

CMake usage

I'm having trouble to build a solution for MSVC using your CMakeLists.txt.

I'm not used to CMake, is there a way I can specify where to find the Lua includes (and lib if necessary), for example using LuaJIT ? It seems your script assumes that the user has a standard Lua installation.

registering function not working

Hey :)

I can't call the C++ function in Lua I just registered :(

void print_text(const char* msg)
{
    //printf("%s", msg.c_str());
    std::cout << "kaguya rocks ! " << msg << std::endl;
}

kaguya::State state;
kaguya::LoadLibs();
state.dofile("test.lua");

state["print_text"] = &print_text;

I always get "test.lua:7: attempt to call a nil value (global 'print_text')"

but calling state["print_text"]("meep"); works :P

In my lua script it's just print_text("hello world\n)

How does newLib work ?

Hey,
I'm currently trying to understand "newLib". I want to register a lua script from inside my C++ code for my main lua script I load with dofile. :)

An example would be great :)

Thank you :D

Is it possible add __call meta method?

for example:

class Vector3
{
public:
    Vector3(float x, float y, float z);
};

It can call

local vec = Vector3.new(1, 2, 3)

to create a vector3 object. but sometimes I want to create the user data with

local vec = Vector3(1, 2, 3)
```, 

Is possible add ```__call``` method for class?

Crash when incorrectly calling member function

I found a crash that can easily occur by a typo in the lua code:

std::map<unsigned, unsigned> myMap;

class FooClass{
public:
    void mapCallback(const std::map<unsigned, unsigned>& map)
    {
        myMap = map;
    }
};

void testMap(kaguya::State& state)
{
    state["testMap"].setClass(kaguya::ClassMetatable<FooClass>().addMemberFunction("testMap", &FooClass::mapCallback));
    state["foo"] = FooClass();
    // Wrong -> Crash
    state("myMap = {[1]=2, [3]=4, [5]=6}\n foo.testMap(myMap)");
    //Correct
    state("myMap = {[1]=2, [3]=4, [5]=6}\n foo:testMap(myMap)");
    TEST_EQUAL(myMap[1], 2);
    TEST_EQUAL(myMap[3], 4);
    TEST_EQUAL(myMap[5], 6);
}

The reason is that the . instead of : skips the this pointer and kaguya does not detect the invalid argument count and happily tries to get a map from index 2 at the stack which is not there. Such errors should be detected

Kaguya on Linux ?

Has your lib been tested on Linux :) ?
It works perfectly on Windows but I want to pass a string as parameter on Linux is says :

maybe...Argument mismatch:GameObject,string,string,string candidate is: GameObject,std::__cxx11::basic_string<char, std::char_traits<char> std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>n std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>n std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>n std::allocator<char> >,

But basically, a std::__cxx11::basic_string<char, std::char_traits<char> std::allocator<char> > IS a string.
Is it cause of Lua or Kaguya ?

Is there a way to use optional args with overloads ?

For exemple if we have :

class Vector2
{
...
};
class A
{
public:
    void move(int x, int y, bool moveNow = true);
    void move(Vector2 pos, moveNow = true);
};

When binding, how should I use KAGUYA_MEMBER_FUNCTION_OVERLOADS ?

Passing a LuaRef from a kaguya::State to another kaguya::State

How to pass a value from one state to another ? Using kaguya::LuaRef doesn't work, is there another way ?

kaguya::State luaP;
kaguya::State luaQ;
luaP("test = \"hello\"");
kaguya::LuaRef retainValue = luaP["test"];
luaQ["test"] = test;
luaQ("print(test)");

Doing it like that works but I want to store a kaguya::LuaRef or something like that

kaguya::State luaP;
kaguya::State luaQ;
luaP("test = \"hello\"");
luaQ["test"] = luaP["test"];
luaQ("print(test)");

how to return a table?

how can i return a table?
i do not want to create map in c/c++(it use frequency)

now code:(how to change to kaguya)
int nRows = dataTable.NumOfRows();
int nField = dataTable.NumOfFields();
lua_newtable(tolua_S);
int array_index = lua_gettop(tolua_S);
for (int i = 0; i < nRows; i++)
{
lua_newtable(tolua_S);
int result_index = lua_gettop(tolua_S);
for (int j = 0; j < nField; j++)
{
dataTable.SetRow(i);
lua_pushstring(tolua_S, dataTable.NameOfField(j));
lua_pushstring(tolua_S, dataTable.ValueOfField(j));
lua_settable(tolua_S, result_index);
}
lua_settop(tolua_S, result_index);
lua_rawseti(tolua_S, array_index, i + 1);
}

__index and __newindex can not work in kaguya.

e.g.

static const Variant& VariantMapGetVariant(const VariantMap& variantMap, const String& key)
{
    VariantMap::ConstIterator i = variantMap.Find(StringHash(key));
    if (i == variantMap.End())
        return Variant::EMPTY;

    return i->second_;
}

static void VariantMapSetVariant(VariantMap& variantMap, const String& key, const Variant& value)
{
    variantMap[StringHash(key)] = value;
}

static void RegisterVariantMap(kaguya::State& lua)
{
    using namespace kaguya;

    lua["KVariantMap"].setClass(UserdataMetatable<VariantMap>()
        .setConstructors<VariantMap()>()

        // Can not work in kaguya
        // .addStaticFunction("__index", &VariantMapGetVariant)
        // .addStaticFunction("__newindex", &VariantMapSetVariant)

        .addStaticFunction("Get", &VariantMapGetVariant)
        .addStaticFunction("Set", &VariantMapSetVariant)
        );
}

Enum classes are broken

lua_type_traits for enum should be like this, I think:

    template<typename T> struct lua_type_traits<T
        , typename traits::enable_if<traits::is_enum<T>::value>::type>
    {
        typedef typename traits::remove_const_reference<T>::type get_type;
        typedef typename traits::remove_const_reference<T>::type push_type;

        static bool strictCheckType(lua_State* l, int index)
        {
            return lua_type_traits<int>::strictCheckType(l, index);
        }
        static bool checkType(lua_State* l, int index)
        {
            return lua_type_traits<int>::checkType(l, index);
        }
        static get_type get(lua_State* l, int index)
        {
            return static_cast<get_type>(static_cast<int>(lua_type_traits<int>::get(l, index)));
        }
        static int push(lua_State* l, push_type s)
        {
            return lua_type_traits<int>::push(l, static_cast<int>(s));
        }
    };

Cannot init UserdataMetatable when class is noncopyable

struct NcTest {
    NcTest(NcTest const &) = delete;
    auto foo() -> NcTest & { return *this; }
};
auto const ncTestMt = kaguya::UserdataMetatable<NcTest>().addFunction("foo", &NcTest::foo);

Error C2280 'anonymous-namespace'::NcTest::NcTest(const anonymous-namespace'::NcTest &)': attempting to reference a deleted function

In visual studio 2015 upd 3

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.