1 #ifndef _library__lua_class__hpp__included__
2 #define _library__lua_class__hpp__included__
4 #include "lua-base.hpp"
11 bool (*is
)(state
& _state
, int index
);
12 const std::string
& (*name
)();
13 std::string (*print
)(state
& _state
, int index
);
16 std::list
<class_ops
>& userdata_recogn_fns();
17 std::string
try_recognize_userdata(state
& _state
, int index
);
18 std::string
try_print_userdata(state
& _state
, int index
);
19 std::unordered_map
<std::type_index
, void*>& class_types();
22 * Helper class containing binding data for Lua class call.
24 template<class T
> struct class_binding
27 * The pointer to call.
29 int (T::*fn
)(state
& lstate
, const std::string
& _fname
);
31 * The state to call it in.
35 * The name of the method to pass.
40 template<class T
> class _class
;
43 * Function to obtain class object for given Lua class.
45 template<class T
> _class
<T
>& objclass()
47 auto& type
= typeid(T
);
48 if(!class_types().count(type
))
49 throw std::runtime_error("Internal error: Lua class not found!");
50 return *reinterpret_cast<_class
<T
>*>(class_types()[type
]);
53 template<class T
> struct class_method
62 int (T::*fn
)(state
& LS
, const std::string
& fname
);
66 * The type of Lua classes.
68 template<class T
> class _class
70 template<typename
... U
> T
* _create(state
& _state
, U
... args
)
72 void* obj
= _state
.newuserdata(sizeof(T
));
73 load_metatable(_state
);
74 _state
.setmetatable(-2);
75 T
* _obj
= reinterpret_cast<T
*>(obj
);
76 new(_obj
) T(_state
, args
...);
80 static int class_bind_trampoline(lua_State
* LS
)
83 class_binding
<T
>* b
= (class_binding
<T
>*)lua_touserdata(LS
, lua_upvalueindex(1));
84 state
L(*b
->_state
, LS
);
85 T
* p
= _class
<T
>::get(L
, 1, b
->fname
);
86 return (p
->*(b
->fn
))(L
, b
->fname
);
87 } catch(std::exception
& e
) {
88 std::string err
= e
.what();
89 lua_pushlstring(LS
, err
.c_str(), err
.length());
94 T
* _get(state
& _state
, int arg
, const std::string
& fname
, bool optional
= false)
96 if(_state
.type(arg
) == LUA_TNONE
|| _state
.type(arg
) == LUA_TNIL
) {
102 load_metatable(_state
);
103 if(!_state
.getmetatable(arg
))
105 if(!_state
.rawequal(-1, -2))
108 return reinterpret_cast<T
*>(_state
.touserdata(arg
));
110 (stringfmt() << "argument #" << arg
<< " to " << fname
<< " must be " << name
).throwex();
111 return NULL
; //Never reached.
114 bool _is(state
& _state
, int arg
)
116 if(_state
.type(arg
) != LUA_TUSERDATA
)
118 load_metatable(_state
);
119 if(!_state
.getmetatable(arg
)) {
123 bool ret
= _state
.rawequal(-1, -2);
128 objpin
<T
> _pin(state
& _state
, int arg
, const std::string
& fname
)
130 T
* obj
= get(_state
, arg
, fname
);
131 _state
.pushvalue(arg
);
132 objpin
<T
> t(_state
, obj
);
138 * Create a new Lua class.
140 * Parameter _name: The name of the class.
142 _class(const std::string
& _name
)
146 m
.is
= _class
<T
>::is
;
147 m
.name
= _class
<T
>::get_name
;
148 m
.print
= _class
<T
>::print
;
149 userdata_recogn_fns().push_back(m
);
150 auto& type
= typeid(T
);
151 class_types()[type
] = this;
155 * Create a new instance of object.
157 * Parameter _state: The Lua state to create the object in.
158 * Parameter args: The arguments to pass to class constructor.
160 template<typename
... U
> static T
* create(state
& _state
, U
... args
)
162 return objclass
<T
>()._create(_state
, args
...);
166 * Bind a method to class.
168 * Parameter _state: The state to do the binding in.
169 * Parameter keyname: The name of the method.
170 * Parameter fn: The method to call.
171 * Parameter force: If true, overwrite existing method.
173 void bind(state
& _state
, const char* keyname
, int (T::*fn
)(state
& LS
, const std::string
& fname
))
175 load_metatable(_state
);
176 _state
.pushstring(keyname
);
177 std::string fname
= name
+ std::string("::") + keyname
;
178 void* ptr
= _state
.newuserdata(sizeof(class_binding
<T
>) + fname
.length() + 1);
179 class_binding
<T
>* bdata
= reinterpret_cast<class_binding
<T
>*>(ptr
);
181 bdata
->_state
= &_state
.get_master();
182 std::copy(fname
.begin(), fname
.end(), bdata
->fname
);
183 bdata
->fname
[fname
.length()] = 0;
184 _state
.pushcclosure(class_bind_trampoline
, 1);
189 * Bind multiple at once.
191 void bind_multi(state
& _state
, std::initializer_list
<class_method
<T
>> list
, void* doonce_key
= NULL
)
193 static char once_key
;
194 if(_state
.do_once(doonce_key
? doonce_key
: &once_key
))
196 bind(_state
, i
.name
, i
.fn
);
199 * Get a pointer to the object.
201 * Parameter _state: The Lua state.
202 * Parameter arg: Argument index.
203 * Parameter fname: The name of function for error messages.
204 * Parameter optional: If true and argument is NIL or none, return NULL.
205 * Throws std::runtime_error: Wrong type.
207 static T
* get(state
& _state
, int arg
, const std::string
& fname
, bool optional
= false)
208 throw(std::bad_alloc
, std::runtime_error
)
210 return objclass
<T
>()._get(_state
, arg
, fname
, optional
);
214 * Identify if object is of this type.
216 * Parameter _state: The Lua state.
217 * Parameter arg: Argument index.
218 * Returns: True if object is of specified type, false if not.
220 static bool is(state
& _state
, int arg
) throw()
223 return objclass
<T
>()._is(_state
, arg
);
231 static const std::string
& get_name()
234 return objclass
<T
>().name
;
236 static std::string foo
= "???";
241 * Format instance of this class as string.
243 static std::string
print(state
& _state
, int index
)
245 T
* obj
= get(_state
, index
, "__internal_print");
249 * Get a pin of object against Lua GC.
251 * Parameter _state: The Lua state.
252 * Parameter arg: Argument index.
253 * Parameter fname: Name of function for error message purposes.
254 * Throws std::runtime_error: Wrong type.
256 static objpin
<T
> pin(state
& _state
, int arg
, const std::string
& fname
) throw(std::bad_alloc
,
259 return objclass
<T
>()._pin(_state
, arg
, fname
);
262 static int dogc(lua_State
* LS
)
264 T
* obj
= reinterpret_cast<T
*>(lua_touserdata(LS
, 1));
269 static int newindex(lua_State
* LS
)
271 lua_pushstring(LS
, "Writing metatables of classes is not allowed");
276 static int index(lua_State
* LS
)
278 lua_getmetatable(LS
, 1);
279 lua_pushvalue(LS
, 2);
284 void load_metatable(state
& _state
)
287 _state
.pushlightuserdata(this);
288 _state
.rawget(LUA_REGISTRYINDEX
);
289 if(_state
.type(-1) == LUA_TNIL
) {
291 _state
.pushlightuserdata(this);
293 _state
.pushvalue(-1);
294 _state
.setmetatable(-2);
295 _state
.pushstring("__gc");
296 _state
.pushcfunction(&_class
<T
>::dogc
);
298 _state
.pushstring("__newindex");
299 _state
.pushcfunction(&_class
<T
>::newindex
);
301 _state
.pushstring("__index");
302 _state
.pushcfunction(&_class
<T
>::index
);
304 _state
.rawset(LUA_REGISTRYINDEX
);
309 _class(const _class
<T
>&);
310 _class
& operator=(const _class
<T
>&);