Skip to content

Commit

Permalink
Support registering member variables with generated getters and setters.
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremyong committed Feb 10, 2014
1 parent 03d982b commit d6f0470
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 16 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,29 @@ are not supported at this time. The arguments to the `SetClass`
function are a list of member functions you wish to register (callable
from Lua). The format is [function name, function pointer, ...].
#### Registering Class Member Variables
For convenience, if you pass a pointer to a member instead of a member
function, Selene will automatically generate a setter and getter for
the member. The getter name is just the name of the member variable
you supply and the setter has "set_" prepended to that name.
```c++
// Define Bar as above
sel::State state;
state["Bar"].SetClass<Bar, int>("x", &Bar::x);
```

```lua
-- now we can do the following:
bar = Bar.new(4)

print(bar.x()) -- will print '4'

bar.set_x(-4)
print(bar.x()) -- will print '-4'
```

### Registering Object Instances

You can also register an explicit object which was instantiated from
Expand Down
51 changes: 35 additions & 16 deletions include/Class.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct BaseClass {

template <typename T,
typename A,
typename... Funs>
typename... Members>
class Class : public BaseClass {
private:
std::string _name;
Expand All @@ -33,8 +33,7 @@ class Class : public BaseClass {
std::vector<std::unique_ptr<T>> _instances;

std::string _get_metatable_name() {
//return _name + "_lib";
return _name;
return _name + "_lib";
}

void _register_ctor(lua_State *state) {
Expand All @@ -45,10 +44,30 @@ class Class : public BaseClass {
_dtor.reset(new Dtor<T>(state, _get_metatable_name()));
}

template <typename M>
void _register_member(lua_State *state,
const char *member_name,
M T::*member) {
std::function<M(T*)> lambda_get = [member](T *t) {
return t->*member;
};
_funs.emplace_back(
new ClassFun<1, T, M>
{state, std::string{member_name}, _get_metatable_name(), lambda_get});

std::function<void(T*, M)> lambda_set = [member](T *t, M value) {
(t->*member) = value;
};
_funs.emplace_back(
new ClassFun<0, T, void, M>
{state, std::string("set_") + member_name,
_get_metatable_name(), lambda_set});
}

template <typename Ret, typename... Args>
void _register_fun(lua_State *state,
const char *fun_name,
Ret(T::*fun)(Args...)) {
void _register_member(lua_State *state,
const char *fun_name,
Ret(T::*fun)(Args...)) {
std::function<Ret(T*, Args...)> lambda = [fun](T *t, Args... args) {
return (t->*fun)(args...);
};
Expand All @@ -58,24 +77,24 @@ class Class : public BaseClass {
{state, std::string(fun_name), _get_metatable_name(), lambda});
}

void _register_funs(lua_State *state) {}
void _register_members(lua_State *state) {}

template <typename F, typename... Fs>
void _register_funs(lua_State *state,
const char *name,
F fun,
Fs... funs) {
_register_fun(state, name, fun);
_register_funs(state, funs...);
template <typename M, typename... Ms>
void _register_members(lua_State *state,
const char *name,
M member,
Ms... members) {
_register_member(state, name, member);
_register_members(state, members...);
}

public:
Class(lua_State *state, const std::string &name,
Funs... funs) : _name(name) {
Members... members) : _name(name) {
luaL_newmetatable(state, _get_metatable_name().c_str());
_register_ctor(state);
_register_dtor(state);
_register_funs(state, funs...);
_register_members(state, members...);
lua_pushvalue(state, -1);
lua_setfield(state, -1, "__index");
}
Expand Down
2 changes: 2 additions & 0 deletions test/Test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ static TestMap tests = {
{"test_create_table_index", test_create_table_index},

{"test_register_class", test_register_class},
{"test_get_member_variable", test_get_member_variable},
{"test_set_member_variable", test_set_member_variable},
{"test_class_field_set", test_class_field_set},
{"test_class_gc", test_class_gc},
{"test_pass_pointer", test_pass_pointer},
Expand Down
15 changes: 15 additions & 0 deletions test/class_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,21 @@ bool test_register_class(sel::State &state) {
return result1 == 8 && result2 == "8+2";
}

bool test_get_member_variable(sel::State &state) {
state["Bar"].SetClass<Bar, int>("x", &Bar::x);
state("bar = Bar.new(-2)");
state("barx = bar:x()");
return state["barx"] == -2;
}

bool test_set_member_variable(sel::State &state) {
state["Bar"].SetClass<Bar, int>("x", &Bar::x);
state("bar = Bar.new(-2)");
state("bar:set_x(-4)");
state("barx = bar:x()");
return state["barx"] == -4;
}

bool test_class_field_set(sel::State &state) {
state["Bar"].SetClass<Bar, int>("set", &Bar::SetX, "get", &Bar::GetX);
state("bar = Bar.new(4)");
Expand Down

0 comments on commit d6f0470

Please sign in to comment.