[DEV] import basic c++ lua wrapper
This commit is contained in:
commit
11bbc0e7a1
98
README.md
Normal file
98
README.md
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
LuaWrapper
|
||||||
|
Copyright (c) 2010-2013 Alexander Ames
|
||||||
|
Alexander.Ames@gmail.com
|
||||||
|
|
||||||
|
Original source :
|
||||||
|
https://bitbucket.org/alexames/luawrapper/src/fd9c4fdbf4b25034e3b8475a2c8da66b7caab427?at=default
|
||||||
|
|
||||||
|
LuaWrapper is a library designed to help bridge the gab between Lua and C++.
|
||||||
|
It is designed to be small (a single header file), simple, fast, and typesafe.
|
||||||
|
It has no external dependencies other than the lua library itself, and does not
|
||||||
|
need to be precompiled; the header can simply be dropped into a project and
|
||||||
|
used immediately. It even supports class inheritance to a certain degree.
|
||||||
|
Objects can be created in either Lua or C++, and passed back and forth.
|
||||||
|
|
||||||
|
Instructions on how to use the library follow, but a simple example project has
|
||||||
|
been set up to see basic library usage and can be found at
|
||||||
|
|
||||||
|
https://bitbucket.org/alexames/luawrapperexample
|
||||||
|
|
||||||
|
In Lua, the objects are userdata, but through tricky use of metatables, they
|
||||||
|
can be treated almost identically to tables. Each userdata has a __index and
|
||||||
|
__newindex function that maps to a table hidden storage table in the registry.
|
||||||
|
|
||||||
|
The main functions of interest are the following:
|
||||||
|
luaW_is<T>
|
||||||
|
luaW_to<T>
|
||||||
|
luaW_check<T>
|
||||||
|
luaW_push<T>
|
||||||
|
luaW_register<T>
|
||||||
|
luaW_extend<T, U>
|
||||||
|
luaW_hold<T>
|
||||||
|
luaW_release<T>
|
||||||
|
|
||||||
|
The first four functions allow you to manipulate arbitrary classes just like
|
||||||
|
you would the primitive types (e.g. numbers or strings). luaW_is<T> allows you
|
||||||
|
to check if the object is what you think it is, and will take the is-a
|
||||||
|
relationship into account unless the optional strict argument is set.
|
||||||
|
luaW_to<T> will return a pointer of type T to your object (unless it is of the
|
||||||
|
wrong type, in which case it will return NULL).
|
||||||
|
|
||||||
|
Registering a class:
|
||||||
|
|
||||||
|
Run luaW_register to create a table and metatable for your class. This creates
|
||||||
|
a table with the name you specify filled with the function from the table
|
||||||
|
argument in addition to the function new. This is generally for things you
|
||||||
|
think of as static methods in C++. The metatable becomes a metatable for each
|
||||||
|
object if your class. These can be thought of as member functions or methods.
|
||||||
|
|
||||||
|
You may also supply constructors and destructors for classes that do not have a
|
||||||
|
default constructor or that require special set up or tear down. You may
|
||||||
|
specify NULL as the constructor, which means that you will not be able to call
|
||||||
|
the new function on your class table. You will need to manually push objects
|
||||||
|
from C++. By default, the default constructor is used to create objects and a
|
||||||
|
simple call to delete is used to destroy them. When using the constructor, you
|
||||||
|
do not have access to the userdata's storage table. If you want to add or
|
||||||
|
adjust values to the storage table you can use the special post constructor
|
||||||
|
metamethod ("__postctor" or LUAW_POSTCTOR_KEY).
|
||||||
|
|
||||||
|
By default, LuaWrapper uses the address of C++ object to identify unique
|
||||||
|
objects. In some cases this is not desired, such as in the case of shared_ptrs.
|
||||||
|
Two shared_ptrs may themselves have unique locations in memory but still
|
||||||
|
represent the same object. For cases like that, you may specify an identifier
|
||||||
|
function which is responsible for pushing a key representing your object on to
|
||||||
|
the stack.
|
||||||
|
|
||||||
|
Extending a class:
|
||||||
|
|
||||||
|
To extend a class use the function luaW_extend<T, U>, where T is a class that
|
||||||
|
extends U. All functions in the base class will be available to the derived
|
||||||
|
class (except when they share a function name, in which case the derived
|
||||||
|
class's function wins).
|
||||||
|
|
||||||
|
Pointer Ownership:
|
||||||
|
|
||||||
|
Objects created from within Lua scripts (or that are created through luaW_new)
|
||||||
|
are considered to be owned by Lua. Ownership merely means that when all
|
||||||
|
references to it are removed, the garbage collector will delete the object. An
|
||||||
|
object created in C++ and pushed to Lua is not considered owned unless
|
||||||
|
luaW_hold is run on it. LuaWrapper uses a weak table to cache objects in order
|
||||||
|
to prevent the __gc metamethod from deleting pointers to objects that are still
|
||||||
|
in use. If an object is created in Lua and you do not want it to be owned by
|
||||||
|
Lua, you may call luaW_release on it.
|
||||||
|
|
||||||
|
Lua Wrapper Utilities:
|
||||||
|
|
||||||
|
A second file, called LuaWrapperUtil.hpp includes a number of additional
|
||||||
|
functions that may be useful, which build upon the core LuaWrapper API. The
|
||||||
|
main features are some functions which automatically cast interger types to
|
||||||
|
enum types and templated getters and setters for primitives an pointers to
|
||||||
|
objects. All functions in LuaWrapperUtil.hpp are prefixed with luaU_.
|
||||||
|
Documentation and some examples are provided in the comments of the file.
|
||||||
|
|
||||||
|
Contributions:
|
||||||
|
|
||||||
|
Thanks to Christopher Eykamp for the idea to use ephemeron tables to cache
|
||||||
|
userdata to avoid unnecessary allocations as wells as various other feedback.
|
||||||
|
|
||||||
|
Thanks to qwer1304 for the addition of enum support in the utilities functions.
|
19
license.txt
Normal file
19
license.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2010-2011 Alexander Ames
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to
|
||||||
|
deal in the Software without restriction, including without limitation the
|
||||||
|
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
IN THE SOFTWARE.
|
643
luaWrapper/luaWrapper.hpp
Normal file
643
luaWrapper/luaWrapper.hpp
Normal file
@ -0,0 +1,643 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2013 Alexander Ames
|
||||||
|
* Alexander.Ames@gmail.com
|
||||||
|
* See Copyright Notice at the end of this file
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** API Summary:
|
||||||
|
*
|
||||||
|
* LuaWrapper is a library designed to help bridge the gab between Lua and
|
||||||
|
* C++. It is designed to be small (a single header file), simple, fast,
|
||||||
|
* and typesafe. It has no external dependencies, and does not need to be
|
||||||
|
* precompiled; the header can simply be dropped into a project and used
|
||||||
|
* immediately. It even supports class inheritance to a certain degree. Objects
|
||||||
|
* can be created in either Lua or C++, and passed back and forth.
|
||||||
|
*
|
||||||
|
* The main functions of interest are the following:
|
||||||
|
* luaW_is<T>
|
||||||
|
* luaW_to<T>
|
||||||
|
* luaW_check<T>
|
||||||
|
* luaW_push<T>
|
||||||
|
* luaW_register<T>
|
||||||
|
* luaW_setfuncs<T>
|
||||||
|
* luaW_extend<T, U>
|
||||||
|
* luaW_hold<T>
|
||||||
|
* luaW_release<T>
|
||||||
|
*
|
||||||
|
* These functions allow you to manipulate arbitrary classes just like you
|
||||||
|
* would the primitive types (e.g. numbers or strings). If you are familiar
|
||||||
|
* with the normal Lua API the behavior of these functions should be very
|
||||||
|
* intuative.
|
||||||
|
*
|
||||||
|
* For more information see the README and the comments below
|
||||||
|
*/
|
||||||
|
#ifndef __LUA_WRAPPER_H__
|
||||||
|
#define __LUA_WRAPPER_H__
|
||||||
|
|
||||||
|
// If you are linking against Lua compiled in C++, define LUAW_NO_EXTERN_C
|
||||||
|
#include <lua/lua.h>
|
||||||
|
#include <lua/lauxlib.h>
|
||||||
|
|
||||||
|
#define LUAW_POSTCTOR_KEY "__postctor"
|
||||||
|
#define LUAW_EXTENDS_KEY "__extends"
|
||||||
|
#define LUAW_STORAGE_KEY "storage"
|
||||||
|
#define LUAW_CACHE_KEY "cache"
|
||||||
|
#define LUAW_CACHE_METATABLE_KEY "cachemetatable"
|
||||||
|
#define LUAW_HOLDS_KEY "holds"
|
||||||
|
#define LUAW_WRAPPER_KEY "LuaWrapper"
|
||||||
|
/**
|
||||||
|
* A simple utility function to adjust a given index
|
||||||
|
* Useful for when a parameter index needs to be adjusted
|
||||||
|
* after pushing or popping things off the stack
|
||||||
|
*/
|
||||||
|
inline int luaW_correctindex(lua_State* _L, int _index, int _correction) {
|
||||||
|
return _index < 0 ? _index - _correction : _index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These are the default allocator and deallocator. If you would prefer an
|
||||||
|
* alternative option, you may select a different function when registering
|
||||||
|
* your class.
|
||||||
|
*/
|
||||||
|
template <typename T> T* luaW_defaultallocator(lua_State*) {
|
||||||
|
return new T();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void luaW_defaultdeallocator(lua_State*, T* _obj) {
|
||||||
|
delete _obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifier function is responsible for pushing a value unique to each
|
||||||
|
* object on to the stack. Most of the time, this can simply be the address
|
||||||
|
* of the pointer, but sometimes that is not adaquate. For example, if you
|
||||||
|
* are using shared_ptr you would need to push the address of the object the
|
||||||
|
* shared_ptr represents, rather than the address of the shared_ptr itself.
|
||||||
|
*/
|
||||||
|
template <typename T> void luaW_defaultidentifier(lua_State* _L, T* _obj) {
|
||||||
|
lua_pushlightuserdata(_L, _obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is what is used by LuaWrapper to contain the userdata. data
|
||||||
|
* stores a pointer to the object itself, and cast is used to cast toward the
|
||||||
|
* base class if there is one and it is necessary. Rather than use RTTI and
|
||||||
|
* typid to compare types, I use the clever trick of using the cast to compare
|
||||||
|
* types. Because there is at most one cast per type, I can use it to identify
|
||||||
|
* when and object is the type I want. This is only used internally.
|
||||||
|
*/
|
||||||
|
struct luaW_Userdata {
|
||||||
|
luaW_Userdata(void* vptr = NULL, luaW_Userdata (*udcast)(const luaW_Userdata&) = NULL) :
|
||||||
|
data(vptr),
|
||||||
|
cast(udcast) {
|
||||||
|
// nothing to do ...
|
||||||
|
}
|
||||||
|
void* data;
|
||||||
|
luaW_Userdata (*cast)(const luaW_Userdata&);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class cannot actually to be instantiated. It is used only hold the
|
||||||
|
* table name and other information.
|
||||||
|
*/
|
||||||
|
template <typename T> class LuaWrapper {
|
||||||
|
public:
|
||||||
|
static const char* classname;
|
||||||
|
static void (*identifier)(lua_State*, T*);
|
||||||
|
static T* (*allocator)(lua_State*);
|
||||||
|
static void (*deallocator)(lua_State*, T*);
|
||||||
|
static luaW_Userdata (*cast)(const luaW_Userdata&);
|
||||||
|
static void (*postconstructorrecurse)(lua_State* _L, int numargs);
|
||||||
|
private:
|
||||||
|
LuaWrapper();
|
||||||
|
};
|
||||||
|
template <typename T> const char* LuaWrapper<T>::classname;
|
||||||
|
template <typename T> void (*LuaWrapper<T>::identifier)(lua_State*, T*);
|
||||||
|
template <typename T> T* (*LuaWrapper<T>::allocator)(lua_State*);
|
||||||
|
template <typename T> void (*LuaWrapper<T>::deallocator)(lua_State*, T*);
|
||||||
|
template <typename T> luaW_Userdata (*LuaWrapper<T>::cast)(const luaW_Userdata&);
|
||||||
|
template <typename T> void (*LuaWrapper<T>::postconstructorrecurse)(lua_State* _L, int _numargs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cast from an object of type T to an object of type U. This template
|
||||||
|
* function is instantiated by calling luaW_extend<T, U>(L). This is only used
|
||||||
|
* internally.
|
||||||
|
*/
|
||||||
|
template <typename T, typename U> luaW_Userdata luaW_cast(const luaW_Userdata& _obj) {
|
||||||
|
return luaW_Userdata(static_cast<U*>(static_cast<T*>(_obj.data)), LuaWrapper<U>::cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U> void luaW_identify(lua_State* _L, T* _obj) {
|
||||||
|
LuaWrapper<U>::identifier(_L, static_cast<U*>(_obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> inline void luaW_wrapperfield(lua_State* _L, const char* _field) {
|
||||||
|
lua_getfield(_L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... LuaWrapper
|
||||||
|
lua_getfield(_L, -1, _field); // ... LuaWrapper LuaWrapper.field
|
||||||
|
lua_getfield(_L, -1, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.field LuaWrapper.field.class
|
||||||
|
lua_replace(_L, -3); // ... LuaWrapper.field.class LuaWrapper.field
|
||||||
|
lua_pop(_L, 1); // ... LuaWrapper.field.class
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analogous to lua_is(boolean|string|*)
|
||||||
|
*
|
||||||
|
* Returns 1 if the value at the given acceptable index is of type T (or if
|
||||||
|
* strict is false, convertable to type T) and 0 otherwise.
|
||||||
|
*/
|
||||||
|
template <typename T> bool luaW_is(lua_State *_L, int _index, bool _strict = false) {
|
||||||
|
bool equal = false;// lua_isnil(_L, index);
|
||||||
|
if (!equal && lua_isuserdata(_L, _index) && lua_getmetatable(_L, _index)) {
|
||||||
|
// ... ud ... udmt
|
||||||
|
luaL_getmetatable(_L, LuaWrapper<T>::classname); // ... ud ... udmt Tmt
|
||||||
|
equal = lua_rawequal(_L, -1, -2) != 0;
|
||||||
|
if (!equal && !_strict) {
|
||||||
|
lua_getfield(_L, -2, LUAW_EXTENDS_KEY); // ... ud ... udmt Tmt udmt.extends
|
||||||
|
for (lua_pushnil(_L); lua_next(_L, -2); lua_pop(_L, 1)) {
|
||||||
|
// ... ud ... udmt Tmt udmt.extends k v
|
||||||
|
equal = lua_rawequal(_L, -1, -4) != 0;
|
||||||
|
if (equal) {
|
||||||
|
lua_pop(_L, 2); // ... ud ... udmt Tmt udmt.extends
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pop(_L, 1); // ... ud ... udmt Tmt
|
||||||
|
}
|
||||||
|
lua_pop(_L, 2); // ... ud ...
|
||||||
|
}
|
||||||
|
return equal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analogous to lua_to(boolean|string|*)
|
||||||
|
*
|
||||||
|
* Converts the given acceptable index to a T*. That value must be of (or
|
||||||
|
* convertable to) type T; otherwise, returns NULL.
|
||||||
|
*/
|
||||||
|
template <typename T> T* luaW_to(lua_State* _L, int _index, bool _strict = false) {
|
||||||
|
if (luaW_is<T>(_L, _index, _strict)) {
|
||||||
|
luaW_Userdata* pud = static_cast<luaW_Userdata*>(lua_touserdata(_L, _index));
|
||||||
|
luaW_Userdata ud;
|
||||||
|
while ( !_strict
|
||||||
|
&& LuaWrapper<T>::cast != pud->cast) {
|
||||||
|
ud = pud->cast(*pud);
|
||||||
|
pud = &ud;
|
||||||
|
}
|
||||||
|
return static_cast<T*>(pud->data);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analogous to luaL_check(boolean|string|*)
|
||||||
|
*
|
||||||
|
* Converts the given acceptable index to a T*. That value must be of (or
|
||||||
|
* convertable to) type T; otherwise, an error is raised.
|
||||||
|
*/
|
||||||
|
template <typename T> T* luaW_check(lua_State* _L, int _index, bool _strict = false) {
|
||||||
|
T* obj = NULL;
|
||||||
|
if (luaW_is<T>(_L, _index, _strict)) {
|
||||||
|
luaW_Userdata* pud = static_cast<luaW_Userdata*>(lua_touserdata(_L, _index));
|
||||||
|
luaW_Userdata ud;
|
||||||
|
while (!_strict && LuaWrapper<T>::cast != pud->cast) {
|
||||||
|
ud = pud->cast(*pud);
|
||||||
|
pud = &ud;
|
||||||
|
}
|
||||||
|
obj = (T*)pud->data;
|
||||||
|
} else {
|
||||||
|
const char *msg = lua_pushfstring(_L, "%s expected, got %s", LuaWrapper<T>::classname, luaL_typename(_L, _index));
|
||||||
|
luaL_argerror(_L, _index, msg);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T* luaW_opt(lua_State* _L, int _index, T* _fallback = NULL, bool _strict = false) {
|
||||||
|
if (lua_isnil(_L, _index)) {
|
||||||
|
return _fallback;
|
||||||
|
} else {
|
||||||
|
return luaW_check<T>(_L, _index, _strict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analogous to lua_push(boolean|string|*)
|
||||||
|
*
|
||||||
|
* Pushes a userdata of type T onto the stack. If this object already exists in
|
||||||
|
* the Lua environment, it will assign the existing storage table to it.
|
||||||
|
* Otherwise, a new storage table will be created for it.
|
||||||
|
*/
|
||||||
|
template <typename T> void luaW_push(lua_State* _L, T* _obj) {
|
||||||
|
if (_obj) {
|
||||||
|
LuaWrapper<T>::identifier(_L, _obj); // ... id
|
||||||
|
luaW_wrapperfield<T>(_L, LUAW_CACHE_KEY); // ... id cache
|
||||||
|
lua_pushvalue(_L, -2); // ... id cache id
|
||||||
|
lua_gettable(_L, -2); // ... id cache obj
|
||||||
|
if (lua_isnil(_L, -1)) {
|
||||||
|
// Create the new luaW_userdata and place it in the cache
|
||||||
|
lua_pop(_L, 1); // ... id cache
|
||||||
|
lua_insert(_L, -2); // ... cache id
|
||||||
|
luaW_Userdata* ud = static_cast<luaW_Userdata*>(lua_newuserdata(_L, sizeof(luaW_Userdata))); // ... cache id obj
|
||||||
|
ud->data = _obj;
|
||||||
|
ud->cast = LuaWrapper<T>::cast;
|
||||||
|
lua_pushvalue(_L, -1); // ... cache id obj obj
|
||||||
|
lua_insert(_L, -4); // ... obj cache id obj
|
||||||
|
lua_settable(_L, -3); // ... obj cache
|
||||||
|
luaL_getmetatable(_L, LuaWrapper<T>::classname); // ... obj cache mt
|
||||||
|
lua_setmetatable(_L, -3); // ... obj cache
|
||||||
|
lua_pop(_L, 1); // ... obj
|
||||||
|
} else {
|
||||||
|
lua_replace(_L, -3); // ... obj cache
|
||||||
|
lua_pop(_L, 1); // ... obj
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lua_pushnil(_L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructs LuaWrapper that it owns the userdata, and can manage its memory.
|
||||||
|
* When all references to the object are removed, Lua is free to garbage
|
||||||
|
* collect it and delete the object.
|
||||||
|
*
|
||||||
|
* Returns true if luaW_hold took hold of the object, and false if it was
|
||||||
|
* already held
|
||||||
|
*/
|
||||||
|
template <typename T> bool luaW_hold(lua_State* _L, T* _obj) {
|
||||||
|
luaW_wrapperfield<T>(_L, LUAW_HOLDS_KEY); // ... holds
|
||||||
|
LuaWrapper<T>::identifier(_L, _obj); // ... holds id
|
||||||
|
lua_pushvalue(_L, -1); // ... holds id id
|
||||||
|
lua_gettable(_L, -3); // ... holds id hold
|
||||||
|
// If it's not held, hold it
|
||||||
|
if (!lua_toboolean(_L, -1)) {
|
||||||
|
// Apply hold boolean
|
||||||
|
lua_pop(_L, 1); // ... holds id
|
||||||
|
lua_pushboolean(_L, true); // ... holds id true
|
||||||
|
lua_settable(_L, -3); // ... holds
|
||||||
|
lua_pop(_L, 1); // ...
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
lua_pop(_L, 3); // ...
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases LuaWrapper's hold on an object. This allows the user to remove
|
||||||
|
* all references to an object in Lua and ensure that Lua will not attempt to
|
||||||
|
* garbage collect it.
|
||||||
|
*
|
||||||
|
* This function takes the index of the identifier for an object rather than
|
||||||
|
* the object itself. This is because needs to be able to run after the object
|
||||||
|
* has already been deallocated. A wrapper is provided for when it is more
|
||||||
|
* convenient to pass in the object directly.
|
||||||
|
*/
|
||||||
|
template <typename T> void luaW_release(lua_State* _L, int _index) {
|
||||||
|
luaW_wrapperfield<T>(_L, LUAW_HOLDS_KEY); // ... id ... holds
|
||||||
|
lua_pushvalue(_L, luaW_correctindex(_L, _index, 1)); // ... id ... holds id
|
||||||
|
lua_pushnil(_L); // ... id ... holds id nil
|
||||||
|
lua_settable(_L, -3); // ... id ... holds
|
||||||
|
lua_pop(_L, 1); // ... id ...
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void luaW_release(lua_State* _L, T* _obj) {
|
||||||
|
LuaWrapper<T>::identifier(_L, _obj); // ... id
|
||||||
|
luaW_release<T>(_L, -1); // ... id
|
||||||
|
lua_pop(_L, 1); // ...
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void luaW_postconstructorinternal(lua_State* _L, int _numargs) {
|
||||||
|
// ... ud args...
|
||||||
|
if (LuaWrapper<T>::postconstructorrecurse) {
|
||||||
|
LuaWrapper<T>::postconstructorrecurse(_L, _numargs);
|
||||||
|
}
|
||||||
|
luaL_getmetatable(_L, LuaWrapper<T>::classname); // ... ud args... mt
|
||||||
|
lua_getfield(_L, -1, LUAW_POSTCTOR_KEY); // ... ud args... mt postctor
|
||||||
|
if (lua_type(_L, -1) == LUA_TFUNCTION) {
|
||||||
|
for (int i = 0; i < _numargs + 1; i++) {
|
||||||
|
lua_pushvalue(_L, -3 - _numargs); // ... ud args... mt postctor ud args...
|
||||||
|
}
|
||||||
|
lua_call(_L, _numargs + 1, 0); // ... ud args... mt
|
||||||
|
lua_pop(_L, 1); // ... ud args...
|
||||||
|
} else {
|
||||||
|
lua_pop(_L, 2); // ... ud args...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called from Lua, not C++
|
||||||
|
*
|
||||||
|
* Calls the lua post-constructor (LUAW_POSTCTOR_KEY or "__postctor") on a
|
||||||
|
* userdata. Assumes the userdata is on the stack and numargs arguments follow
|
||||||
|
* it. This runs the LUAW_POSTCTOR_KEY function on T's metatable, using the
|
||||||
|
* object as the first argument and whatever else is below it as the rest of the
|
||||||
|
* arguments This exists to allow types to adjust values in thier storage table,
|
||||||
|
* which can not be created until after the constructor is called.
|
||||||
|
*/
|
||||||
|
template <typename T> void luaW_postconstructor(lua_State* _L, int _numargs) {
|
||||||
|
// ... ud args...
|
||||||
|
luaW_postconstructorinternal<T>(_L, _numargs); // ... ud args...
|
||||||
|
lua_pop(_L, _numargs); // ... ud
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is generally called from Lua, not C++
|
||||||
|
*
|
||||||
|
* Creates an object of type T using the constructor and subsequently calls the
|
||||||
|
* post-constructor on it.
|
||||||
|
*/
|
||||||
|
template <typename T> inline int luaW_new(lua_State* _L, int _numargs) {
|
||||||
|
// ... args...
|
||||||
|
T* obj = LuaWrapper<T>::allocator(_L);
|
||||||
|
luaW_push<T>(_L, obj); // ... args... ud
|
||||||
|
luaW_hold<T>(_L, obj);
|
||||||
|
lua_insert(_L, -1 - _numargs); // ... ud args...
|
||||||
|
luaW_postconstructor<T>(_L, _numargs); // ... ud
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> int luaW_new(lua_State* _L) {
|
||||||
|
return luaW_new<T>(_L, lua_gettop(_L));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called from Lua, not C++
|
||||||
|
*
|
||||||
|
* The default metamethod to call when indexing into lua userdata representing
|
||||||
|
* an object of type T. This will first check the userdata's environment table
|
||||||
|
* and if it's not found there it will check the metatable. This is done so
|
||||||
|
* individual userdata can be treated as a table, and can hold thier own
|
||||||
|
* values.
|
||||||
|
*/
|
||||||
|
template <typename T> int luaW_index(lua_State* _L) {
|
||||||
|
// obj key
|
||||||
|
T* obj = luaW_to<T>(_L, 1);
|
||||||
|
luaW_wrapperfield<T>(_L, LUAW_STORAGE_KEY); // obj key storage
|
||||||
|
LuaWrapper<T>::identifier(_L, obj); // obj key storage id
|
||||||
|
lua_gettable(_L, -2); // obj key storage store
|
||||||
|
// Check if storage table exists
|
||||||
|
if (!lua_isnil(_L, -1)) {
|
||||||
|
lua_pushvalue(_L, -3); // obj key storage store key
|
||||||
|
lua_gettable(_L, -2); // obj key storage store store[k]
|
||||||
|
}
|
||||||
|
// If either there is no storage table or the key wasn't found
|
||||||
|
// then fall back to the metatable
|
||||||
|
if (lua_isnil(_L, -1)) {
|
||||||
|
lua_settop(_L, 2); // obj key
|
||||||
|
lua_getmetatable(_L, -2); // obj key mt
|
||||||
|
lua_pushvalue(_L, -2); // obj key mt k
|
||||||
|
lua_gettable(_L, -2); // obj key mt mt[k]
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called from Lua, not C++
|
||||||
|
*
|
||||||
|
* The default metamethod to call when creating a new index on lua userdata
|
||||||
|
* representing an object of type T. This will index into the the userdata's
|
||||||
|
* environment table that it keeps for personal storage. This is done so
|
||||||
|
* individual userdata can be treated as a table, and can hold thier own
|
||||||
|
* values.
|
||||||
|
*/
|
||||||
|
template <typename T> int luaW_newindex(lua_State* _L) {
|
||||||
|
// obj key value
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
luaW_wrapperfield<T>(_L, LUAW_STORAGE_KEY); // obj key value storage
|
||||||
|
LuaWrapper<T>::identifier(_L, obj); // obj key value storage id
|
||||||
|
lua_pushvalue(_L, -1); // obj key value storage id id
|
||||||
|
lua_gettable(_L, -3); // obj key value storage id store
|
||||||
|
// Add the storage table if there isn't one already
|
||||||
|
if (lua_isnil(_L, -1)) {
|
||||||
|
lua_pop(_L, 1); // obj key value storage id
|
||||||
|
lua_newtable(_L); // obj key value storage id store
|
||||||
|
lua_pushvalue(_L, -1); // obj key value storage id store store
|
||||||
|
lua_insert(_L, -3); // obj key value storage store id store
|
||||||
|
lua_settable(_L, -4); // obj key value storage store
|
||||||
|
}
|
||||||
|
lua_pushvalue(_L, 2); // obj key value ... store key
|
||||||
|
lua_pushvalue(_L, 3); // obj key value ... store key value
|
||||||
|
lua_settable(_L, -3); // obj key value ... store
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called from Lua, not C++
|
||||||
|
*
|
||||||
|
* The __gc metamethod handles cleaning up userdata. The userdata's reference
|
||||||
|
* count is decremented and if this is the final reference to the userdata its
|
||||||
|
* environment table is nil'd and pointer deleted with the destructor callback.
|
||||||
|
*/
|
||||||
|
template <typename T> int luaW_gc(lua_State* _L) {
|
||||||
|
// obj
|
||||||
|
T* obj = luaW_to<T>(_L, 1);
|
||||||
|
LuaWrapper<T>::identifier(_L, obj); // obj key value storage id
|
||||||
|
luaW_wrapperfield<T>(_L, LUAW_HOLDS_KEY); // obj id counts count holds
|
||||||
|
lua_pushvalue(_L, 2); // obj id counts count holds id
|
||||||
|
lua_gettable(_L, -2); // obj id counts count holds hold
|
||||||
|
if (lua_toboolean(_L, -1) && LuaWrapper<T>::deallocator) {
|
||||||
|
LuaWrapper<T>::deallocator(_L, obj);
|
||||||
|
}
|
||||||
|
luaW_wrapperfield<T>(_L, LUAW_STORAGE_KEY); // obj id counts count holds hold storage
|
||||||
|
lua_pushvalue(_L, 2); // obj id counts count holds hold storage id
|
||||||
|
lua_pushnil(_L); // obj id counts count holds hold storage id nil
|
||||||
|
lua_settable(_L, -3); // obj id counts count holds hold storage
|
||||||
|
luaW_release<T>(_L, 2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thakes two tables and registers them with Lua to the table on the top of the
|
||||||
|
* stack.
|
||||||
|
*
|
||||||
|
* This function is only called from LuaWrapper internally.
|
||||||
|
*/
|
||||||
|
inline void luaW_registerfuncs(lua_State* _L, const luaL_Reg _defaulttable[], const luaL_Reg _table[]) {
|
||||||
|
// ... T
|
||||||
|
#if LUA_VERSION_NUM == 502
|
||||||
|
if (_defaulttable) {
|
||||||
|
luaL_setfuncs(_L, _defaulttable, 0); // ... T
|
||||||
|
}
|
||||||
|
if (_table) {
|
||||||
|
luaL_setfuncs(_L, _table, 0); // ... T
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (_defaulttable) {
|
||||||
|
luaL_register(_L, NULL, _defaulttable); // ... T
|
||||||
|
}
|
||||||
|
if (_table) {
|
||||||
|
luaL_register(_L, NULL, _table); // ... T
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the LuaWrapper tables used to track internal state.
|
||||||
|
*
|
||||||
|
* This function is only called from LuaWrapper internally.
|
||||||
|
*/
|
||||||
|
inline void luaW_initialize(lua_State* _L) {
|
||||||
|
// Ensure that the LuaWrapper table is set up
|
||||||
|
lua_getfield(_L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... LuaWrapper
|
||||||
|
if (lua_isnil(_L, -1)) {
|
||||||
|
lua_newtable(_L); // ... nil {}
|
||||||
|
lua_pushvalue(_L, -1); // ... nil {} {}
|
||||||
|
lua_setfield(_L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... nil LuaWrapper
|
||||||
|
// Create a storage table
|
||||||
|
lua_newtable(_L); // ... LuaWrapper nil {}
|
||||||
|
lua_setfield(_L, -2, LUAW_STORAGE_KEY); // ... nil LuaWrapper
|
||||||
|
// Create a holds table
|
||||||
|
lua_newtable(_L); // ... LuaWrapper {}
|
||||||
|
lua_setfield(_L, -2, LUAW_HOLDS_KEY); // ... nil LuaWrapper
|
||||||
|
// Create a cache table, with weak values so that the userdata will not
|
||||||
|
// be ref counted
|
||||||
|
lua_newtable(_L); // ... nil LuaWrapper {}
|
||||||
|
lua_setfield(_L, -2, LUAW_CACHE_KEY); // ... nil LuaWrapper
|
||||||
|
lua_newtable(_L); // ... nil LuaWrapper {}
|
||||||
|
lua_pushstring(_L, "v"); // ... nil LuaWrapper {} "v"
|
||||||
|
lua_setfield(_L, -2, "__mode"); // ... nil LuaWrapper {}
|
||||||
|
lua_setfield(_L, -2, LUAW_CACHE_METATABLE_KEY); // ... nil LuaWrapper
|
||||||
|
lua_pop(_L, 1); // ... nil
|
||||||
|
}
|
||||||
|
lua_pop(_L, 1); // ...
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run luaW_register or luaW_setfuncs to create a table and metatable for your
|
||||||
|
* class. These functions create a table with filled with the function from
|
||||||
|
* the table argument in addition to the functions new and build (This is
|
||||||
|
* generally for things you think of as static methods in C++). The given
|
||||||
|
* metatable argument becomes a metatable for each object of your class. These
|
||||||
|
* can be thought of as member functions or methods.
|
||||||
|
*
|
||||||
|
* You may also supply constructors and destructors for classes that do not
|
||||||
|
* have a default constructor or that require special set up or tear down. You
|
||||||
|
* may specify NULL as the constructor, which means that you will not be able
|
||||||
|
* to call the new function on your class table. You will need to manually push
|
||||||
|
* objects from C++. By default, the default constructor is used to create
|
||||||
|
* objects and a simple call to delete is used to destroy them.
|
||||||
|
*
|
||||||
|
* By default LuaWrapper uses the address of C++ object to identify unique
|
||||||
|
* objects. In some cases this is not desired, such as in the case of
|
||||||
|
* shared_ptrs. Two shared_ptrs may themselves have unique locations in memory
|
||||||
|
* but still represent the same object. For cases like that, you may specify an
|
||||||
|
* identifier function which is responsible for pushing a key representing your
|
||||||
|
* object on to the stack.
|
||||||
|
*
|
||||||
|
* luaW_register will set table as the new value of the global of the given
|
||||||
|
* name. luaW_setfuncs is identical to luaW_register, but it does not set the
|
||||||
|
* table globally. As with luaL_register and luaL_setfuncs, both funcstions
|
||||||
|
* leave the new table on the top of the stack.
|
||||||
|
*/
|
||||||
|
template <typename T> void luaW_setfuncs(lua_State* _L,
|
||||||
|
const char* _classname,
|
||||||
|
const luaL_Reg* _table,
|
||||||
|
const luaL_Reg* _metatable,
|
||||||
|
T* (*_allocator)(lua_State*) = luaW_defaultallocator<T>,
|
||||||
|
void (*_deallocator)(lua_State*, T*) = luaW_defaultdeallocator<T>,
|
||||||
|
void (*_identifier)(lua_State*, T*) = luaW_defaultidentifier<T>) {
|
||||||
|
luaW_initialize(_L);
|
||||||
|
LuaWrapper<T>::classname = _classname;
|
||||||
|
LuaWrapper<T>::identifier = _identifier;
|
||||||
|
LuaWrapper<T>::allocator = _allocator;
|
||||||
|
LuaWrapper<T>::deallocator = _deallocator;
|
||||||
|
const luaL_Reg defaulttable[] = {
|
||||||
|
{ "new", luaW_new<T> },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
const luaL_Reg defaultmetatable[] = {
|
||||||
|
{ "__index", luaW_index<T> },
|
||||||
|
{ "__newindex", luaW_newindex<T> },
|
||||||
|
{ "__gc", luaW_gc<T> },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
// Set up per-type tables
|
||||||
|
lua_getfield(_L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... LuaWrapper
|
||||||
|
lua_getfield(_L, -1, LUAW_STORAGE_KEY); // ... LuaWrapper LuaWrapper.storage
|
||||||
|
lua_newtable(_L); // ... LuaWrapper LuaWrapper.storage {}
|
||||||
|
lua_setfield(_L, -2, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.storage
|
||||||
|
lua_pop(_L, 1); // ... LuaWrapper
|
||||||
|
lua_getfield(_L, -1, LUAW_HOLDS_KEY); // ... LuaWrapper LuaWrapper.holds
|
||||||
|
lua_newtable(_L); // ... LuaWrapper LuaWrapper.holds {}
|
||||||
|
lua_setfield(_L, -2, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.holds
|
||||||
|
lua_pop(_L, 1); // ... LuaWrapper
|
||||||
|
lua_getfield(_L, -1, LUAW_CACHE_KEY); // ... LuaWrapper LuaWrapper.cache
|
||||||
|
lua_newtable(_L); // ... LuaWrapper LuaWrapper.cache {}
|
||||||
|
luaW_wrapperfield<T>(_L, LUAW_CACHE_METATABLE_KEY); // ... LuaWrapper LuaWrapper.cache {} cmt
|
||||||
|
lua_setmetatable(_L, -2); // ... LuaWrapper LuaWrapper.cache {}
|
||||||
|
lua_setfield(_L, -2, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.cache
|
||||||
|
lua_pop(_L, 2); // ...
|
||||||
|
// Open table
|
||||||
|
lua_newtable(_L); // ... T
|
||||||
|
luaW_registerfuncs(_L, _allocator ? defaulttable : NULL, _table); // ... T
|
||||||
|
// Open metatable, set up extends table
|
||||||
|
luaL_newmetatable(_L, _classname); // ... T mt
|
||||||
|
lua_newtable(_L); // ... T mt {}
|
||||||
|
lua_setfield(_L, -2, LUAW_EXTENDS_KEY); // ... T mt
|
||||||
|
luaW_registerfuncs(_L, defaultmetatable, _metatable); // ... T mt
|
||||||
|
lua_setfield(_L, -2, "metatable"); // ... T
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void luaW_register(lua_State* _L,
|
||||||
|
const char* _classname,
|
||||||
|
const luaL_Reg* _table,
|
||||||
|
const luaL_Reg* _metatable,
|
||||||
|
T* (*_allocator)(lua_State*) = luaW_defaultallocator<T>,
|
||||||
|
void (*_deallocator)(lua_State*, T*) = luaW_defaultdeallocator<T>,
|
||||||
|
void (*_identifier)(lua_State*, T*) = luaW_defaultidentifier<T>) {
|
||||||
|
luaW_setfuncs(_L, _classname, _table, _metatable, _allocator, _deallocator, _identifier); // ... T
|
||||||
|
lua_pushvalue(_L, -1); // ... T T
|
||||||
|
lua_setglobal(_L, _classname); // ... T
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* luaW_extend is used to declare that class T inherits from class U. All
|
||||||
|
* functions in the base class will be available to the derived class (except
|
||||||
|
* when they share a function name, in which case the derived class's function
|
||||||
|
* wins). This also allows luaW_to<T> to cast your object apropriately, as
|
||||||
|
* casts straight through a void pointer do not work.
|
||||||
|
*/
|
||||||
|
template <typename T, typename U> void luaW_extend(lua_State* _L) {
|
||||||
|
if(!LuaWrapper<T>::classname) {
|
||||||
|
luaL_error(_L, "attempting to call extend on a type that has not been registered");
|
||||||
|
}
|
||||||
|
if(!LuaWrapper<U>::classname) {
|
||||||
|
luaL_error(_L, "attempting to extend %s by a type that has not been registered", LuaWrapper<T>::classname);
|
||||||
|
}
|
||||||
|
LuaWrapper<T>::cast = luaW_cast<T, U>;
|
||||||
|
LuaWrapper<T>::identifier = luaW_identify<T, U>;
|
||||||
|
LuaWrapper<T>::postconstructorrecurse = luaW_postconstructorinternal<U>;
|
||||||
|
luaL_getmetatable(_L, LuaWrapper<T>::classname); // mt
|
||||||
|
luaL_getmetatable(_L, LuaWrapper<U>::classname); // mt emt
|
||||||
|
// Point T's metatable __index at U's metatable for inheritance
|
||||||
|
lua_newtable(_L); // mt emt {}
|
||||||
|
lua_pushvalue(_L, -2); // mt emt {} emt
|
||||||
|
lua_setfield(_L, -2, "__index"); // mt emt {}
|
||||||
|
lua_setmetatable(_L, -3); // mt emt
|
||||||
|
// Set up per-type tables to point at parent type
|
||||||
|
lua_getfield(_L, LUA_REGISTRYINDEX, LUAW_WRAPPER_KEY); // ... LuaWrapper
|
||||||
|
lua_getfield(_L, -1, LUAW_STORAGE_KEY); // ... LuaWrapper LuaWrapper.storage
|
||||||
|
lua_getfield(_L, -1, LuaWrapper<U>::classname); // ... LuaWrapper LuaWrapper.storage U
|
||||||
|
lua_setfield(_L, -2, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.storage
|
||||||
|
lua_pop(_L, 1); // ... LuaWrapper
|
||||||
|
lua_getfield(_L, -1, LUAW_HOLDS_KEY); // ... LuaWrapper LuaWrapper.holds
|
||||||
|
lua_getfield(_L, -1, LuaWrapper<U>::classname); // ... LuaWrapper LuaWrapper.holds U
|
||||||
|
lua_setfield(_L, -2, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.holds
|
||||||
|
lua_pop(_L, 1); // ... LuaWrapper
|
||||||
|
lua_getfield(_L, -1, LUAW_CACHE_KEY); // ... LuaWrapper LuaWrapper.cache
|
||||||
|
lua_getfield(_L, -1, LuaWrapper<U>::classname); // ... LuaWrapper LuaWrapper.cache U
|
||||||
|
lua_setfield(_L, -2, LuaWrapper<T>::classname); // ... LuaWrapper LuaWrapper.cache
|
||||||
|
lua_pop(_L, 2); // ...
|
||||||
|
// Make a list of all types that inherit from U, for type checking
|
||||||
|
lua_getfield(_L, -2, LUAW_EXTENDS_KEY); // mt emt mt.extends
|
||||||
|
lua_pushvalue(_L, -2); // mt emt mt.extends emt
|
||||||
|
lua_setfield(_L, -2, LuaWrapper<U>::classname); // mt emt mt.extends
|
||||||
|
lua_getfield(_L, -2, LUAW_EXTENDS_KEY); // mt emt mt.extends emt.extends
|
||||||
|
for (lua_pushnil(_L); lua_next(_L, -2); lua_pop(_L, 1)) {
|
||||||
|
// mt emt mt.extends emt.extends k v
|
||||||
|
lua_pushvalue(_L, -2); // mt emt mt.extends emt.extends k v k
|
||||||
|
lua_pushvalue(_L, -2); // mt emt mt.extends emt.extends k v k
|
||||||
|
lua_rawset(_L, -6); // mt emt mt.extends emt.extends k v
|
||||||
|
}
|
||||||
|
lua_pop(_L, 4); // mt emt
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
737
luaWrapper/luaWrapperUtil.hpp
Normal file
737
luaWrapper/luaWrapperUtil.hpp
Normal file
@ -0,0 +1,737 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2013 Alexander Ames
|
||||||
|
* Alexander.Ames@gmail.com
|
||||||
|
* See Copyright Notice at the end of this file
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** API Summary:
|
||||||
|
*
|
||||||
|
* This is a set of utility functions that add to the functionalit of
|
||||||
|
* LuaWrapper. Over time I found myself repeating a few patterns, such as
|
||||||
|
* writing many trvial getter and setter functions, and wanting pass ownership
|
||||||
|
* of one object to another and have the Lua script properly handle that case.
|
||||||
|
*
|
||||||
|
* This file contains the additional functions that I've added but that do
|
||||||
|
* not really belong in the core API.
|
||||||
|
*/
|
||||||
|
#ifndef __LUA__WRAPPER__UTILS_HPP__
|
||||||
|
#define __LUA__WRAPPER__UTILS_HPP__
|
||||||
|
|
||||||
|
#include <luaWrapper/luaWrapper.hpp>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#ifndef LUAW_STD
|
||||||
|
#define LUAW_STD std
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This template removes reference and const qualifier from the type
|
||||||
|
*/
|
||||||
|
template <typename T> struct luaW_remove_cr {
|
||||||
|
typedef typename std::remove_const<typename std::remove_reference<T>::type>::type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of templated luaL_check and lua_push functions for use in the getters
|
||||||
|
* and setters below
|
||||||
|
*
|
||||||
|
* It is often useful to override luaU_check, luaU_to and/or luaU_push to
|
||||||
|
* operate on your own simple types rather than register your type with
|
||||||
|
* LuaWrapper, especially with small objects.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename U, typename = void> struct luaU_Impl {
|
||||||
|
static U luaU_check(lua_State* _L, int _index);
|
||||||
|
static U luaU_to(lua_State* _L, int _index);
|
||||||
|
static void luaU_push(lua_State* _L, const U& _value);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename U> U luaU_check(lua_State* _L, int _index) {
|
||||||
|
return luaU_Impl<U>::luaU_check(_L, _index);
|
||||||
|
}
|
||||||
|
template<typename U> U luaU_to(lua_State* _L, int _index) {
|
||||||
|
return luaU_Impl<U>::luaU_to(_L, _index);
|
||||||
|
}
|
||||||
|
template<typename U> void luaU_push(lua_State* _L, const U& _value) {
|
||||||
|
luaU_Impl<U>::luaU_push(_L, _value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This is slightly different than the previous three functions in that you
|
||||||
|
* shouldn't need to write your own version of it, since it uses luaU_check
|
||||||
|
* automatically.
|
||||||
|
*/
|
||||||
|
template<typename U> U luaU_opt(lua_State* _L, int _index, const U& _fallback = U()) {
|
||||||
|
if (lua_isnil(_L, _index))
|
||||||
|
return _fallback;
|
||||||
|
else
|
||||||
|
return luaU_Impl<U>::luaU_check(_L, _index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> struct luaU_Impl<bool> {
|
||||||
|
static bool luaU_check(lua_State* _L, int _index) {
|
||||||
|
return lua_toboolean(_L, _index) != 0;
|
||||||
|
}
|
||||||
|
static bool luaU_to(lua_State* _L, int _index) {
|
||||||
|
return lua_toboolean(_L, _index) != 0;
|
||||||
|
}
|
||||||
|
static void luaU_push(lua_State* _L, const bool& _value) {
|
||||||
|
lua_pushboolean(_L, _value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct luaU_Impl<const char*> {
|
||||||
|
static const char* luaU_check(lua_State* _L, int _index) {
|
||||||
|
return luaL_checkstring(_L, _index);
|
||||||
|
}
|
||||||
|
static const char* luaU_to(lua_State* _L, int _index) {
|
||||||
|
return lua_tostring(_L, _index);
|
||||||
|
}
|
||||||
|
static void luaU_push(lua_State* _L, const char* const& _value) {
|
||||||
|
lua_pushstring(_L, _value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct luaU_Impl<unsigned int> {
|
||||||
|
static unsigned int luaU_check(lua_State* _L, int _index) {
|
||||||
|
return static_cast<unsigned int>(luaL_checkinteger(_L, _index));
|
||||||
|
}
|
||||||
|
static unsigned int luaU_to(lua_State* _L, int _index) {
|
||||||
|
return static_cast<unsigned int>(lua_tointeger(_L, _index));
|
||||||
|
}
|
||||||
|
static void luaU_push(lua_State* _L, const unsigned int& _value) {
|
||||||
|
lua_pushinteger(_L, _value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct luaU_Impl<int> {
|
||||||
|
static int luaU_check(lua_State* _L, int _index) {
|
||||||
|
return static_cast<int>(luaL_checkinteger(_L, _index));
|
||||||
|
}
|
||||||
|
static int luaU_to(lua_State* _L, int _index) {
|
||||||
|
return static_cast<int>(lua_tointeger(_L, _index));
|
||||||
|
}
|
||||||
|
static void luaU_push(lua_State* _L, const int& _value) {
|
||||||
|
lua_pushinteger(_L, _value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct luaU_Impl<unsigned char> {
|
||||||
|
static unsigned char luaU_check(lua_State* _L, int _index) {
|
||||||
|
return static_cast<unsigned char>(luaL_checkinteger(_L, _index));
|
||||||
|
}
|
||||||
|
static unsigned char luaU_to(lua_State* _L, int _index) {
|
||||||
|
return static_cast<unsigned char>(lua_tointeger(_L, _index));
|
||||||
|
}
|
||||||
|
static void luaU_push(lua_State* _L, const unsigned char& _value) {
|
||||||
|
lua_pushinteger(_L, _value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct luaU_Impl<char> {
|
||||||
|
static char luaU_check(lua_State* _L, int _index) {
|
||||||
|
return static_cast<char>(luaL_checkinteger(_L, _index));
|
||||||
|
}
|
||||||
|
static char luaU_to(lua_State* _L, int _index) {
|
||||||
|
return static_cast<char>(lua_tointeger(_L, _index));
|
||||||
|
}
|
||||||
|
static void luaU_push(lua_State* _L, const char& _value) {
|
||||||
|
lua_pushinteger(_L, _value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct luaU_Impl<float> {
|
||||||
|
static float luaU_check(lua_State* _L, int _index) {
|
||||||
|
return static_cast<float>(luaL_checknumber(_L, _index));
|
||||||
|
}
|
||||||
|
static float luaU_to(lua_State* _L, int _index) {
|
||||||
|
return static_cast<float>(lua_tonumber(_L, _index));
|
||||||
|
}
|
||||||
|
static void luaU_push(lua_State* _L, const float& _value) {
|
||||||
|
lua_pushnumber(_L, _value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct luaU_Impl<double> {
|
||||||
|
static double luaU_check(lua_State* _L, int _index) {
|
||||||
|
return static_cast<double>(luaL_checknumber(_L, _index));
|
||||||
|
}
|
||||||
|
static double luaU_to(lua_State* _L, int _index) {
|
||||||
|
return static_cast<double>(lua_tonumber(_L, _index));
|
||||||
|
}
|
||||||
|
static void luaU_push(lua_State* _L, const double& _value) {
|
||||||
|
lua_pushnumber(_L, _value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> struct luaU_Impl<T, typename LUAW_STD::enable_if<LUAW_STD::is_enum<T>::value>::type> {
|
||||||
|
static T luaU_check(lua_State* _L, int _index) {
|
||||||
|
return static_cast<T>(luaL_checkinteger(_L, _index));
|
||||||
|
}
|
||||||
|
static T luaU_to(lua_State* _L, int _index) {
|
||||||
|
return static_cast<T>(lua_tointeger(_L, _index));
|
||||||
|
}
|
||||||
|
static void luaU_push(lua_State* _L, const T& _value) {
|
||||||
|
lua_pushnumber(_L, static_cast<int>(_value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> struct luaU_Impl<T*, typename LUAW_STD::enable_if<LUAW_STD::is_class<T>::value>::type> {
|
||||||
|
static T* luaU_check(lua_State* _L, int _index) {
|
||||||
|
return luaW_check<T>(_L, _index);
|
||||||
|
}
|
||||||
|
static T* luaU_to(lua_State* _L, int _index) {
|
||||||
|
return luaW_to<T>(_L, _index);
|
||||||
|
}
|
||||||
|
static void luaU_push(lua_State* _L, T*& _value) {
|
||||||
|
luaW_push <T>(_L, _value);
|
||||||
|
}
|
||||||
|
static void luaU_push(lua_State* _L, T* _value) {
|
||||||
|
luaW_push <T>(_L, _value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These are just some functions I've always felt should exist
|
||||||
|
*/
|
||||||
|
template <typename U> inline U luaU_getfield(lua_State* _L, int _index, const char* _field) {
|
||||||
|
static_assert(!LUAW_STD::is_same<U, const char*>::value,
|
||||||
|
"luaU_getfield is not safe to use on const char*'s. (The string will be popped from the stack.)");
|
||||||
|
lua_getfield(_L, _index, _field);
|
||||||
|
U val = luaU_to<U>(_L, -1);
|
||||||
|
lua_pop(_L, 1);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> inline U luaU_checkfield(lua_State* _L, int _index, const char* _field) {
|
||||||
|
static_assert(!LUAW_STD::is_same<U, const char*>::value,
|
||||||
|
"luaU_checkfield is not safe to use on const char*'s. (The string will be popped from the stack.)");
|
||||||
|
lua_getfield(_L, _index, _field);
|
||||||
|
U val = luaU_check<U>(_L, -1);
|
||||||
|
lua_pop(_L, 1);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> inline U luaU_optfield(lua_State* _L, int _index, const char* _field, const U& _fallback = U()) {
|
||||||
|
static_assert(!LUAW_STD::is_same<U, const char*>::value,
|
||||||
|
"luaU_getfield is not safe to use on const char*'s. (The string will be popped from the stack.)");
|
||||||
|
lua_getfield(_L, _index, _field);
|
||||||
|
U val = luaU_opt<U>(_L, -1, _fallback);
|
||||||
|
lua_pop(_L, 1);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> inline void luaU_setfield(lua_State* _L, int _index, const char* _field, U _val) {
|
||||||
|
luaU_push<U>(_L, _val);
|
||||||
|
lua_setfield(_L, luaW_correctindex(_L, _index, 1), _field);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A set of trivial getter and setter templates. These templates are designed
|
||||||
|
* to call trivial getters or setters.
|
||||||
|
*
|
||||||
|
* There are four forms:
|
||||||
|
* 1. Getting or setting a public member variable that is of a primitive type
|
||||||
|
* 2. Getting or setting a public member variable that is a pointer to an
|
||||||
|
* object
|
||||||
|
* 3. Getting or setting a private member variable that is of a primitive type
|
||||||
|
* through a getter or setter
|
||||||
|
* 3. Getting or setting a private member variable that is is a pointer to an
|
||||||
|
* object through a getter or setter
|
||||||
|
*
|
||||||
|
* The interface to all of them is the same however. In addition to plain
|
||||||
|
* getter and setter functions, there is a getset which does both - if an
|
||||||
|
* argument is supplied it attempts to set the value, and in either case it
|
||||||
|
* returns the value. In your lua table declaration in C++ rather than write
|
||||||
|
* individiual wrappers for each getter and setter you may do the following:
|
||||||
|
*
|
||||||
|
* static luaL_reg Foo_metatable[] =
|
||||||
|
* {
|
||||||
|
* { "GetBar", luaU_get<Foo, bool, &Widget::GetBar> },
|
||||||
|
* { "SetBar", luaU_set<Foo, bool, &Widget::SetBar> },
|
||||||
|
* { "Bar", luaU_getset<Foo, bool, &Widget::GetBar, &Widget::SetBar> },
|
||||||
|
* { NULL, NULL }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Getters and setters must have one of the following signatures:
|
||||||
|
* void T::Setter(U _value);
|
||||||
|
* void T::Setter(U* _value);
|
||||||
|
* void T::Setter(const U& _value);
|
||||||
|
* U Getter() const;
|
||||||
|
* U* Getter() const;
|
||||||
|
*
|
||||||
|
* In this example, the variable Foo::bar is private and so it is accessed
|
||||||
|
* through getter and setter functions. If Foo::bar were public, it could be
|
||||||
|
* accessed directly, like so:
|
||||||
|
*
|
||||||
|
* static luaL_reg Foo_metatable[] =
|
||||||
|
* {
|
||||||
|
* { "GetBar", luaU_get<Foo, bool, &Widget::bar> },
|
||||||
|
* { "SetBar", luaU_set<Foo, bool, &Widget::bar> },
|
||||||
|
* { "Bar", luaU_getset<Foo, bool, &Widget::bar> },
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* In a Lua script, you can now use foo:GetBar(), foo:SetBar() and foo:Bar()
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <typename T, typename U, U T::*Member> int luaU_get(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
luaU_push<U>(_L, obj->*Member);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, U* T::*Member> int luaU_get(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
luaW_push<U>(_L, obj->*Member);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, U (T::*Getter)() const> int luaU_get(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
luaU_push<U>(_L, (obj->*Getter)());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, const U& (T::*Getter)() const> int luaU_get(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
luaU_push<U>(_L, (obj->*Getter)());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, U* (T::*Getter)() const> int luaU_get(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
luaW_push<U>(_L, (obj->*Getter)());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, U T::*Member> int luaU_set(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj) {
|
||||||
|
obj->*Member = luaU_check<U>(_L, 2);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, U* T::*Member> int luaU_set(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj) {
|
||||||
|
U* member = luaW_opt<U>(_L, 2);
|
||||||
|
obj->*Member = member;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, const U* T::*Member> int luaU_set(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj) {
|
||||||
|
U* member = luaW_opt<U>(_L, 2);
|
||||||
|
obj->*Member = member;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, const U* T::*Member> int luaU_setandrelease(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj) {
|
||||||
|
U* member = luaW_opt<U>(_L, 2);
|
||||||
|
obj->*Member = member;
|
||||||
|
if (member) {
|
||||||
|
luaW_release<U>(_L, member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, void (T::*Setter)(U)> int luaU_set(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj) {
|
||||||
|
(obj->*Setter)(luaU_check<U>(_L, 2));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, void (T::*Setter)(const U&)> int luaU_set(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj) {
|
||||||
|
(obj->*Setter)(luaU_check<U>(_L, 2));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, void (T::*Setter)(U*)> int luaU_set(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj) {
|
||||||
|
U* member = luaW_opt<U>(_L, 2);
|
||||||
|
(obj->*Setter)(member);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, void (T::*Setter)(U*)> int luaU_setandrelease(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj) {
|
||||||
|
U* member = luaW_opt<U>(_L, 2);
|
||||||
|
(obj->*Setter)(member);
|
||||||
|
if (member) {
|
||||||
|
luaW_release<U>(_L, member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, U T::*Member> int luaU_getset(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj && lua_gettop(_L) >= 2) {
|
||||||
|
obj->*Member = luaU_check<U>(_L, 2);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
luaU_push<U>(_L, obj->*Member);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, U* T::*Member> int luaU_getset(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj && lua_gettop(_L) >= 2) {
|
||||||
|
U* member = luaW_opt<U>(_L, 2);
|
||||||
|
obj->*Member = member;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
luaW_push<U>(_L, obj->*Member);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, U* T::*Member> int luaU_getsetandrelease(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj && lua_gettop(_L) >= 2) {
|
||||||
|
U* member = luaW_opt<U>(_L, 2);
|
||||||
|
obj->*Member = member;
|
||||||
|
if (member)
|
||||||
|
luaW_release<U>(_L, member);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
luaW_push<U>(_L, obj->*Member);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, U (T::*Getter)() const, void (T::*Setter)(U)> int luaU_getset(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj && lua_gettop(_L) >= 2) {
|
||||||
|
(obj->*Setter)(luaU_check<U>(_L, 2));
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
luaU_push<U>(_L, (obj->*Getter)());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, U (T::*Getter)() const, void (T::*Setter)(const U&)> int luaU_getset(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj && lua_gettop(_L) >= 2) {
|
||||||
|
(obj->*Setter)(luaU_check<U>(_L, 2));
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
luaU_push<U>(_L, (obj->*Getter)());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, const U& (T::*Getter)() const, void (T::*Setter)(const U&)> int luaU_getset(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj && lua_gettop(_L) >= 2) {
|
||||||
|
(obj->*Setter)(luaU_check<U>(_L, 2));
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
luaU_push<U>(_L, (obj->*Getter)());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, U* (T::*Getter)() const, void (T::*Setter)(U*)> int luaU_getset(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj && lua_gettop(_L) >= 2) {
|
||||||
|
U* member = luaW_opt<U>(_L, 2);
|
||||||
|
(obj->*Setter)(member);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
luaW_push<U>(_L, (obj->*Getter)());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename U, U* (T::*Getter)() const, void (T::*Setter)(U*)> int luaU_getsetandrelease(lua_State* _L) {
|
||||||
|
T* obj = luaW_check<T>(_L, 1);
|
||||||
|
if (obj && lua_gettop(_L) >= 2) {
|
||||||
|
U* member = luaW_opt<U>(_L, 2);
|
||||||
|
(obj->*Setter)(member);
|
||||||
|
if (member)
|
||||||
|
luaW_release<U>(_L, member);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
luaW_push<U>(_L, (obj->*Getter)());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* luaU_func is a special macro that expands into a simple function wrapper.
|
||||||
|
* Unlike the getter setters above, you merely need to name the function you
|
||||||
|
* would like to wrap.
|
||||||
|
*
|
||||||
|
* For example,
|
||||||
|
*
|
||||||
|
* struct Foo
|
||||||
|
* {
|
||||||
|
* int DoSomething(int, const char*);
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* static luaL_reg Foo_metatable[] =
|
||||||
|
* {
|
||||||
|
* { "DoSomething", luaU_func(&Foo::DoSomething) },
|
||||||
|
* { NULL, NULL }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* void RegisterFoo(lua_State* L)
|
||||||
|
* {
|
||||||
|
* luaW_register<Foo>(L, "Foo", NULL, Foo_metatable);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* This macro will expand based on the function signature of Foo::DoSomething
|
||||||
|
* In this example, it would expand into the following wrapper:
|
||||||
|
*
|
||||||
|
* luaU_push(luaW_check<T>(L, 1)->DoSomething(luaU_check<int>(L, 2), luaU_check<const char*>(L, 3)));
|
||||||
|
* return 1;
|
||||||
|
*
|
||||||
|
* In this example there is only one member function called DoSomething. In some
|
||||||
|
* cases there may be multiple overrides for a function. For those cases, an
|
||||||
|
* additional macro has been provided, luaU_funcsig, which takes the entire
|
||||||
|
* function signature. The arguments to the macro reflect the order they would
|
||||||
|
* appear in the function signature: return type, type name, function name, and
|
||||||
|
* finally a list of all the argument types. For example:
|
||||||
|
*
|
||||||
|
* struct Foo
|
||||||
|
* {
|
||||||
|
* int DoSomething (const char*);
|
||||||
|
* int DoSomething (const char*, int);
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* const struct luaL_Reg Foo_metatable[] =
|
||||||
|
* {
|
||||||
|
* {"DoSomething1", luaU_funcsig(int, Foo, DoSomething, const char*)) },
|
||||||
|
* {"DoSomething1", luaU_funcsig(int, Foo, DoSomething, const char*, int)) },
|
||||||
|
* { NULL, NULL }
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* There`s also support for static and freestanding functions. Macros luaU_staticfunc
|
||||||
|
* and luaU_staticfuncsig work equally to luaU_func and luaU_funcsig, except for that
|
||||||
|
* you need to provide a separate metatable for static functions.
|
||||||
|
* For example,
|
||||||
|
*
|
||||||
|
* struct Foo
|
||||||
|
* {
|
||||||
|
* int DoSomething(int, const char*);
|
||||||
|
* static void DoSomethingElse(int a, int b, float c);
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* static luaL_reg Foo_metatable[] =
|
||||||
|
* {
|
||||||
|
* { "DoSomething", luaU_func(&Foo::DoSomething) },
|
||||||
|
* { NULL, NULL }
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* static luaL_reg Foo_metatable_static[] =
|
||||||
|
* {
|
||||||
|
* { "DoSomethingElse", luaU_staticfunc(&Foo::DoSomethingElse) },
|
||||||
|
* { NULL, NULL }
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* void RegisterFoo(lua_State* L)
|
||||||
|
* {
|
||||||
|
* luaW_register<Foo>(L, "Foo", Foo_metatable_static, Foo_metatable);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* After that you will be able to use Foo class from Lua like this:
|
||||||
|
* local foo = Foo.new()
|
||||||
|
* foo:DoSomething(42, 'The Ultimate Question of Life, the Universe, and Everything.') -- member function call
|
||||||
|
* Foo:DoSomethingElse(30, 12, 3.1459) -- Static function call
|
||||||
|
*
|
||||||
|
* These macros and it's underlying templates are somewhat experimental and some
|
||||||
|
* refinements are probably needed. There are cases where it does not
|
||||||
|
* currently work and I expect some changes can be made to refine its behavior.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define luaU_func(memberfunc) &luaU_MemberFuncWrapper<decltype(memberfunc),memberfunc>::call
|
||||||
|
#define luaU_funcsig(returntype, type, funcname, ...) luaU_func(static_cast<returntype (type::*)(__VA_ARGS__)>(&type::funcname))
|
||||||
|
|
||||||
|
#define luaU_staticfunc(func) &luaU_StaticFuncWrapper<decltype(func),func>::call
|
||||||
|
#define luaU_staticfuncsig(returntype, type, funcname, ...) luaU_staticfunc(static_cast<returntype (*)(__VA_ARGS__)>(&type::funcname))
|
||||||
|
|
||||||
|
template<int... ints> struct luaU_IntPack { };
|
||||||
|
template<int start, int count, int... tail> struct luaU_MakeIntRangeType {
|
||||||
|
typedef typename luaU_MakeIntRangeType<start, count-1, start+count-1, tail...>::type type;
|
||||||
|
};
|
||||||
|
template<int start, int... tail> struct luaU_MakeIntRangeType<start, 0, tail...> {
|
||||||
|
typedef luaU_IntPack<tail...> type;
|
||||||
|
};
|
||||||
|
template<int start, int count> inline typename luaU_MakeIntRangeType<start, count>::type luaU_makeIntRange() {
|
||||||
|
return typename luaU_MakeIntRangeType<start, count>::type();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Member function wrapper
|
||||||
|
*/
|
||||||
|
template<class MemFunPtrType, MemFunPtrType MemberFunc> struct luaU_MemberFuncWrapper;
|
||||||
|
|
||||||
|
template<class T, class ReturnType, class... Args, ReturnType(T::*MemberFunc)(Args...)> struct luaU_MemberFuncWrapper<ReturnType (T::*)(Args...), MemberFunc> {
|
||||||
|
public:
|
||||||
|
static int call(lua_State* _L) {
|
||||||
|
return callImpl(_L, luaU_makeIntRange<2,sizeof...(Args)>());
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
template<int... indices> static int callImpl(lua_State* _L, luaU_IntPack<indices...>) {
|
||||||
|
luaU_push<ReturnType>(_L, (luaW_check<T>(_L, 1)->*MemberFunc)(luaU_check<typename luaW_remove_cr<Args>::type>(_L, indices)...));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, class... Args, void(T::*MemberFunc)(Args...)> struct luaU_MemberFuncWrapper<void(T::*)(Args...), MemberFunc> {
|
||||||
|
public:
|
||||||
|
static int call(lua_State* _L) {
|
||||||
|
return callImpl(_L, luaU_makeIntRange<2, sizeof...(Args)>());
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
template<int... indices> static int callImpl(lua_State* _L, luaU_IntPack<indices...>) {
|
||||||
|
(luaW_check<T>(_L, 1)->*MemberFunc)(luaU_check<typename luaW_remove_cr<Args>::type>(_L, indices)...);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* static function wrapper
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<class FunPtrType, FunPtrType Func> struct luaU_StaticFuncWrapper;
|
||||||
|
|
||||||
|
template<class ReturnType, class... Args, ReturnType(*Func)(Args...)> struct luaU_StaticFuncWrapper<ReturnType(*)(Args...), Func> {
|
||||||
|
public:
|
||||||
|
static int call(lua_State* _L) {
|
||||||
|
return callImpl(_L, luaU_makeIntRange<2,sizeof...(Args)>());
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
template<int... indices> static int callImpl(lua_State* _L, luaU_IntPack<indices...>) {
|
||||||
|
luaU_push<ReturnType>(_L, (*Func)(luaU_check<typename luaW_remove_cr<Args>::type>(_L, indices)...));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class... Args, void(*Func)(Args...)> struct luaU_StaticFuncWrapper<void(*)(Args...), Func> {
|
||||||
|
public:
|
||||||
|
static int call(lua_State* _L) {
|
||||||
|
return callImpl(_L, luaU_makeIntRange<2, sizeof...(Args)>());
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
template<int... indices>
|
||||||
|
static int callImpl(lua_State* _L, luaU_IntPack<indices...>) {
|
||||||
|
(*Func)(luaU_check<typename luaW_remove_cr<Args>::type>(_L, indices)...);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls the copy constructor for an object of type T.
|
||||||
|
* Arguments may be passed in, in case they're needed for the postconstructor
|
||||||
|
*
|
||||||
|
* e.g.
|
||||||
|
*
|
||||||
|
* C++:
|
||||||
|
* luaL_reg Foo_Metatable[] =
|
||||||
|
* {
|
||||||
|
* { "clone", luaU_clone<Foo> },
|
||||||
|
* { NULL, NULL }
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* Lua:
|
||||||
|
* foo = Foo.new()
|
||||||
|
* foo2 = foo:clone()
|
||||||
|
*/
|
||||||
|
template <typename T> int luaU_clone(lua_State* _L) {
|
||||||
|
T* obj = new T(*luaW_check<T>(_L, 1));
|
||||||
|
lua_remove(_L, 1); // ...
|
||||||
|
int numargs = lua_gettop(_L);
|
||||||
|
luaW_push<T>(_L, obj); // ... clone
|
||||||
|
luaW_hold<T>(_L, obj);
|
||||||
|
luaW_postconstructor<T>(_L, numargs);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* luaU_build is intended to be used to initialize many values by passing in a
|
||||||
|
* table. They keys of the table are used as function names, and values are
|
||||||
|
* used as arguments to the function. This is intended to be used on functions
|
||||||
|
* that are simple setters.
|
||||||
|
*
|
||||||
|
* For example, if luaU_build is set as the post constructor, you can
|
||||||
|
* initialize an object as so:
|
||||||
|
*
|
||||||
|
* f = Foo.new
|
||||||
|
* {
|
||||||
|
* X = 10;
|
||||||
|
* Y = 20;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* After the object is constructed, luaU_build will do the equivalent of
|
||||||
|
* calling f:X(10) and f:Y(20).
|
||||||
|
*/
|
||||||
|
template <typename T> int luaU_build(lua_State* _L) {
|
||||||
|
// obj {}
|
||||||
|
lua_insert(_L, -2); // {} obj
|
||||||
|
if (lua_type(_L, 1) == LUA_TTABLE) {
|
||||||
|
for (lua_pushnil(_L); lua_next(_L, 1); lua_pop(_L, 1)) {
|
||||||
|
// {} obj k v
|
||||||
|
lua_pushvalue(_L, -2); // {} obj k v k
|
||||||
|
lua_gettable(_L, -4); // {} obj k v ud[k]
|
||||||
|
lua_pushvalue(_L, -4); // {} obj k v ud[k] ud
|
||||||
|
lua_pushvalue(_L, -3); // {} obj k v ud[k] ud v
|
||||||
|
lua_call(_L, 2, 0); // {} obj k v
|
||||||
|
}
|
||||||
|
// {} ud
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes the object of type T at the top of the stack and stores it in on a
|
||||||
|
* table with the name storagetable, on the table at the specified _index.
|
||||||
|
*
|
||||||
|
* You may manually call luaW_hold and luaW_release to handle pointer
|
||||||
|
* ownership, but it is often easier to simply store a Lua userdata on a table
|
||||||
|
* that is owned by its parent. This ensures that your object will not be
|
||||||
|
* prematurely freed, and that it can only be destoryed after its parent.
|
||||||
|
*
|
||||||
|
* e.g.
|
||||||
|
*
|
||||||
|
* Foo* parent = luaW_check<Foo>(_L, 1);
|
||||||
|
* Bar* child = luaW_check<Bar>(_L, 2);
|
||||||
|
* if (parent && child)
|
||||||
|
* {
|
||||||
|
* luaU_store<Bar>(_L, 1, "Children");
|
||||||
|
* parent->AddChild(child);
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
template <typename T> void luaU_store(lua_State* _L, int _index, const char* _storagetable, const char* _key = NULL) {
|
||||||
|
// ... store ... obj
|
||||||
|
lua_getfield(_L, _index, _storagetable); // ... store ... obj store.storagetable
|
||||||
|
if (_key) {
|
||||||
|
lua_pushstring(_L, _key); // ... store ... obj store.storagetable key
|
||||||
|
} else {
|
||||||
|
LuaWrapper<T>::identifier(_L, luaW_to<T>(_L, -2)); // ... store ... obj store.storagetable key
|
||||||
|
}
|
||||||
|
lua_pushvalue(_L, -3); // ... store ... obj store.storagetable key obj
|
||||||
|
lua_settable(_L, -3); // ... store ... obj store.storagetable
|
||||||
|
lua_pop(_L, 1); // ... store ... obj
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
21
lutin_luaWrapper.py
Normal file
21
lutin_luaWrapper.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import lutinModule as module
|
||||||
|
import lutinTools as tools
|
||||||
|
|
||||||
|
def get_desc():
|
||||||
|
return "luwWrapper : simple Lua automatic wrapper"
|
||||||
|
|
||||||
|
|
||||||
|
def create(target):
|
||||||
|
# module name is 'edn' and type binary.
|
||||||
|
myModule = module.Module(__file__, 'luaWrapper', 'LIBRARY')
|
||||||
|
|
||||||
|
# name of the dependency
|
||||||
|
myModule.add_module_depend('lua')
|
||||||
|
|
||||||
|
myModule.add_export_path(tools.get_current_path(__file__))
|
||||||
|
|
||||||
|
# add the currrent module at the
|
||||||
|
return myModule
|
||||||
|
|
||||||
|
|
15
sample/README
Normal file
15
sample/README
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
LuaWrapperExample
|
||||||
|
Copyright (c) 2010-2013 Alexander Ames
|
||||||
|
Alexander.Ames@gmail.com
|
||||||
|
|
||||||
|
This repository is a very simple example of how you can use LuaWrapper to
|
||||||
|
create typesafe bindings between Lua and C++. This is not a complete tutorial,
|
||||||
|
but rather just a quick project to illustrate how the library is used.
|
||||||
|
Specifically, it does not cover the hold, release or clean functions.
|
||||||
|
|
||||||
|
See the README functions in ./example1/ and ./example2/ for more information.
|
||||||
|
|
||||||
|
The main repository for LuaWrapper can be found at
|
||||||
|
|
||||||
|
https://bitbucket.org/alexames/luawrapper/
|
||||||
|
|
32
sample/example1/BankAccount.cpp
Normal file
32
sample/example1/BankAccount.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "BankAccount.hpp"
|
||||||
|
|
||||||
|
float BankAccount::s_totalMoneyInBank = 0;
|
||||||
|
|
||||||
|
BankAccount::BankAccount(const char* _owner, float _balance) :
|
||||||
|
m_owner(_owner) ,
|
||||||
|
m_balance(_balance) {
|
||||||
|
s_totalMoneyInBank += _balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* BankAccount::getOwnerName() const {
|
||||||
|
return m_owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BankAccount::deposit(float _amount) {
|
||||||
|
s_totalMoneyInBank += _amount;
|
||||||
|
m_balance += _amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BankAccount::withdraw(float _amount) {
|
||||||
|
s_totalMoneyInBank -= _amount;
|
||||||
|
m_balance -= _amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BankAccount::checkBalance() const {
|
||||||
|
return m_balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
float BankAccount::checkTotalMoneyInBank() {
|
||||||
|
return s_totalMoneyInBank;
|
||||||
|
}
|
||||||
|
|
21
sample/example1/BankAccount.hpp
Normal file
21
sample/example1/BankAccount.hpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef EXAMPLE_HPP_
|
||||||
|
#define EXAMPLE_HPP_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class BankAccount {
|
||||||
|
public:
|
||||||
|
BankAccount(const char* _owner, float _balance);
|
||||||
|
const char* getOwnerName() const;
|
||||||
|
void deposit(float _amount);
|
||||||
|
void withdraw(float _amount);
|
||||||
|
float checkBalance() const;
|
||||||
|
static float checkTotalMoneyInBank();
|
||||||
|
private:
|
||||||
|
const char* m_owner;
|
||||||
|
float m_balance;
|
||||||
|
static float s_totalMoneyInBank;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EXAMPLE_HPP_
|
93
sample/example1/LuaBankAccount.cpp
Normal file
93
sample/example1/LuaBankAccount.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <lua/lua.h>
|
||||||
|
#include <lua/lauxlib.h>
|
||||||
|
#include <luaWrapper/luaWrapper.hpp>
|
||||||
|
|
||||||
|
#include "BankAccount.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocator
|
||||||
|
*
|
||||||
|
* Types that do not have a default contructor require you to write an allocator function.
|
||||||
|
* This function is passed to luaW_register.
|
||||||
|
*/
|
||||||
|
|
||||||
|
BankAccount* BankAccount_new(lua_State *_L) {
|
||||||
|
const char* owner = luaL_checkstring(_L, 1);
|
||||||
|
float balance = luaL_checknumber(_L, 2);
|
||||||
|
return new BankAccount(owner, balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static Functions
|
||||||
|
*
|
||||||
|
* These functions can be called directly from the BankAccount table in lua
|
||||||
|
*/
|
||||||
|
|
||||||
|
int BankAccount_checkTotalMoneyInBank(lua_State *_L) {
|
||||||
|
lua_pushnumber(_L, BankAccount::checkTotalMoneyInBank());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Member Functions
|
||||||
|
*
|
||||||
|
* These functions are stored on the BankAccount.metatable table.
|
||||||
|
* All BankAccount objects in Lua have access to the functions defined there
|
||||||
|
* by the use of special a __index metatmethod that is set up by LuaWrapper.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int BankAccount_getOwnerName(lua_State *_L) {
|
||||||
|
BankAccount* account = luaW_check<BankAccount>(_L, 1);
|
||||||
|
lua_pushstring(_L, account->getOwnerName());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BankAccount_deposit(lua_State* _L) {
|
||||||
|
BankAccount* account = luaW_check<BankAccount>(_L, 1);
|
||||||
|
float amount = luaL_checknumber(_L, 2);
|
||||||
|
account->deposit(amount);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BankAccount_withdraw(lua_State* _L) {
|
||||||
|
BankAccount* account = luaW_check<BankAccount>(_L, 1);
|
||||||
|
float amount = luaL_checknumber(_L, 2);
|
||||||
|
account->withdraw(amount);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BankAccount_checkBalance(lua_State* _L) {
|
||||||
|
BankAccount* account = luaW_check<BankAccount>(_L, 1);
|
||||||
|
lua_pushnumber(_L, account->checkBalance());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static luaL_Reg BankAccount_table[] = {
|
||||||
|
{ "checkTotalMoneyInBank", BankAccount_checkTotalMoneyInBank },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static luaL_Reg BankAccount_metatable[] = {
|
||||||
|
{ "getOwnerName", BankAccount_getOwnerName },
|
||||||
|
{ "deposit", BankAccount_deposit },
|
||||||
|
{ "withdraw", BankAccount_withdraw },
|
||||||
|
{ "checkBalance", BankAccount_checkBalance },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
int luaopen_BankAccount(lua_State* _L) {
|
||||||
|
luaW_register<BankAccount>(_L,
|
||||||
|
"BankAccount",
|
||||||
|
BankAccount_table,
|
||||||
|
BankAccount_metatable,
|
||||||
|
BankAccount_new // If your class has a default constructor you can omit this argument,
|
||||||
|
// LuaWrapper will generate a default allocator for you.
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
7
sample/example1/LuaBankAccount.hpp
Normal file
7
sample/example1/LuaBankAccount.hpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef LUAEXAMPLE_HPP_
|
||||||
|
#define LUAEXAMPLE_HPP_
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
int luaopen_BankAccount(lua_State* _L);
|
||||||
|
|
||||||
|
#endif // LUAEXAMPLE_HPP_
|
3
sample/example1/Makefile
Normal file
3
sample/example1/Makefile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
all:
|
||||||
|
g++ -std=c++0x -L../lua-5.1/src -I../lua-5.1/src -I../luawrapper BankAccount.cpp LuaBankAccount.cpp main.cpp -llua -ldl -o example1
|
22
sample/example1/README
Normal file
22
sample/example1/README
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
This folder includes a simple project to demonstrate how LuaWrapper may be used
|
||||||
|
to bind your C++ class to Lua.
|
||||||
|
|
||||||
|
main.cpp contains a simple main function that will call luaopen_BankAccount
|
||||||
|
then run the script given.
|
||||||
|
|
||||||
|
BankAccount.cpp and BankAccount.hpp contain a simple BankAccount class which you
|
||||||
|
can use to deposit and withdraw money from, and check the current balance.
|
||||||
|
|
||||||
|
LuaBankAccount.cpp contains the function wrappers. This is where the interesting
|
||||||
|
part is.
|
||||||
|
|
||||||
|
A visual studio project and makefile are provided, or you can use your own
|
||||||
|
tool chain to compile the example. Once compiled, run
|
||||||
|
|
||||||
|
example1.exe example1.lua
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
./example1 example1.lua
|
||||||
|
|
||||||
|
to see the code in action.
|
22
sample/example1/example1.lua
Normal file
22
sample/example1/example1.lua
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
-- create a bank account and do some account action:
|
||||||
|
alicesaccount = BankAccount.new("Alice", 100)
|
||||||
|
alicesaccount:deposit(20);
|
||||||
|
alicesaccount:deposit(30);
|
||||||
|
alicesaccount:deposit(40);
|
||||||
|
|
||||||
|
bobsaccount = BankAccount.new("Bob", 200)
|
||||||
|
bobsaccount:withdraw(10);
|
||||||
|
bobsaccount:withdraw(15);
|
||||||
|
bobsaccount:withdraw(20);
|
||||||
|
|
||||||
|
-- create a function
|
||||||
|
function printaccountbalance(account)
|
||||||
|
local name = account:getOwnerName()
|
||||||
|
local balance = account:checkBalance()
|
||||||
|
print(string.format("%s has $%d", name, balance))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- print for debug :
|
||||||
|
printaccountbalance(alicesaccount)
|
||||||
|
printaccountbalance(bobsaccount)
|
||||||
|
print(string.format("The bank has $%d", BankAccount.checkTotalMoneyInBank()))
|
26
sample/example1/lutin_luaWrapperExample1.py
Normal file
26
sample/example1/lutin_luaWrapperExample1.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import lutinModule as module
|
||||||
|
import lutinTools as tools
|
||||||
|
|
||||||
|
def get_desc():
|
||||||
|
return "luaWrapper example 1 : simple lua wrapper"
|
||||||
|
|
||||||
|
def create(target):
|
||||||
|
# module name is 'edn' and type binary.
|
||||||
|
myModule = module.Module(__file__, 'luaWrapperExample1', 'BINARY')
|
||||||
|
# add extra compilation flags :
|
||||||
|
myModule.add_extra_compile_flags()
|
||||||
|
# add the file to compile:
|
||||||
|
myModule.add_src_file([
|
||||||
|
'BankAccount.cpp',
|
||||||
|
'LuaBankAccount.cpp',
|
||||||
|
'main.cpp'])
|
||||||
|
|
||||||
|
# name of the dependency
|
||||||
|
myModule.add_module_depend('luaWrapper')
|
||||||
|
|
||||||
|
|
||||||
|
# add the currrent module at the
|
||||||
|
return myModule
|
||||||
|
|
||||||
|
|
22
sample/example1/main.cpp
Normal file
22
sample/example1/main.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <lua/lua.h>
|
||||||
|
#include <lua/lualib.h>
|
||||||
|
#include <lua/lauxlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "LuaBankAccount.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main(int _argc, const char *_argv[]) {
|
||||||
|
if (_argc == 2) {
|
||||||
|
lua_State* L = luaL_newstate();
|
||||||
|
luaL_openlibs(L);
|
||||||
|
luaopen_BankAccount(L);
|
||||||
|
if (luaL_dofile(L, _argv[1])) {
|
||||||
|
std::cout << lua_tostring(L, -1) << std::endl;
|
||||||
|
}
|
||||||
|
lua_close(L);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
95
sample/example2/Example.cpp
Normal file
95
sample/example2/Example.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#include "Example.hpp"
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// These are just a bunch of generic getters and setters for
|
||||||
|
// values in the Example class
|
||||||
|
|
||||||
|
bool Example::GetBoolean() const {
|
||||||
|
return m_boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Example::GetInteger() const {
|
||||||
|
return m_integer;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Example::GetUInteger() const {
|
||||||
|
return m_uinteger;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* Example::GetCString() const {
|
||||||
|
return m_cstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& Example::GetCPPString() const {
|
||||||
|
return m_cppstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vector2D& Example::GetVec() const {
|
||||||
|
return m_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Example::GetNumber() const {
|
||||||
|
return m_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Example::GetFloatNumber() const {
|
||||||
|
return m_floatnumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
Example* Example::GetPtr() const {
|
||||||
|
return m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Example::SetBoolean(bool _val) {
|
||||||
|
m_boolean = _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Example::SetInteger(int _val) {
|
||||||
|
m_integer = _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Example::SetUInteger(unsigned int _val) {
|
||||||
|
m_uinteger = _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Example::SetCString(const char* _val) {
|
||||||
|
m_cstring = _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Example::SetCPPString(const std::string& _val) {
|
||||||
|
m_cppstring = _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Example::SetVec(const Vector2D& _val) {
|
||||||
|
m_vec = _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Example::SetNumber(double _val) {
|
||||||
|
m_number = _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Example::SetFloatNumber(float _val) {
|
||||||
|
m_floatnumber = _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Example::SetPtr(Example* _val) {
|
||||||
|
m_ptr = _val;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Example::DoSomething(bool _b) {
|
||||||
|
std::cout << "b = " << _b << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Example::DoSomethingElse(int _i, int _j) {
|
||||||
|
std::cout << "i = " << _i << ", j = " << _j << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Example::DoSomethingElse(float _f) {
|
||||||
|
std::cout << "f = " << _f << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
60
sample/example2/Example.hpp
Normal file
60
sample/example2/Example.hpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#ifndef EXAMPLE_HPP_
|
||||||
|
#define EXAMPLE_HPP_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Vector2D.hpp"
|
||||||
|
|
||||||
|
class Example {
|
||||||
|
public:
|
||||||
|
Example() :
|
||||||
|
m_boolean(),
|
||||||
|
m_integer(),
|
||||||
|
m_uinteger(),
|
||||||
|
m_cstring(""),
|
||||||
|
m_cppstring(""),
|
||||||
|
m_number(),
|
||||||
|
m_floatnumber(),
|
||||||
|
m_ptr(),
|
||||||
|
m_vec() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool m_boolean;
|
||||||
|
int m_integer;
|
||||||
|
unsigned int m_uinteger;
|
||||||
|
const char* m_cstring;
|
||||||
|
std::string m_cppstring;
|
||||||
|
double m_number;
|
||||||
|
float m_floatnumber;
|
||||||
|
Example* m_ptr;
|
||||||
|
Vector2D m_vec;
|
||||||
|
|
||||||
|
bool GetBoolean() const;
|
||||||
|
int GetInteger() const;
|
||||||
|
unsigned int GetUInteger() const;
|
||||||
|
const char* GetCString() const;
|
||||||
|
const std::string& GetCPPString() const;
|
||||||
|
double GetNumber() const;
|
||||||
|
float GetFloatNumber() const;
|
||||||
|
Example* GetPtr() const;
|
||||||
|
const Vector2D& GetVec() const;
|
||||||
|
|
||||||
|
void SetBoolean(bool _val);
|
||||||
|
void SetInteger(int _val);
|
||||||
|
void SetUInteger(unsigned int _val);
|
||||||
|
void SetCString(const char* _val);
|
||||||
|
void SetCPPString(const std::string& _val);
|
||||||
|
void SetNumber(double _val);
|
||||||
|
void SetFloatNumber(float _val);
|
||||||
|
void SetPtr(Example* _val);
|
||||||
|
void SetVec(const Vector2D& _Member);
|
||||||
|
|
||||||
|
int DoSomething(bool _b);
|
||||||
|
void DoSomething2(bool _b, int _p) {};
|
||||||
|
|
||||||
|
int DoSomethingElse(int _i, int _j);
|
||||||
|
int DoSomethingElse(float _f);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
60
sample/example2/LuaCustomTypes.hpp
Normal file
60
sample/example2/LuaCustomTypes.hpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#ifndef LUA_CUSTOM_TYPES_H__
|
||||||
|
#define LUA_CUSTOM_TYPES_H__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <lua/lua.h>
|
||||||
|
#include <luaWrapper/luaWrapper.hpp>
|
||||||
|
#include <luaWrapper/luaWrapperUtil.hpp>
|
||||||
|
|
||||||
|
#include "Vector2D.hpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LuaWrapper knows about primitive types like ints and floats, but it doesn't
|
||||||
|
* know about things like std::strings or other more complicated types.
|
||||||
|
* Sometimes, rather than register the type with LuaWrapper, it's easier to
|
||||||
|
* be able to convert it to and from Lua's primitive types, like strings or
|
||||||
|
* tables.
|
||||||
|
*
|
||||||
|
* To do this, you must write luaU_check, luaU_to and luaU_push functions for
|
||||||
|
* your type. You don't always need all three, it depends on if you're pushing
|
||||||
|
* objects to Lua, getting objects from Lua, or both.
|
||||||
|
*
|
||||||
|
* This example uses std::string, but if you have other custom string types it
|
||||||
|
* should be easy to write versions of those functions too
|
||||||
|
*/
|
||||||
|
template<> struct luaU_Impl<std::string> {
|
||||||
|
static std::string luaU_check(lua_State* _L, int _index) {
|
||||||
|
return std::string(luaL_checkstring(_L, _index));
|
||||||
|
}
|
||||||
|
static std::string luaU_to(lua_State* _L, int _index) {
|
||||||
|
return std::string(lua_tostring(_L, _index));
|
||||||
|
}
|
||||||
|
static void luaU_push(lua_State* _L, const std::string& _val) {
|
||||||
|
lua_pushstring(_L, _val.c_str());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These two functions let me convert a simple Vector2D structure into a Lua
|
||||||
|
* table holding the x and y values
|
||||||
|
*/
|
||||||
|
template<> struct luaU_Impl<Vector2D> {
|
||||||
|
static Vector2D luaU_check(lua_State* _L, int _index) {
|
||||||
|
return Vector2D(
|
||||||
|
luaU_getfield<float>(_L, _index, "x"),
|
||||||
|
luaU_getfield<float>(_L, _index, "y"));
|
||||||
|
}
|
||||||
|
static Vector2D luaU_to(lua_State* _L, int _index ) {
|
||||||
|
return Vector2D(
|
||||||
|
luaU_getfield<float>(_L, _index, "x"),
|
||||||
|
luaU_getfield<float>(_L, _index, "y"));
|
||||||
|
}
|
||||||
|
static void luaU_push(lua_State* _L, const Vector2D& _val) {
|
||||||
|
lua_newtable(_L);
|
||||||
|
luaU_setfield<float>(_L, -1, "x", _val.x);
|
||||||
|
luaU_setfield<float>(_L, -1, "y", _val.y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
140
sample/example2/LuaExample.cpp
Normal file
140
sample/example2/LuaExample.cpp
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <lua/lua.h>
|
||||||
|
|
||||||
|
#include <luaWrapper/luaWrapper.hpp>
|
||||||
|
#include <luaWrapper/luaWrapperUtil.hpp>
|
||||||
|
|
||||||
|
#include "LuaCustomTypes.hpp"
|
||||||
|
#include "Example.hpp"
|
||||||
|
|
||||||
|
static int Example_PrintMe(lua_State* L) {
|
||||||
|
Example* ex = luaW_check<Example>(L, 1);
|
||||||
|
std::cout << "Example="
|
||||||
|
<< "{m_boolean=" << ex->m_boolean
|
||||||
|
<< ",m_integer=" << ex->m_integer
|
||||||
|
<< ",m_uinteger=" << ex->m_uinteger
|
||||||
|
<< ",m_string='" << ex->m_cstring << "'"
|
||||||
|
<< ",m_cppstring='" << ex->m_cppstring << "'"
|
||||||
|
<< ",m_number=" << ex->m_number
|
||||||
|
<< ",m_floatnumber=" << ex->m_floatnumber
|
||||||
|
<< ",m_vec={x=" << ex->m_vec.x << ",y=" << ex->m_vec.y <<"}}" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static luaL_Reg Example_metatable[] = {
|
||||||
|
// This function is
|
||||||
|
{ "PrintMe", Example_PrintMe },
|
||||||
|
|
||||||
|
// In many cases, all you need are simple getter or setter functions This
|
||||||
|
// was such a common pattern for me that I wrote a huge set of templates
|
||||||
|
// that generate these getter and setter functions for me. This is an
|
||||||
|
// example of how they can be used
|
||||||
|
//
|
||||||
|
// Because everything in the Example class is marked public, you can access
|
||||||
|
// them directly with these templates.
|
||||||
|
//
|
||||||
|
// Class | data type | class member
|
||||||
|
{ "GetBoolean", luaU_get<Example, bool, &Example::m_boolean> },
|
||||||
|
{ "SetBoolean", luaU_set<Example, bool, &Example::m_boolean> },
|
||||||
|
{ "Boolean", luaU_getset<Example, bool, &Example::m_boolean> },
|
||||||
|
|
||||||
|
{ "GetInteger", luaU_get<Example, int, &Example::m_integer> },
|
||||||
|
{ "SetInteger", luaU_set<Example, int, &Example::m_integer> },
|
||||||
|
{ "Integer", luaU_getset<Example, int, &Example::m_integer> },
|
||||||
|
|
||||||
|
{ "GetUInteger", luaU_get<Example, unsigned int, &Example::m_uinteger> },
|
||||||
|
{ "SetUInteger", luaU_set<Example, unsigned int, &Example::m_uinteger> },
|
||||||
|
{ "UInteger", luaU_getset<Example, unsigned int, &Example::m_uinteger> },
|
||||||
|
|
||||||
|
{ "GetCString", luaU_get<Example, const char*, &Example::m_cstring> },
|
||||||
|
{ "SetCString", luaU_set<Example, const char*, &Example::m_cstring> },
|
||||||
|
{ "CString", luaU_getset<Example, const char*, &Example::m_cstring> },
|
||||||
|
|
||||||
|
{ "GetCPPString", luaU_get<Example, std::string, &Example::m_cppstring> },
|
||||||
|
{ "SetCPPString", luaU_set<Example, std::string, &Example::m_cppstring> },
|
||||||
|
{ "CPPString", luaU_getset<Example, std::string, &Example::m_cppstring> },
|
||||||
|
|
||||||
|
{ "GetVec", luaU_get<Example, Vector2D, &Example::m_vec> },
|
||||||
|
{ "SetVec", luaU_set<Example, Vector2D, &Example::m_vec> },
|
||||||
|
{ "Vec", luaU_getset<Example, Vector2D, &Example::m_vec> },
|
||||||
|
|
||||||
|
{ "GetNumber", luaU_get<Example, double, &Example::m_number> },
|
||||||
|
{ "SetNumber", luaU_set<Example, double, &Example::m_number> },
|
||||||
|
{ "Number", luaU_getset<Example, double, &Example::m_number> },
|
||||||
|
|
||||||
|
{ "GetFloatNumber", luaU_get<Example, float, &Example::m_floatnumber> },
|
||||||
|
{ "SetFloatNumber", luaU_set<Example, float, &Example::m_floatnumber> },
|
||||||
|
{ "FloatNumber", luaU_getset<Example, float, &Example::m_floatnumber> },
|
||||||
|
|
||||||
|
{ "GetPtr", luaU_get<Example, Example, &Example::m_ptr> },
|
||||||
|
{ "SetPtr", luaU_set<Example, Example, &Example::m_ptr> },
|
||||||
|
{ "Ptr", luaU_getset<Example, Example, &Example::m_ptr> },
|
||||||
|
|
||||||
|
// The getters and setters above work on member variables directly, but
|
||||||
|
// sometimes all you have are getter and setter functions instead of
|
||||||
|
// variables. You can still automate the creation of Getter and Setter Lua
|
||||||
|
// function wrappers.
|
||||||
|
|
||||||
|
// Normally it would be silly to have getter and setter functions for both
|
||||||
|
// the member variable AND the getter/setter function, I've included both
|
||||||
|
// here as an example of how it works
|
||||||
|
|
||||||
|
// Example of member access through getters and setters
|
||||||
|
// Class | data type | getter
|
||||||
|
// Class | data type | setter
|
||||||
|
// Class | data type | getter | setter
|
||||||
|
{ "GetBooleanFunc", luaU_get<Example, bool, &Example::GetBoolean> },
|
||||||
|
{ "SetBooleanFunc", luaU_set<Example, bool, &Example::SetBoolean> },
|
||||||
|
{ "BooleanFunc", luaU_getset<Example, bool, &Example::GetBoolean, &Example::SetBoolean> },
|
||||||
|
|
||||||
|
{ "GetIntegerFunc", luaU_get<Example, int, &Example::GetInteger> },
|
||||||
|
{ "SetIntegerFunc", luaU_set<Example, int, &Example::SetInteger> },
|
||||||
|
{ "IntegerFunc", luaU_getset<Example, int, &Example::GetInteger, &Example::SetInteger> },
|
||||||
|
|
||||||
|
{ "GetUIntegerFunc", luaU_get<Example, unsigned int, &Example::GetUInteger> },
|
||||||
|
{ "SetUIntegerFunc", luaU_set<Example, unsigned int, &Example::SetUInteger> },
|
||||||
|
{ "UIntegerFunc", luaU_getset<Example, unsigned int, &Example::GetUInteger, &Example::SetUInteger> },
|
||||||
|
|
||||||
|
{ "GetCStringFunc", luaU_get<Example, const char*, &Example::GetCString> },
|
||||||
|
{ "SetCStringFunc", luaU_set<Example, const char*, &Example::SetCString> },
|
||||||
|
{ "CStringFunc", luaU_getset<Example, const char*, &Example::GetCString, &Example::SetCString> },
|
||||||
|
|
||||||
|
{ "GetNumberFunc", luaU_get<Example, double, &Example::GetNumber> },
|
||||||
|
{ "SetNumberFunc", luaU_set<Example, double, &Example::SetNumber> },
|
||||||
|
{ "NumberFunc", luaU_getset<Example, double, &Example::GetNumber, &Example::SetNumber> },
|
||||||
|
|
||||||
|
{ "GetFloatNumberFunc", luaU_get<Example, float, &Example::GetFloatNumber> },
|
||||||
|
{ "SetFloatNumberFunc", luaU_set<Example, float, &Example::SetFloatNumber> },
|
||||||
|
{ "FloatNumberFunc", luaU_getset<Example, float, &Example::GetFloatNumber, &Example::SetFloatNumber> },
|
||||||
|
|
||||||
|
{ "GetPtrFunc", luaU_get<Example, Example, &Example::GetPtr> },
|
||||||
|
{ "SetPtrFunc", luaU_set<Example, Example, &Example::SetPtr> },
|
||||||
|
{ "PtrFunc", luaU_getset<Example, Example, &Example::GetPtr, &Example::SetPtr> },
|
||||||
|
|
||||||
|
// In order to use luaU_get and luaU_set on non-primitive types, you must define luaU_to
|
||||||
|
// and luaU_check for that type.
|
||||||
|
// See LuaCustomTypes.hpp for an example involving std::string and Vector2D
|
||||||
|
{ "GetCPPStringFunc", luaU_get<Example, std::string, &Example::GetCPPString> },
|
||||||
|
{ "SetCPPStringFunc", luaU_set<Example, std::string, &Example::SetCPPString> },
|
||||||
|
{ "CPPStringFunc", luaU_getset<Example, std::string, &Example::GetCPPString, &Example::SetCPPString> },
|
||||||
|
|
||||||
|
{ "GetVecFunc", luaU_get<Example, Vector2D, &Example::GetVec> },
|
||||||
|
{ "SetSetFunc", luaU_set<Example, Vector2D, &Example::SetVec> },
|
||||||
|
{ "VecFunc", luaU_getset<Example, Vector2D, &Example::GetVec, &Example::SetVec> },
|
||||||
|
|
||||||
|
{ "DoSomething", luaU_func(&Example::DoSomething) },
|
||||||
|
{ "DoSomething2", luaU_func(&Example::DoSomething2) },
|
||||||
|
|
||||||
|
//{ "DoSomethingElse1", luaU_funcsig(int, Example, DoSomethingElse, int, int) },
|
||||||
|
//{ "DoSomethingElse2", luaU_funcsig(int, Example, DoSomethingElse, float) },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
int luaopen_Example(lua_State* L)
|
||||||
|
{
|
||||||
|
luaW_register<Example>(L, "Example", NULL, Example_metatable);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
7
sample/example2/LuaExample.hpp
Normal file
7
sample/example2/LuaExample.hpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef LUAEXAMPLE_HPP_
|
||||||
|
#define LUAEXAMPLE_HPP_
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
int luaopen_Example(lua_State* _L);
|
||||||
|
|
||||||
|
#endif
|
3
sample/example2/Makefile
Normal file
3
sample/example2/Makefile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
all:
|
||||||
|
g++ -std=c++0x -L../lua-5.1/src -I../lua-5.1/src -I../luawrapper Example.cpp LuaExample.cpp main.cpp -llua -ldl -o example2
|
66
sample/example2/README
Normal file
66
sample/example2/README
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
This folder includes a project that demonstrates some of the more sophisticated
|
||||||
|
and complex features of LuaWrapper. Make sure you fully understand the code in
|
||||||
|
example 1 before reading the code here. Example 2 introduces some of the
|
||||||
|
features contained in the luawrapperutil.hpp file which are prefixed with luaU_
|
||||||
|
instead of luaW_
|
||||||
|
|
||||||
|
# Automatic Getter and Setter Generation
|
||||||
|
|
||||||
|
In example 1, all of the wrapper functions were written manually. It is very
|
||||||
|
common need to write get or set function wrappers - so common in fact that this
|
||||||
|
patter was extracted out into a templated function. In example 1, BankAccount
|
||||||
|
had the following wrapper:
|
||||||
|
|
||||||
|
int BankAccount_checkBalance(lua_State *L)
|
||||||
|
{
|
||||||
|
BankAccount* account = luaW_check<BankAccount>(L, 1);
|
||||||
|
lua_pushnumber(L, account->checkBalance());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static luaL_Reg BankAccount_metatable[] =
|
||||||
|
{
|
||||||
|
...
|
||||||
|
{ "checkBalance", BankAccount_checkBalance },
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
Rather than write code like that every time you need to create a get function,
|
||||||
|
you can instead just do this:
|
||||||
|
|
||||||
|
{ "checkBalance", luaU_get<BankAccount, float, &BankAccount::checkBalance },
|
||||||
|
|
||||||
|
This code will automatically instantiate a function wrapper that returns a
|
||||||
|
float, the result of a call to checkBalance.
|
||||||
|
|
||||||
|
# Generic push, to and check functions
|
||||||
|
|
||||||
|
Normally, when you need to push a value to Lua or get a value from the stack,
|
||||||
|
you use a function like lua_pushnumber or lua_tonumber. luawrapperutil.hpp
|
||||||
|
contains a generic version of these functions as well as specializations for
|
||||||
|
the primitive types in C++. That means you can do things like this:
|
||||||
|
|
||||||
|
int i = luaU_check<int>(L, 1);
|
||||||
|
luaU_push<double>(L, 1.234);
|
||||||
|
|
||||||
|
Additionally, it is possible to extend this functionality to non-primitive
|
||||||
|
types. A common use is to create a wrapper for std::strings so that you may do
|
||||||
|
this:
|
||||||
|
|
||||||
|
std::string str1 = luaU_check<std::string>(L, 1);
|
||||||
|
std::string str2 = "Lua is awesome!"
|
||||||
|
luaU_push<std::string>(L, str2);
|
||||||
|
|
||||||
|
Examples of how to create your own luaU_push, luaU_to, and luaU_check can be
|
||||||
|
found in LuaCustomTypes.hpp
|
||||||
|
|
||||||
|
A visual studio project and makefile are provided, or you can use your own
|
||||||
|
tool chain to compile the example. Once compiled, run
|
||||||
|
|
||||||
|
example2.exe example2.lua
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
./example2 example2.lua
|
||||||
|
|
||||||
|
to see the code in action.
|
14
sample/example2/Vector2D.hpp
Normal file
14
sample/example2/Vector2D.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef VECTOR2D_H_
|
||||||
|
#define VECTOR2D_H_
|
||||||
|
|
||||||
|
struct Vector2D {
|
||||||
|
Vector2D(float x_ = 0.f, float y_ = 0.f) :
|
||||||
|
x(x_),
|
||||||
|
y(y_) {
|
||||||
|
|
||||||
|
}
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
27
sample/example2/example2.lua
Normal file
27
sample/example2/example2.lua
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
local ex = Example.new()
|
||||||
|
|
||||||
|
ex:SetBoolean(true)
|
||||||
|
|
||||||
|
-- luaU_getset creates a function that acts as both a getter and a setter!
|
||||||
|
-- For example, I can use a single function, Integer, to set the value to 100
|
||||||
|
-- then print out that value
|
||||||
|
ex:Integer(100)
|
||||||
|
print("Integer = ", ex:Integer());
|
||||||
|
|
||||||
|
ex:SetCPPString("This will be automatically conveted into a std::string")
|
||||||
|
|
||||||
|
-- Because I've defined helper functions for Vector2D, I can pass this table
|
||||||
|
-- to a function expecting a Vector2d as an argument. I don't need to register
|
||||||
|
-- a Vector2D type with luaW_register - this table will automatically be converted
|
||||||
|
vec = { x = 20; y = 30 }
|
||||||
|
ex:SetVec(vec)
|
||||||
|
|
||||||
|
|
||||||
|
vec2 = ex:GetVec()
|
||||||
|
print "Printing values from the vector stored on `ex`:"
|
||||||
|
for k, v in pairs(vec2) do
|
||||||
|
print(k, v)
|
||||||
|
end
|
||||||
|
|
||||||
|
ex:PrintMe()
|
26
sample/example2/lutin_luaWrapperExample2.py
Normal file
26
sample/example2/lutin_luaWrapperExample2.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import lutinModule as module
|
||||||
|
import lutinTools as tools
|
||||||
|
|
||||||
|
def get_desc():
|
||||||
|
return "luaWrapper example 2 : simple lua wrapper"
|
||||||
|
|
||||||
|
def create(target):
|
||||||
|
# module name is 'edn' and type binary.
|
||||||
|
myModule = module.Module(__file__, 'luaWrapperExample2', 'BINARY')
|
||||||
|
# add extra compilation flags :
|
||||||
|
myModule.add_extra_compile_flags()
|
||||||
|
# add the file to compile:
|
||||||
|
myModule.add_src_file([
|
||||||
|
'Example.cpp',
|
||||||
|
'LuaExample.cpp',
|
||||||
|
'main.cpp'])
|
||||||
|
|
||||||
|
# name of the dependency
|
||||||
|
myModule.add_module_depend('luaWrapper')
|
||||||
|
|
||||||
|
|
||||||
|
# add the currrent module at the
|
||||||
|
return myModule
|
||||||
|
|
||||||
|
|
20
sample/example2/main.cpp
Normal file
20
sample/example2/main.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <lua/lua.h>
|
||||||
|
#include <lua/lualib.h>
|
||||||
|
#include <lua/lauxlib.h>
|
||||||
|
|
||||||
|
#include "LuaExample.hpp"
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
if (argc == 2) {
|
||||||
|
lua_State* L = luaL_newstate();
|
||||||
|
luaL_openlibs(L);
|
||||||
|
luaopen_Example(L);
|
||||||
|
if (luaL_dofile(L, argv[1])) {
|
||||||
|
std::cout << lua_tostring(L, -1) << std::endl;
|
||||||
|
}
|
||||||
|
lua_close(L);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user