You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

553 lines
22 KiB
Markdown

# Moon -- A C Binding Toolkit for Lua #
This library provides new convenience functions for binding C types to
Lua as userdata for Lua 5.1, Lua 5.2, and Lua 5.3. It supports objects
with different lifetimes, polymorphic type checking, type-safe binding
of tagged unions or embedded structs, properties and methods at the
same time, and uniform handling of pointers to objects using a simple
and small set of API functions.
## Using this Library ##
This package includes a header file `moon.h` and the corresponding
source file `moon.c`. To use this package you need to include the
header file wherever you want to call one of the macros/functions
defined within. If you just have a single source file where you want
to use those functions, you are done: `moon.h` includes `moon.c` and
makes every function `static`. If you have multiple source files that
need functions/macros from this library, this approach is flawed,
because you will end up with multiple versions of the same functions.
Instead include the header wherever you need it, but when you compile
those source files, define the macro `MOON_PREFIX` to a unique name
to use for all functions in the `moon` library. You also have to
compile and link `moon.c` using the same define. This approach will
change the common `moon_` prefix to your custom prefix behind the
scenes to avoid linker errors in case another library also links to
`moon.c`.
The header file `moon_flag.h` can be included whenever needed, but it
depends on the functions defined in `moon.c`. The `moon_dlfix.h`
header is completely independent, but relies on some platform specific
functions.
## Reference ##
This section lists all provided macros/functions.
### `moon.h`/`moon.c` ###
The main part of the moon toolkit.
#### `MOON_EXPORT`, `MOON_IMPORT`, `MOON_LOCAL` ####
#define MOON_EXPORT
#define MOON_IMPORT
#define MOON_LOCAL
Macros for specifying symbol visibility.
#### `MOON_CONCAT` ####
#define MOON_CONCAT( _a, _b )
A macro that evaluates both arguments and joins them together. You can
use that to build valid C identifiers with custom prefixes or
suffixes.
#### `MOON_STRINGIFY` ####
#define MOON_STRINGIFY( _v )
A macro that has the same effect as `#_v`, but works outside of a
macro substitution.
#### `moon_object_header` ####
typedef struct {
unsigned char flags;
unsigned char cleanup_offset;
unsigned char vcheck_offset;
unsigned char object_offset;
} moon_object_header;
Common data structure shared by all userdata objects created via the
moon toolkit. The object may have optional fields following the memory
of this header structure, stored at the given offsets. The `flags`
field is a bit mask describing the details of the object. A pointer to
this header can be obtained by using plain `lua_touserdata` on a moon
object.
#### `moon_object_cast` ####
typedef void* (*moon_object_cast)( void* );
Function pointer type for conversion functions used by `moon_defcast`.
#### `moon_object_destructor` ####
typedef void (*moon_object_destructor)( void* );
Function pointer type for cleanup functions of moon objects.
#### `MOON_OBJECT_IS_VALID`, `MOON_OBJECT_IS_POINTER` ####
#define MOON_OBJECT_IS_VALID 0x01
#define MOON_OBJECT_IS_POINTER 0x02
Values stored in the `flags` field of the `moon_object_header`
structure. The only value interesting for users of the library is the
`MOON_OBJECT_IS_VALID` flag which is reset automatically by the
`moon_killobject` function to signal that the destructor has already
run.
#### `moon_defobject` ####
/* [ -nup, +0, e ] */
void moon_defobject( lua_State* L,
char const* metatable_name,
size_t userdata_size,
luaL_Reg const* methods,
int nup );
This function creates a new metatable and registers the functions in
the `luaL_Reg` array (functions starting with double underscores `__`
go into the metatable, functions starting with a fullstop `.` are
setup as properties, and the rest goes into a table used by the
`__index` metafield). Property functions act as `__index` and
`__newindex` functions at the same time, i.e. they should return a
value when called with two arguments, and assign the third value when
called with three. If the `luaL_Reg` array also contains an `__index`
and/or `__newindex` function, those functions are called as fallbacks
when method/property lookup has failed. In case a metatable with the
given name already exists, an error is raised. The `userdata_size` is
stored in the metatable for the `moon_newobject` function -- use a
size of 0 to prohibit use of `moon_newobject` (e.g. for incomplete
types). If `nup` is non-zero, it pops those upvalues from the current
Lua stack top and makes them available to all registered functions
(metamethods, property functions, *and* methods). A `__gc` metamethod
and a default `__tostring` metamethod are provided by `moon_defobject`
as well.
#### `moon_newobject` ####
/* [ -0, +1, e ] */
void* moon_newobject( lua_State* L,
char const* metatable_name,
moon_object_destructor destructor );
This function allocates a userdata, sets a metatable, and stores the
cleanup function for later use by the `__gc` metamethod or the
`moon_killobject` function. It throws an error if the `metatable_name`
has not been registered via the `moon_defobject` function. The new
userdata object is pushed to the top of the Lua stack, and a pointer
to the payload (*not* the `moon_object_header` structure) is returned.
#### `moon_newpointer` ####
/* [ -0, +1, e ] */
void** moon_newpointer( lua_State* L,
char const* metatable_name,
moon_object_destructor destructor );
This function allocates a userdata suitable for storing a pointer,
sets a metatable, and stores the cleanup function for later use by the
`__gc` metamethod or the `moon_killobject` function. It is equivalent
to `moon_newobject` with the difference that the payload is stored as
a pointer, not inside the userdata memory. The pointer is initialized
to `NULL` when this function returns, and may be set by assigning to
the memory location pointed to by the return value.
#### `moon_newfield` ####
/* [ -0, +1, e ] */
void** moon_newfield( lua_State* L,
char const* metatable_name,
int idx,
int (*isvalid)( void* p ),
void* p );
This function allocates a userdata suitable for storing a pointer, and
sets a metatable. It is similar to `moon_newpointer`, but it is
intended for exposing a data structure embedded within another
userdata (referenced by stack position `idx`). The resulting moon
object keeps the parent userdata alive by storing a reference in its
uservalue table. If `idx` is `0`, no uservalue table is set. Setting a
cleanup function is not possible, because the parent userdata is
responsible for cleaning up memory and other resources.
If an `isvalid` function pointer is provided, it is called by the
`moon_checkobject`/`moon_testobject` functions to check whether the
object is still valid. This can be used to make sure that a tagged
union used as parent userdata still has the correct type, or that the
parent userdata hasn't released any necessary resources prior to
garbage collection. If the value referenced by `idx` is a moon object
that also has an `isvalid` check registered, all checks are performed
in the order from parent object(s) to child object.
#### `moon_getmethods` ####
/* [ -0, +(0|1), e ] */
int moon_getmethods( lua_State* L,
char const* tname );
If the metatable identified by `tname` has methods registered, pushes
the methods table and returns `LUA_TTABLE`. Otherwise nothing is
pushed and `LUA_TNIL` is returned. This function only works for moon
objects and raises an error if the metatable `tname` wasn't registered
via `moon_defobject`.
#### `moon_killobject` ####
/* [ -0, +0, e ] */
void moon_killobject( lua_State* L,
int idx );
If the moon object at the given stack index is valid, its cleanup
function is run, and the object is marked as invalid (to prevent the
cleanup function from running again). This function can be used to
reclaim resources before the object becomes unreachable.
#### `moon_defcast` ####
/* [ -0, +0, e ] */
void moon_defcast( lua_State* L,
char const* tname1,
char const* tname2,
moon_object_cast cast );
Registers the conversion function `cast` for converting userdata
objects of type `tname1` to type `tname2`. The `cast` function is
called automatically by `moon_checkobject( L, idx, tname2 )` when
applied to an object of type `tname1`, so function implementations can
be reused without extra work. The metatable `tname1` must already
exist and belong to a moon object type (created via `moon_defobject`).
#### `moon_checkobject` ####
/* [ -0, +0, v ] */
void* moon_checkobject( lua_State* L,
int idx,
char const* metatable_name );
This function ensures that the value stored at stack index `idx`
1. is a full userdata
2. is a moon object
3. has the metatable identified by `metatable_name` or has a
cast function to `metatable_name` registered
4. has the `MOON_OBJECT_IS_VALID` flag set
5. all `isvalid` functions return a non-zero value (for objects
created via `moon_newfield`)
6. contains a non-`NULL` pointer value (for objects created via
`moon_newpointer` or `moon_newfield`).
If any of those conditions are false, an error is raised. Otherwise
this function returns a pointer to the object's memory (meaning the
objects created via `moon_newpointer` and `moon_newfield` are
dereferenced once, and if necessary the registered cast function is
called).
#### `moon_testobject` ####
/* [ -0, +0, e ] */
void* moon_testobject( lua_State* L,
int idx,
char const* metatable_name );
Performs the same checks as `moon_checkobject`, but returns `NULL` if
any of those conditions are false instead of raising an error.
#### `moon_checkint` ####
/* [ -0, +0, v ] */
lua_Integer moon_checkint( lua_State* L,
int idx,
lua_Integer min,
lua_Integer max );
This function works like `luaL_checkinteger` but additionally ensures
that the given value is in the range [`min`, `max`], or else an error
is thrown.
#### `moon_optint` ####
/* [ -0, +0, v ] */
lua_Integer moon_optint( lua_State* L,
int idx,
lua_Integer min,
lua_Integer max,
lua_Integer def );
Similar to `moon_checkint` but uses the default value `def` if the
value at the given stack position is `nil` or `none`.
#### `moon_atexit` ####
/* [ -0, +1, e ] */
int* moon_atexit( lua_State* L,
lua_CFunction cleanup );
This function puts an integer-sized userdata (initialized to 0) in the
registry and sets the given `cleanup` function as `__gc` metamethod.
The userdata is also pushed to the top of the Lua stack, and returned
as an `int` pointer.
Use this function if you want to call a cleanup function when the Lua
state is closed, but only if some initialization succeeded. The usual
approach is as follows:
1. Call `moon_atexit` registering your cleanup function.
2. Do your initialization.
3. If successful, you set the `int` pointer to non-zero, which is
almost atomic and can't fail, and pop the userdata.
4. When the cleanup function is called, check for a non-zero value
before actually cleaning up.
#### `moon_setuvfield` ####
/* [ -1, +0, e ] */
void moon_setuvfield( lua_State* L,
int idx,
char const* key );
This function pops the value at the top of the stack and stores it
under `key` in the environment/uservalue table of the object at stack
position `idx`.
#### `moon_getuvfield` ####
/* [ -0, +(0|1), e ] */
int moon_getuvfield( lua_State* L,
int idx,
char const* key );
This function works similar to `luaL_getmetafield`, but it looks for
`key` in the environment/uservalue table of the object at index `idx`,
and pushes the corresponding value to the top of the stack. If there
is no uservalue table or no such field, nothing is pushed and
`LUA_TNIL` is returned. Otherwise, the return value is the type of the
pushed value.
#### `moon_getcache` ####
/* [ -0, +1, e ] */
void moon_getcache( lua_State* L,
int idx );
This function looks up and pushes a weak-valued table under a private
key in the table given by index `idx` (often `LUA_REGISTRYINDEX`). If
the weak-valued table doesn't exist yet, it is created automatically.
This function is useful to map lightuserdata to full userdata, but it
can also be used to cache full userdata for enum values (using
separate caches per enum type), etc.
#### `moon_stack_assert` ####
/* [ -0, +0, v ] */
void moon_stack_assert( lua_State* L,
... );
This "function" is implemented as a macro that evaluates to `void` if
`NDEBUG` is defined. If it is not, it tries to match the type
specifications (strings) given as arguments to the values at the top
of the Lua stack. Every mismatch is reported on `stderr`, and finally
the whole Lua stack is dumped to `stderr` using the `moon_stack`
function below, and an error is raised. Currently the following type
specifications are supported:
* `"n"`: nil
* `"b"`: boolean
* `"l"`: lightuserdata
* `"i"`: integer (equivalent to `"d"` before Lua 5.3)
* `"d"`: number (think `double`)
* `"s"`: string
* `"t"`: table
* `"f"`: function
* `"u"`: userdata
* `"c"`: coroutine
* `"a"`: any (non-nil) value
You can combine the single letter options to express alternatives, so
e.g. `"tf"` means: table or function.
#### `moon_stack` ####
/* [ -0, +0, - ] */
void moon_stack( lua_State* L );
This "function" is also implemented as a macro that evaluates to
`void` in case `NDEBUG` is defined. Otherwise it prints the current
contents of the Lua stack in human-readable format to `stderr`.
#### `moon_absindex` ####
Compatiblity macro for `lua_absindex`, but also available on Lua 5.1
as a function.
#### `moon_derive` ####
int moon_derive( lua_State* L );
A `lua_CFunction` that may be registered as part of your module and
allows Lua code to subclass a moon object. When called it expects two
strings as arguments: a new (non-existing) type name and an old
(existing) type name of a moon object type. It sets up the new type
name as an alias to the old type but with a different methods table.
The new methods table (initially a copy of the methods of the old
type) is returned.
#### `moon_downcast` ####
int moon_downcast( lua_State* L );
A `lua_CFunction` that may be registered as part of your module and
allows Lua code to change the type of a moon object to a type created
via `moon_derive`. It is typically used in constructors of derived
types, and expects a moon object and the new type name as arguments.
If successful, the object (with its metatable replaced) is returned.
### `moon_flag.h` ###
`moon_flag.h` is a macro file, that can be included multiple times and
each time defines a new userdata type as a type-safe representation of
a given enum/flag type in Lua. The resulting userdata values support
`+` (bitwise or, in Lua 5.3 also `|`), `-` (create a new value with
certain bits cleared), and calling (test if all bits are set). For Lua
5.3 also bitwise "and" and bitwise "not" are defined.
Parameters are passed as macros before including the macro file. Any
arguments and all internal macros are `#undef`ed before leaving the
macro file. The following parameters are recognized:
* `MOON_FLAG_NAME` (required): A metatable name used for defining a
userdata type.
* `MOON_FLAG_TYPE` (required): The underlying enum/flag type that is
handled by the custom userdata.
* `MOON_FLAG_SUFFIX` (required): All defined functions have this
suffix (and the `moon_flag_` prefix) to make them unique.
* `MOON_FLAG_NOBITOPS` (optional): If this macro is defined, no
metamethods for bitwise operations are created. This includes
`__add`, `__sub`, and `__call` metamethods. If you do this, you
should think about using strings and `luaL_checkoption` instead of
userdata for representing your flags in Lua.
* `MOON_FLAG_NORELOPS` (optional): If this macro is defined, the
`__eq` metamethod is not created.
* `MOON_FLAG_USECACHE` (optional): The constructor function for this
flag looks in a local cache before creating a new full userdata,
and returns the cached value if possible. This way each enum/flag
value has at most one userdata associated with it.
* `MOON_FLAG_EQMETHOD( _a, _b )` (optional): If you need a custom
comparison operation instead of the usual `==`, define this macro.
The following (static) functions will be defined, unless they are
disabled via one of the parameter macros above:
/* [ -0, +0, e ] */
void moon_flag_def_SUFFIX( lua_State* L );
/* [ -0, +1, e ] */
void moon_flag_new_SUFFIX( lua_State* L, TYPE value );
/* [ -0, +0, v ] */
TYPE moon_flag_get_SUFFIX( lua_State* L, int idx );
int moon_flag_add_SUFFIX( lua_State* L );
int moon_flag_sub_SUFFIX( lua_State* L );
int moon_flag_call_SUFFIX( lua_State* L );
int moon_flag_and_SUFFIX( lua_State* L ); /* Lua 5.3+ */
int moon_flag_not_SUFFIX( lua_State* L ); /* Lua 5.3+ */
int moon_flag_eq_SUFFIX( lua_State* L );
The last six are metamethods and not supposed to be called from C.
`moon_flag_def_SUFFIX` defines the new type, creates the metatable and
registers all metamethods. `moon_flag_new_SUFFIX` pushes a userdata
representing the given value to the top of the Lua stack, while
`moon_flag_get_SUFFIX` returns the corresponding enum value from a
userdata on the Lua stack (or raises an error).
### `moon_dlfix.h` ###
On Linux and BSDs (and possibly other Unix machines) binary extension
modules aren't linked to the Lua library directly, but instead expect
the main executable to reexport the Lua API. If you don't have control
over the main executable (e.g. you are writing a plugin for a 3rd
party program), you are out of luck. This header file tries to
reexport the Lua API from the shared library linked to your plugin to
make it available for extension modules. It relies on some platform
specific tricks, so it probably won't work everywhere.
#### `MOON_DLFIX` ####
#define MOON_DLFIX()
This macro uses the dynamic linker to search for the Lua API in an
already loaded shared library and reexport it for extension modules.
If the necessary linker tricks don't work on the given platform, this
macro evaluates to a `void` expression, and you will continue to get
the usual unresolved symbol errors when loading a binary extension
module.
#### `MOON_DLFIX_LIBNAME` ####
If the builtin heuristics fail to find the shared Lua library you can
specify the library name/path by defining this macro.
#### `MOON_DLFIX_LIBPREFIX` ####
For some OSes *all* loaded shared libraries is searched for an ELF
object that contains the Lua symbols. Since this procedure also finds
shared objects that have the Lua library as a dependency, the library
name is checked for a known prefix to make sure that only the actual
Lua library is exported. The default is `"liblua"`, but you can change
it by defining this macro.
## Contact ##
Philipp Janda, siffiejoe(a)gmx.net
Comments and feedback are always welcome.
## License ##
`moon` is *copyrighted free software* distributed under the Tiny
license. The full license text follows:
moon (c) 2013-2016 Philipp Janda
You may do anything with this work that copyright law would normally
restrict, so long as you retain the above notice(s) and this license
in all redistributed copies and derived works. There is no warranty.