From 6eeed8d6658004f6a7c1f24be1e2d7903c571eba Mon Sep 17 00:00:00 2001 From: Victoria Lacroix Date: Fri, 26 Dec 2025 06:20:14 -0500 Subject: [PATCH 1/2] Update code formatting C goes from GNU style to Pike Style, and Lua goes from 3-spaces to tabs, with no line length limits. --- LuaGObject/buffer.c | 124 +- LuaGObject/callable.c | 2536 ++++++++++++++---------------- LuaGObject/class.lua | 638 ++++---- LuaGObject/component.lua | 529 +++---- LuaGObject/core.lua | 17 +- LuaGObject/enum.lua | 164 +- LuaGObject/ffi.lua | 263 ++-- LuaGObject/gi.c | 1327 ++++++++-------- LuaGObject/init.lua | 72 +- LuaGObject/log.lua | 43 +- LuaGObject/lua_gobject.h | 120 +- LuaGObject/marshal.c | 3231 ++++++++++++++++++-------------------- LuaGObject/namespace.lua | 277 ++-- LuaGObject/object.c | 949 ++++++----- LuaGObject/package.lua | 53 +- LuaGObject/record.c | 1178 +++++++------- LuaGObject/record.lua | 319 ++-- 17 files changed, 5545 insertions(+), 6295 deletions(-) diff --git a/LuaGObject/buffer.c b/LuaGObject/buffer.c index c3f3c8dc..61ac75c9 100644 --- a/LuaGObject/buffer.c +++ b/LuaGObject/buffer.c @@ -1,12 +1,9 @@ -/* - * Dynamic Lua binding to GObject using dynamic gobject-introspection. - * - * Copyright (c) 2010, 2011 Pavel Holejsovsky - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - * Implementation of writable buffer object. - */ +/* Dynamic Lua binding to GObject using dynamic gobject-introspection. + +Copyright (c) 2010, 2011 Pavel Holejsovsky +Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php + +Implementation of writable buffer object. */ #include #include "lua_gobject.h" @@ -14,91 +11,92 @@ static int buffer_len (lua_State *L) { - luaL_checkudata (L, 1, LUA_GOBJECT_BYTES_BUFFER); - lua_pushinteger (L, lua_objlen (L, 1)); - return 1; + luaL_checkudata (L, 1, LUA_GOBJECT_BYTES_BUFFER); + lua_pushinteger (L, lua_objlen (L, 1)); + return 1; } static int buffer_tostring (lua_State *L) { - gpointer data = luaL_checkudata (L, 1, LUA_GOBJECT_BYTES_BUFFER); - lua_pushlstring (L, data, lua_objlen (L, 1)); - return 1; + gpointer data = luaL_checkudata (L, 1, LUA_GOBJECT_BYTES_BUFFER); + lua_pushlstring (L, data, lua_objlen (L, 1)); + return 1; } static int buffer_index (lua_State *L) { - lua_gobject_Unsigned index; - unsigned char *buffer = luaL_checkudata (L, 1, LUA_GOBJECT_BYTES_BUFFER); - index = lua_tointeger (L, 2); - if (index > 0 && (size_t) index <= lua_objlen (L, 1)) - lua_pushinteger (L, buffer[index - 1]); - else - { - luaL_argcheck (L, !lua_isnoneornil (L, 2), 2, "nil index"); - lua_pushnil (L); - } - return 1; + lua_gobject_Unsigned index; + unsigned char *buffer = luaL_checkudata (L, 1, + LUA_GOBJECT_BYTES_BUFFER); + index = lua_tointeger (L, 2); + if (index > 0 && (size_t) index <= lua_objlen (L, 1)) + lua_pushinteger (L, buffer[index - 1]); + else { + luaL_argcheck (L, !lua_isnoneornil (L, 2), 2, "nil index"); + lua_pushnil (L); + } + return 1; } static int buffer_newindex (lua_State *L) { - lua_gobject_Unsigned index; - unsigned char *buffer = luaL_checkudata (L, 1, LUA_GOBJECT_BYTES_BUFFER); - index = luaL_checkint (L, 2); - luaL_argcheck (L, index > 0 && (size_t) index <= lua_objlen (L, 1), - 2, "bad index"); - buffer[index - 1] = luaL_checkint (L, 3) & 0xff; - return 0; + lua_gobject_Unsigned index; + unsigned char *buffer = luaL_checkudata (L, 1, + LUA_GOBJECT_BYTES_BUFFER); + index = luaL_checkint (L, 2); + luaL_argcheck (L, index > 0 && (size_t) index <= lua_objlen (L, 1), + 2, "bad index"); + buffer[index - 1] = luaL_checkint (L, 3) & 0xff; + return 0; } static const luaL_Reg buffer_mt_reg[] = { - { "__len", buffer_len }, - { "__tostring", buffer_tostring }, - { "__index", buffer_index }, - { "__newindex", buffer_newindex }, - { NULL, NULL } + { "__len", buffer_len }, + { "__tostring", buffer_tostring }, + { "__index", buffer_index }, + { "__newindex", buffer_newindex }, + { NULL, NULL } }; static int buffer_new (lua_State *L) { - size_t size; - gpointer *buffer; - const char *source = NULL; + size_t size; + gpointer *buffer; + const char *source = NULL; - if (lua_type (L, 1) == LUA_TSTRING) - source = lua_tolstring (L, 1, &size); - else - size = luaL_checkint (L, 1); - buffer = lua_newuserdata (L, size); - if (source) - memcpy (buffer, source, size); - else - memset (buffer, 0, size); - luaL_getmetatable (L, LUA_GOBJECT_BYTES_BUFFER); - lua_setmetatable (L, -2); - return 1; + if (lua_type (L, 1) == LUA_TSTRING) + source = lua_tolstring (L, 1, &size); + else + size = luaL_checkint (L, 1); + buffer = lua_newuserdata (L, size); + if (source) + memcpy (buffer, source, size); + else + memset (buffer, 0, size); + luaL_getmetatable (L, LUA_GOBJECT_BYTES_BUFFER); + lua_setmetatable (L, -2); + return 1; } static const luaL_Reg buffer_reg[] = { - { "new", buffer_new }, - { NULL, NULL } + { "new", buffer_new }, + { NULL, NULL } }; void lua_gobject_buffer_init (lua_State *L) { - /* Register metatables. */ - luaL_newmetatable (L, LUA_GOBJECT_BYTES_BUFFER); - luaL_register (L, NULL, buffer_mt_reg); - lua_pop (L, 1); + /* Register metatables. */ + luaL_newmetatable (L, LUA_GOBJECT_BYTES_BUFFER); + luaL_register (L, NULL, buffer_mt_reg); + lua_pop (L, 1); - /* Register global API. */ - lua_newtable (L); - luaL_register (L, NULL, buffer_reg); - lua_setfield (L, -2, "bytes"); + /* Register global API. */ + lua_newtable (L); + luaL_register (L, NULL, buffer_reg); + lua_setfield (L, -2, "bytes"); } diff --git a/LuaGObject/callable.c b/LuaGObject/callable.c index a8aa3f73..3f3f06f2 100644 --- a/LuaGObject/callable.c +++ b/LuaGObject/callable.c @@ -1,7 +1,7 @@ /* * Dynamic Lua binding to GObject using dynamic gobject-introspection. * - * Copyright (c) 2010, 2011, 2012, 2013 Pavel Holejsovsky + * Copyright(c) 2010, 2011, 2012, 2013 Pavel Holejsovsky * Licensed under the MIT license: * http://www.opensource.org/licenses/mit-license.php * @@ -14,167 +14,138 @@ #include /* Kinds or Param structure variation. */ -typedef enum _ParamKind - { - /* Ordinary typeinfo (ti)-based parameter. */ - PARAM_KIND_TI = 0, +typedef enum _ParamKind { + /* Ordinary typeinfo(ti)-based parameter. */ + PARAM_KIND_TI = 0, - /* Foreign record. ti is unused. */ - PARAM_KIND_RECORD, + /* Foreign record. ti is unused. */ + PARAM_KIND_RECORD, - /* Foreign enum/flags. ti contains underlying numeric type. */ - PARAM_KIND_ENUM - } ParamKind; + /* Foreign enum/flags. ti contains underlying numeric type. */ + PARAM_KIND_ENUM +} ParamKind; /* Represents single parameter in callable description. */ -typedef struct _Param -{ - GITypeInfo *ti; - GIArgInfo ai; +typedef struct _Param { + GITypeInfo *ti; + GIArgInfo ai; - /* Indicates whether ai field is valid. */ - guint has_arg_info : 1; + /* Indicates whether ai field is valid. */ + guint has_arg_info : 1; - /* Direction of the argument. */ - guint dir : 2; + /* Direction of the argument. */ + guint dir : 2; - /* Ownership passing rule for output parameters. */ - guint transfer : 2; + /* Ownership passing rule for output parameters. */ + guint transfer : 2; - /* Flag indicating whether this parameter is represented by Lua input and/or - returned value. Not represented are e.g. callback's user_data, array - sizes etc. */ - guint internal : 1; + /* Flag indicating whether this parameter is represented by Lua input and/or returned value. Not represented are e.g. callback's user_data, array sizes etc. */ + guint internal : 1; - /* Flag indicating that this is internal user_data value for the - callback. This parameter is supplied automatically, not - explicitely from Lua. */ - guint internal_user_data : 1; + /* Flag indicating that this is internal user_data value for the callback. This parameter is supplied automatically, not explicitely from Lua. */ + guint internal_user_data : 1; - /* Set to nonzero if this argument is user_data for closure which is - marked as (scope call). */ - guint call_scoped_user_data : 1; + /* Set to nonzero if this argument is user_data for closure which is marked as(scope call). */ + guint call_scoped_user_data : 1; - /* Number of closures bound to this argument. 0 if this is not - user_data for closure. */ - guint n_closures : 4; + /* Number of closures bound to this argument. 0 if this is not user_data for closure. */ + guint n_closures : 4; - /* Type of the argument, one of ParamKind values. */ - guint kind : 2; + /* Type of the argument, one of ParamKind values. */ + guint kind : 2; - /* Index into env table attached to the callable, contains repotype - table for specified argument. */ - guint repotype_index : 4; + /* Index into env table attached to the callable, contains repotype table for specified argument. */ + guint repotype_index : 4; } Param; -/* Structure representing userdata allocated for any callable, i.e. function, - method, signal, vtable, callback... */ -typedef struct _Callable -{ - /* Stored callable info. */ - GICallableInfo *info; +/* Structure representing userdata allocated for any callable, i.e. function, method, signal, vtable, callback... */ +typedef struct _Callable { + /* Stored callable info. */ + GICallableInfo *info; - /* Address of the function. */ - gpointer address; + /* Address of the function. */ + gpointer address; - /* Optional, associated 'user_data' context field. */ - gpointer user_data; + /* Optional, associated 'user_data' context field. */ + gpointer user_data; - /* Flags with function characteristics. */ - guint has_self : 1; - guint throws : 1; - guint nargs : 6; - guint ignore_retval : 1; - guint is_closure_marshal : 1; + /* Flags with function characteristics. */ + guint has_self : 1; + guint throws : 1; + guint nargs : 6; + guint ignore_retval : 1; + guint is_closure_marshal : 1; - /* Initialized FFI CIF structure. */ - ffi_cif cif; + /* Initialized FFI CIF structure. */ + ffi_cif cif; - /* Param return value and pointer to nargs Param instances. */ - Param retval; - Param *params; + /* Param return value and pointer to nargs Param instances. */ + Param retval; + Param *params; - /* ffi_type* array here, contains ffi_type[nargs + 2] entries. */ - /* params points here, contains Param[nargs] entries. */ + /* ffi_type* array here, contains ffi_type[nargs + 2] entries. */ + /* params points here, contains Param[nargs] entries. */ } Callable; /* Address is lightuserdata of Callable metatable in Lua registry. */ static int callable_mt; -/* Lua thread that can be used for argument marshaling if needed. - * This address is used as a lightuserdata index in the registry. */ +/* Lua thread that can be used for argument marshaling if needed. This address is used as a lightuserdata index in the registry. */ static int marshalling_L_address; /* Structure containing basic callback information. */ -typedef struct _Callback -{ - /* Thread which created callback and Lua-reference to it (so that it - is not GCed). */ - lua_State *L; - int thread_ref; - - /* State lock, to be passed to lua_gobject_state_enter() when callback is - invoked. */ - gpointer state_lock; +typedef struct _Callback { + /* Thread which created callback and Lua-reference to it(so that it is not GCed). */ + lua_State *L; + int thread_ref; + + /* State lock, to be passed to lua_gobject_state_enter() when callback is invoked. */ + gpointer state_lock; } Callback; typedef struct _FfiClosureBlock FfiClosureBlock; /* Single element in FFI callbacks block. */ -typedef struct _FfiClosure -{ - /* Libffi closure object. */ - ffi_closure ffi_closure; - - /* Pointer to the block to which this closure belongs. */ - FfiClosureBlock *block; - - union - { - struct - { - /* Lua reference to associated Callable. */ - int callable_ref; - - /* Callable's target to be invoked (either function, - userdata/table with __call metafunction or coroutine (which - is resumed instead of called). */ - int target_ref; - }; - - /* Closure's entry point, stored only temporarily until closure is - created. */ - gpointer call_addr; - }; - - /* Flag indicating whether closure should auto-destroy itself after it is - called. */ - guint autodestroy : 1; - - /* Flag indicating whether the closure was already created. */ - guint created : 1; +typedef struct _FfiClosure { + /* Libffi closure object. */ + ffi_closure ffi_closure; + + /* Pointer to the block to which this closure belongs. */ + FfiClosureBlock *block; + + union { + struct { + /* Lua reference to associated Callable. */ + int callable_ref; + + /* Callable's target to be invoked(either function, userdata/table with __call metafunction or coroutine(which is resumed instead of called). */ + int target_ref; + }; + + /* Closure's entry point, stored only temporarily until closure is created. */ + gpointer call_addr; + }; + + /* Flag indicating whether closure should auto-destroy itself after it is called. */ + guint autodestroy : 1; + + /* Flag indicating whether the closure was already created. */ + guint created : 1; } FfiClosure; -/* Structure containing closure block. This is user_data block for - C-side closure arguments. */ -struct _FfiClosureBlock -{ - /* 1st closure. */ - FfiClosure ffi_closure; - - /* Target to be invoked. */ - Callback callback; - - /* Number of other closures in the block, excluding the forst one - contained already in this header. */ - int closures_count; - - /* Variable-length array of pointers to other closures. - Unfortunately libffi does not allow to allocate contiguous block - containing more closures, otherwise this array would simply - contain FfiClosure instances instead of pointers to dynamically - allocated ones. */ - FfiClosure *ffi_closures[1]; +/* Structure containing closure block. This is user_data block for C-side closure arguments. */ +struct _FfiClosureBlock { + /* 1st closure. */ + FfiClosure ffi_closure; + + /* Target to be invoked. */ + Callback callback; + + /* Number of other closures in the block, excluding the forst one contained already in this header. */ + int closures_count; + + /* Variable-length array of pointers to other closures. Unfortunately libffi does not allow to allocate contiguous block containing more closures, otherwise this array would simply contain FfiClosure instances instead of pointers to dynamically allocated ones. */ + FfiClosure *ffi_closures[1]; }; /* lightuserdata key to callable cache table. */ @@ -182,1401 +153,1266 @@ static int callable_cache; /* Gets ffi_type for given tag, returns NULL if it cannot be handled. */ static ffi_type * -get_simple_ffi_type (GITypeTag tag) +get_simple_ffi_type(GITypeTag tag) { - ffi_type *ffi; - switch (tag) - { -#define HANDLE_TYPE(tag, ffitype) \ - case GI_TYPE_TAG_ ## tag: \ - ffi = &ffi_type_ ## ffitype; \ - break - - HANDLE_TYPE(VOID, void); - HANDLE_TYPE(BOOLEAN, uint); - HANDLE_TYPE(INT8, sint8); - HANDLE_TYPE(UINT8, uint8); - HANDLE_TYPE(INT16, sint16); - HANDLE_TYPE(UINT16, uint16); - HANDLE_TYPE(INT32, sint32); - HANDLE_TYPE(UINT32, uint32); - HANDLE_TYPE(INT64, sint64); - HANDLE_TYPE(UINT64, uint64); - HANDLE_TYPE(FLOAT, float); - HANDLE_TYPE(DOUBLE, double); + ffi_type *ffi; + switch (tag) { +#define HANDLE_TYPE(tag, ffitype) \ + case GI_TYPE_TAG_ ## tag: \ + ffi = &ffi_type_ ## ffitype; \ + break + + HANDLE_TYPE(VOID, void); + HANDLE_TYPE(BOOLEAN, uint); + HANDLE_TYPE(INT8, sint8); + HANDLE_TYPE(UINT8, uint8); + HANDLE_TYPE(INT16, sint16); + HANDLE_TYPE(UINT16, uint16); + HANDLE_TYPE(INT32, sint32); + HANDLE_TYPE(UINT32, uint32); + HANDLE_TYPE(INT64, sint64); + HANDLE_TYPE(UINT64, uint64); + HANDLE_TYPE(FLOAT, float); + HANDLE_TYPE(DOUBLE, double); #if GLIB_SIZEOF_SIZE_T == 4 - HANDLE_TYPE(GTYPE, uint32); + HANDLE_TYPE(GTYPE, uint32); #else - HANDLE_TYPE(GTYPE, uint64); + HANDLE_TYPE(GTYPE, uint64); #endif #undef HANDLE_TYPE - default: - ffi = NULL; - } + default: + ffi = NULL; + } - return ffi; + return ffi; } /* Gets ffi_type for given Param instance. */ static ffi_type * get_ffi_type(Param *param) { - switch (param->kind) - { - case PARAM_KIND_RECORD: - return &ffi_type_pointer; - - case PARAM_KIND_ENUM: - return param->ti ? get_simple_ffi_type (gi_type_info_get_tag (param->ti)) - : &ffi_type_sint; - - case PARAM_KIND_TI: - break; - } - - /* In case of inout or out parameters, the type is always pointer. */ - GITypeTag tag = gi_type_info_get_tag (param->ti); - ffi_type* ffi = gi_type_info_is_pointer(param->ti) - ? &ffi_type_pointer : get_simple_ffi_type (tag); - if (ffi == NULL) - { - /* Something more complex. */ - if (tag == GI_TYPE_TAG_INTERFACE) - { - GIBaseInfo *ii = gi_type_info_get_interface (param->ti); - if (GI_IS_ENUM_INFO (ii) || GI_IS_FLAGS_INFO (ii)) - ffi = get_simple_ffi_type (gi_enum_info_get_storage_type (GI_ENUM_INFO (ii))); - gi_base_info_unref (ii); + switch (param->kind) { + case PARAM_KIND_RECORD: + return &ffi_type_pointer; + + case PARAM_KIND_ENUM: + return param->ti ? get_simple_ffi_type(gi_type_info_get_tag(param->ti)) + : &ffi_type_sint; + + case PARAM_KIND_TI: + break; + } + + /* In case of inout or out parameters, the type is always pointer. */ + GITypeTag tag = gi_type_info_get_tag(param->ti); + ffi_type* ffi = gi_type_info_is_pointer(param->ti) + ? &ffi_type_pointer : get_simple_ffi_type(tag); + if (ffi == NULL) { + /* Something more complex. */ + if (tag == GI_TYPE_TAG_INTERFACE) { + GIBaseInfo *ii = gi_type_info_get_interface(param->ti); + if (GI_IS_ENUM_INFO(ii) || GI_IS_FLAGS_INFO(ii)) + ffi = get_simple_ffi_type( + gi_enum_info_get_storage_type(GI_ENUM_INFO(ii))); + gi_base_info_unref(ii); + } } - } - return ffi != NULL ? ffi : &ffi_type_pointer; + return ffi != NULL ? ffi : &ffi_type_pointer; } -/* If typeinfo specifies array with length parameter, mark it in - specified callable as an internal one. */ +/* If typeinfo specifies array with length parameter, mark it in specified callable as an internal one. */ static void -callable_mark_array_length (Callable *callable, GITypeInfo *ti) +callable_mark_array_length(Callable *callable, GITypeInfo *ti) { - if (gi_type_info_get_tag (ti) == GI_TYPE_TAG_ARRAY && - gi_type_info_get_array_type (ti) == GI_ARRAY_TYPE_C) - { - guint arg; - if (gi_type_info_get_array_length_index (ti, &arg) && arg < callable->nargs) - callable->params[arg].internal = TRUE; - } + if (gi_type_info_get_tag(ti) == GI_TYPE_TAG_ARRAY && + gi_type_info_get_array_type(ti) == GI_ARRAY_TYPE_C) { + guint arg; + if (gi_type_info_get_array_length_index(ti, &arg) && arg < callable->nargs) + callable->params[arg].internal = TRUE; + } } static void -callable_param_init (Param *param) +callable_param_init(Param *param) { - memset (param, 0, sizeof *param); - param->kind = PARAM_KIND_TI; + memset(param, 0, sizeof *param); + param->kind = PARAM_KIND_TI; } static Callable * -callable_allocate (lua_State *L, int nargs, ffi_type ***ffi_args) +callable_allocate(lua_State *L, int nargs, ffi_type ***ffi_args) { - int argi; - - /* Create userdata structure. */ - luaL_checkstack (L, 2, NULL); - Callable *callable = lua_newuserdata (L, sizeof (Callable) + - sizeof (ffi_type) * (nargs + 2) + - sizeof (Param) * nargs); - memset (callable, 0, sizeof *callable); - lua_pushlightuserdata (L, &callable_mt); - lua_rawget (L, LUA_REGISTRYINDEX); - lua_setmetatable (L, -2); - - /* Inititialize callable contents. */ - *ffi_args = (ffi_type **) &callable[1]; - callable->params = (Param *) &(*ffi_args)[nargs + 2]; - callable->nargs = nargs; - callable->user_data = NULL; - callable->info = NULL; - callable->has_self = 0; - callable->throws = 0; - callable->ignore_retval = 0; - callable->is_closure_marshal = 0; - - /* Clear all 'internal' flags inside callable parameters, parameters are then - marked as internal during processing of their parents. */ - callable_param_init (&callable->retval); - for (argi = 0; argi < nargs; argi++) - callable_param_init (&callable->params[argi]); - - return callable; + int argi; + + /* Create userdata structure. */ + luaL_checkstack(L, 2, NULL); + Callable *callable = lua_newuserdata(L, sizeof(Callable) + + sizeof(ffi_type) *(nargs + 2) + + sizeof(Param) * nargs); + memset(callable, 0, sizeof *callable); + lua_pushlightuserdata(L, &callable_mt); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + + /* Inititialize callable contents. */ + *ffi_args =(ffi_type **) &callable[1]; + callable->params =(Param *) &(*ffi_args)[nargs + 2]; + callable->nargs = nargs; + callable->user_data = NULL; + callable->info = NULL; + callable->has_self = 0; + callable->throws = 0; + callable->ignore_retval = 0; + callable->is_closure_marshal = 0; + + /* Clear all 'internal' flags inside callable parameters, parameters are then marked as internal during processing of their parents. */ + callable_param_init(&callable->retval); + for (argi = 0; argi < nargs; argi++) + callable_param_init(&callable->params[argi]); + + return callable; } static Param * -callable_get_param (Callable *callable, gint n) -{ - Param *param; - - if (n < 0 || n >= callable->nargs) - return NULL; - - param = &callable->params[n]; - if (!param->has_arg_info) - { - /* Ensure basic fields are initialized. */ - gi_callable_info_load_arg (callable->info, n, ¶m->ai); - param->has_arg_info = TRUE; - param->ti = gi_arg_info_get_type_info (¶m->ai); - param->dir = gi_arg_info_get_direction (¶m->ai); - param->transfer = gi_arg_info_get_ownership_transfer (¶m->ai); - } - return param; +callable_get_param(Callable *callable, gint n) { + Param *param; + + if (n < 0 || n >= callable->nargs) + return NULL; + + param = &callable->params[n]; + if (!param->has_arg_info) { + /* Ensure basic fields are initialized. */ + gi_callable_info_load_arg(callable->info, n, ¶m->ai); + param->has_arg_info = TRUE; + param->ti = gi_arg_info_get_type_info(¶m->ai); + param->dir = gi_arg_info_get_direction(¶m->ai); + param->transfer = gi_arg_info_get_ownership_transfer(¶m->ai); + } + return param; } int -lua_gobject_callable_create (lua_State *L, GICallableInfo *info, gpointer addr) +lua_gobject_callable_create(lua_State *L, GICallableInfo *info, gpointer addr) { - Callable *callable; - Param *param, *data_param; - ffi_type **ffi_arg, **ffi_args; - ffi_type *ffi_retval; - gint nargs, argi; - - /* Allocate Callable userdata. */ - nargs = gi_callable_info_get_n_args (info); - callable = callable_allocate (L, nargs, &ffi_args); - callable->info = GI_CALLABLE_INFO (gi_base_info_ref (info)); - callable->address = addr; - if (GI_IS_FUNCTION_INFO (info)) - { - /* Get FunctionInfo flags. */ - const gchar* symbol; - gint flags = gi_function_info_get_flags (GI_FUNCTION_INFO (info)); - if ((flags & GI_FUNCTION_IS_METHOD) != 0 && - (flags & GI_FUNCTION_IS_CONSTRUCTOR) == 0) - callable->has_self = 1; - if (gi_callable_info_can_throw_gerror (GI_CALLABLE_INFO (info))) - callable->throws = 1; - - /* Resolve symbol (function address). */ - symbol = gi_function_info_get_symbol (GI_FUNCTION_INFO (info)); - if (!gi_typelib_symbol (gi_base_info_get_typelib (GI_BASE_INFO (info)), symbol, - &callable->address)) - /* Fail with the error message. */ - return luaL_error (L, "could not locate %s(%s): %s", - lua_tostring (L, -3), symbol, g_module_error ()); - } - else if (GI_IS_SIGNAL_INFO (info)) - /* Signals always have 'self', i.e. the object on which they are - emitted. */ - callable->has_self = 1; - - /* Process return value. */ - callable->retval.ti = gi_callable_info_get_return_type (callable->info); - callable->retval.dir = GI_DIRECTION_OUT; - callable->retval.transfer = gi_callable_info_get_caller_owns (callable->info); - callable->retval.internal = FALSE; - callable->retval.repotype_index = 0; - ffi_retval = get_ffi_type (&callable->retval); - callable_mark_array_length (callable, callable->retval.ti); - - /* Process 'self' argument, if present. */ - ffi_arg = &ffi_args[0]; - if (callable->has_self) - *ffi_arg++ = &ffi_type_pointer; - - /* Process the rest of the arguments. */ - for (argi = 0; argi < nargs; argi++, ffi_arg++) - { - guint arg; - - param = callable_get_param (callable, argi); - *ffi_arg = (param->dir == GI_DIRECTION_IN) - ? get_ffi_type (param) : &ffi_type_pointer; - - /* Mark closure-related user_data fields as internal. */ - if (gi_arg_info_get_closure_index (¶m->ai, &arg)) - { - data_param = callable_get_param (callable, arg); - /* `arg` is defined also on callbacks, so check for invalid scope - to avoid setting the internal flag on them. */ - if (data_param != NULL && gi_arg_info_get_scope (&data_param->ai) == GI_SCOPE_TYPE_INVALID) - { - data_param->internal = TRUE; - if (arg == (guint)argi) - data_param->internal_user_data = TRUE; - data_param->n_closures++; - if (gi_arg_info_get_scope (¶m->ai) == GI_SCOPE_TYPE_CALL) - data_param->call_scoped_user_data = TRUE; - } - } - - /* Mark destroy_notify fields as internal. */ - if (gi_arg_info_get_destroy_index (¶m->ai, &arg)) - { - data_param = callable_get_param (callable, arg); - if (data_param != NULL) - data_param->internal = TRUE; - } - - /* Similarly for array length field. */ - callable_mark_array_length (callable, param->ti); - - /* In case that we have an out or inout argument and callable - returns boolean, mark it as ignore_retval (because we will - signalize failure by returning nil instead of extra - value). */ - if (param->dir != GI_DIRECTION_IN - && gi_type_info_get_tag (callable->retval.ti) == GI_TYPE_TAG_BOOLEAN) - callable->ignore_retval = 1; - } - - /* Manual adjustment of 'GObject.ClosureMarshal' type, which is - crucial for lua_gobject but is missing an array annotation in - glib/gobject-introspection < 1.30. */ - if (!GLIB_CHECK_VERSION (2, 30, 0) - && !strcmp (gi_base_info_get_namespace (GI_BASE_INFO (info)), "GObject") - && !strcmp (gi_base_info_get_name (GI_BASE_INFO (info)), "ClosureMarshal")) - { - callable->is_closure_marshal = 1; - callable->params[2].internal = 1; - } - - /* Add ffi info for 'err' argument. */ - if (callable->throws) - *ffi_arg++ = &ffi_type_pointer; - - /* Create ffi_cif. */ - if (ffi_prep_cif (&callable->cif, FFI_DEFAULT_ABI, - callable->has_self + nargs + callable->throws, - ffi_retval, ffi_args) != FFI_OK) - { - lua_concat (L, lua_gobject_type_get_name (L, GI_BASE_INFO (callable->info))); - return luaL_error (L, "ffi_prep_cif for `%s' failed", - lua_tostring (L, -1)); - } - - return 1; + Callable *callable; + Param *param, *data_param; + ffi_type **ffi_arg, **ffi_args; + ffi_type *ffi_retval; + gint nargs, argi; + + /* Allocate Callable userdata. */ + nargs = gi_callable_info_get_n_args(info); + callable = callable_allocate(L, nargs, &ffi_args); + callable->info = GI_CALLABLE_INFO(gi_base_info_ref(info)); + callable->address = addr; + if (GI_IS_FUNCTION_INFO(info)) { + /* Get FunctionInfo flags. */ + const gchar* symbol; + gint flags = gi_function_info_get_flags(GI_FUNCTION_INFO(info)); + if ((flags & GI_FUNCTION_IS_METHOD) != 0 + && (flags & GI_FUNCTION_IS_CONSTRUCTOR) == 0) + callable->has_self = 1; + if (gi_callable_info_can_throw_gerror(GI_CALLABLE_INFO(info))) + callable->throws = 1; + + /* Resolve symbol(function address). */ + symbol = gi_function_info_get_symbol(GI_FUNCTION_INFO(info)); + if (!gi_typelib_symbol( + gi_base_info_get_typelib(GI_BASE_INFO(info)), + symbol, &callable->address)) + /* Fail with the error message. */ + return luaL_error(L, "could not locate %s(%s): %s", + lua_tostring(L, -3), symbol, g_module_error()); + } + else if (GI_IS_SIGNAL_INFO(info)) + /* Signals always have 'self', i.e. the object on which they are emitted. */ + callable->has_self = 1; + + /* Process return value. */ + callable->retval.ti = gi_callable_info_get_return_type(callable->info); + callable->retval.dir = GI_DIRECTION_OUT; + callable->retval.transfer = gi_callable_info_get_caller_owns(callable->info); + callable->retval.internal = FALSE; + callable->retval.repotype_index = 0; + ffi_retval = get_ffi_type(&callable->retval); + callable_mark_array_length(callable, callable->retval.ti); + + /* Process 'self' argument, if present. */ + ffi_arg = &ffi_args[0]; + if (callable->has_self) + *ffi_arg++ = &ffi_type_pointer; + + /* Process the rest of the arguments. */ + for (argi = 0; argi < nargs; argi++, ffi_arg++) { + guint arg; + + param = callable_get_param(callable, argi); + *ffi_arg =(param->dir == GI_DIRECTION_IN) + ? get_ffi_type(param) : &ffi_type_pointer; + + /* Mark closure-related user_data fields as internal. */ + if (gi_arg_info_get_closure_index(¶m->ai, &arg)) { + data_param = callable_get_param(callable, arg); + /* `arg` is defined also on callbacks, so check for invalid scope to avoid setting the internal flag on them. */ + if (data_param != NULL + && gi_arg_info_get_scope(&data_param->ai) + == GI_SCOPE_TYPE_INVALID) { + data_param->internal = TRUE; + if (arg ==(guint)argi) + data_param->internal_user_data = TRUE; + data_param->n_closures++; + if (gi_arg_info_get_scope(¶m->ai) == GI_SCOPE_TYPE_CALL) + data_param->call_scoped_user_data = TRUE; + } + } + + /* Mark destroy_notify fields as internal. */ + if (gi_arg_info_get_destroy_index(¶m->ai, &arg)) { + data_param = callable_get_param(callable, arg); + if (data_param != NULL) + data_param->internal = TRUE; + } + + /* Similarly for array length field. */ + callable_mark_array_length(callable, param->ti); + + /* In case that we have an out or inout argument and callable returns boolean, mark it as ignore_retval(because we will signalize failure by returning nil instead of extra value). */ + if (param->dir != GI_DIRECTION_IN + && gi_type_info_get_tag(callable->retval.ti) + == GI_TYPE_TAG_BOOLEAN) + callable->ignore_retval = 1; + } + + /* Manual adjustment of 'GObject.ClosureMarshal' type, which is crucial for lua_gobject but is missing an array annotation in glib/gobject-introspection < 1.30. */ + if (!GLIB_CHECK_VERSION(2, 30, 0) + && !strcmp(gi_base_info_get_namespace(GI_BASE_INFO(info)), + "GObject") + && !strcmp(gi_base_info_get_name(GI_BASE_INFO(info)), + "ClosureMarshal")) { + callable->is_closure_marshal = 1; + callable->params[2].internal = 1; + } + + /* Add ffi info for 'err' argument. */ + if (callable->throws) + *ffi_arg++ = &ffi_type_pointer; + + /* Create ffi_cif. */ + if (ffi_prep_cif (&callable->cif, FFI_DEFAULT_ABI, + callable->has_self + nargs + callable->throws, + ffi_retval, ffi_args) != FFI_OK) { + lua_concat(L, lua_gobject_type_get_name(L, + GI_BASE_INFO(callable->info))); + return luaL_error(L, "ffi_prep_cif for `%s' failed", lua_tostring(L, -1)); + } + + return 1; } static int -callable_param_get_kind (lua_State *L) +callable_param_get_kind(lua_State *L) { - int kind = -1, top = lua_gettop (L); - if (lua_gobject_udata_test (L, -1, LUA_GOBJECT_GI_INFO)) - kind = PARAM_KIND_TI; - else - { - luaL_checktype (L, -1, LUA_TTABLE); - lua_getmetatable (L, -1); - if (!lua_isnil (L, -1)) - { - lua_getfield (L, -1, "_type"); - if (!lua_isnil (L, -1)) - { - const char *type = lua_tostring (L, -1); - if (g_strcmp0 (type, "struct") == 0 - || g_strcmp0 (type, "union") == 0) - kind = PARAM_KIND_RECORD; - else if (g_strcmp0 (type, "enum") == 0 - || g_strcmp0 (type, "flags") == 0) - kind = PARAM_KIND_ENUM; - } + int kind = -1, top = lua_gettop(L); + if (lua_gobject_udata_test(L, -1, LUA_GOBJECT_GI_INFO)) + kind = PARAM_KIND_TI; + else { + luaL_checktype(L, -1, LUA_TTABLE); + lua_getmetatable(L, -1); + if (!lua_isnil(L, -1)) { + lua_getfield(L, -1, "_type"); + if (!lua_isnil(L, -1)) { + const char *type = lua_tostring(L, -1); + if (g_strcmp0(type, "struct") == 0 + || g_strcmp0(type, "union") == 0) + kind = PARAM_KIND_RECORD; + else if (g_strcmp0(type, "enum") == 0 + || g_strcmp0(type, "flags") == 0) + kind = PARAM_KIND_ENUM; + } + } } - } - lua_settop (L, top); - return kind; + lua_settop(L, top); + return kind; } static const char *dirs[] = { "in", "out", "inout", NULL }; -/* Parses single 'Param' structure from the table on the top of the - stack. Pops the table from the stack. */ +/* Parses single 'Param' structure from the table on the top of the stack. Pops the table from the stack. */ static void -callable_param_parse (lua_State *L, Param *param) +callable_param_parse(lua_State *L, Param *param) { - int kind = callable_param_get_kind (L); - - /* Initialize parameters to default values. */ - param->transfer = GI_TRANSFER_NOTHING; - param->ti = NULL; - if (kind == -1) - { - /* Check the direction. */ - lua_getfield (L, -1, "dir"); - if (!lua_isnil (L, -1)) - param->dir = luaL_checkoption (L, -1, dirs[0], dirs); - lua_pop (L, 1); - - /* Get transfer flag, prepare default according to dir. */ - lua_getfield (L, -1, "xfer"); - param->transfer = lua_toboolean (L, -1) - ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING; - lua_pop (L, 1); - - /* Get type, assume record (if not overriden by real giinfo type - below). */ - lua_getfield (L, -1, "type"); - if (!lua_isnil (L, -1)) - { - /* This is actually an enum, and 'type' field contains - numeric type for this enum. Store it into the ti. */ - GITypeInfo **ti = luaL_checkudata (L, -1, LUA_GOBJECT_GI_INFO); - param->ti = GI_TYPE_INFO (gi_base_info_ref (*ti)); + int kind = callable_param_get_kind(L); + + /* Initialize parameters to default values. */ + param->transfer = GI_TRANSFER_NOTHING; + param->ti = NULL; + if (kind == -1) { + /* Check the direction. */ + lua_getfield(L, -1, "dir"); + if (!lua_isnil(L, -1)) + param->dir = luaL_checkoption(L, -1, dirs[0], dirs); + lua_pop(L, 1); + + /* Get transfer flag, prepare default according to dir. */ + lua_getfield(L, -1, "xfer"); + param->transfer = lua_toboolean(L, -1) + ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING; + lua_pop(L, 1); + + /* Get type, assume record(if not overriden by real giinfo type below). */ + lua_getfield(L, -1, "type"); + if (!lua_isnil(L, -1)) { + /* This is actually an enum, and 'type' field contains numeric type for this enum. Store it into the ti. */ + GITypeInfo **ti = luaL_checkudata(L, -1, LUA_GOBJECT_GI_INFO); + param->ti = GI_TYPE_INFO(gi_base_info_ref(*ti)); + } + lua_pop(L, 1); + + /* Finally get the type from the table(from index 1) and replace the table with the type. */ + lua_rawgeti(L, -1, 1); + lua_replace(L, -2); } - lua_pop (L, 1); - - /* Finally get the type from the table (from index 1) and - replace the table with the type. */ - lua_rawgeti (L, -1, 1); - lua_replace (L, -2); - } - - /* Parse the type. */ - if (kind == -1) - kind = callable_param_get_kind (L); - if (kind == PARAM_KIND_TI) - { - /* Expect typeinfo. */ - GITypeInfo **pti = lua_touserdata (L, -1); - param->ti = GI_TYPE_INFO (gi_base_info_ref (*pti)); - param->kind = kind; - lua_pop (L, 1); - } - else if (kind == PARAM_KIND_ENUM || kind == PARAM_KIND_RECORD) - { - /* Add it to the env table. */ - int index = lua_objlen (L, -2) + 1; - lua_rawseti (L, -2, index); - param->repotype_index = index; - param->kind = kind; - } - else - luaL_error (L, "bad efn def"); + + /* Parse the type. */ + if (kind == -1) + kind = callable_param_get_kind(L); + if (kind == PARAM_KIND_TI) { + /* Expect typeinfo. */ + GITypeInfo **pti = lua_touserdata(L, -1); + param->ti = GI_TYPE_INFO(gi_base_info_ref(*pti)); + param->kind = kind; + lua_pop(L, 1); + } else if (kind == PARAM_KIND_ENUM || kind == PARAM_KIND_RECORD) { + /* Add it to the env table. */ + int index = lua_objlen(L, -2) + 1; + lua_rawseti(L, -2, index); + param->repotype_index = index; + param->kind = kind; + } else + luaL_error(L, "bad efn def"); } /* Parses callable from given table. */ int -lua_gobject_callable_parse (lua_State *L, int info, gpointer addr) +lua_gobject_callable_parse(lua_State *L, int info, gpointer addr) { - Callable *callable; - int nargs, i; - ffi_type **ffi_args; - ffi_type *ffi_retval; - - /* Allocate the raw structure. */ - nargs = lua_objlen (L, info); - callable = callable_allocate (L, nargs, &ffi_args); - - /* Create 'env' table. */ - lua_newtable (L); - - /* Add function name to it. */ - lua_getfield (L, info, "name"); - lua_rawseti (L, -2, 0); - - /* Get address of the function. */ - if (addr == NULL) - { - lua_getfield (L, info, "addr"); - addr = lua_touserdata (L, -1); - lua_pop (L, 1); - } - callable->address = addr; - - /* Handle 'return' table. */ - lua_getfield (L, info, "ret"); - - /* Get ignore_retval flag. */ - lua_getfield (L, -1, "phantom"); - callable->ignore_retval = lua_toboolean (L, -1); - lua_pop (L, 1); - - /* Parse return value param. */ - callable->retval.dir = GI_DIRECTION_OUT; - callable_param_parse (L, &callable->retval); - ffi_retval = get_ffi_type (&callable->retval); - - /* Parse individual arguments. */ - for (i = 0; i < nargs; i++) - { - lua_rawgeti (L, info, i + 1); - callable->params[i].dir = GI_DIRECTION_IN; - callable_param_parse (L, &callable->params[i]); - ffi_args[i] = (callable->params[i].dir == GI_DIRECTION_IN) - ? get_ffi_type (&callable->params[i]) : &ffi_type_pointer; - } - - /* Handle 'throws' flag. */ - lua_getfield (L, info, "throws"); - callable->throws = lua_toboolean (L, -1); - lua_pop (L, 1); - if (callable->throws) - ffi_args[i] = &ffi_type_pointer; - - /* Create ffi_cif. */ - if (ffi_prep_cif (&callable->cif, FFI_DEFAULT_ABI, - nargs + callable->throws, - ffi_retval, ffi_args) != FFI_OK) - return luaL_error (L, "ffi_prep_cif failed for parsed"); - - /* Attach env table to the returned callable instance. */ - lua_setfenv (L, -2); - return 1; + Callable *callable; + int nargs, i; + ffi_type **ffi_args; + ffi_type *ffi_retval; + + /* Allocate the raw structure. */ + nargs = lua_objlen(L, info); + callable = callable_allocate(L, nargs, &ffi_args); + + /* Create 'env' table. */ + lua_newtable(L); + + /* Add function name to it. */ + lua_getfield(L, info, "name"); + lua_rawseti(L, -2, 0); + + /* Get address of the function. */ + if (addr == NULL) { + lua_getfield(L, info, "addr"); + addr = lua_touserdata(L, -1); + lua_pop(L, 1); + } + callable->address = addr; + + /* Handle 'return' table. */ + lua_getfield(L, info, "ret"); + + /* Get ignore_retval flag. */ + lua_getfield(L, -1, "phantom"); + callable->ignore_retval = lua_toboolean(L, -1); + lua_pop(L, 1); + + /* Parse return value param. */ + callable->retval.dir = GI_DIRECTION_OUT; + callable_param_parse(L, &callable->retval); + ffi_retval = get_ffi_type(&callable->retval); + + /* Parse individual arguments. */ + for (i = 0; i < nargs; i++) { + lua_rawgeti(L, info, i + 1); + callable->params[i].dir = GI_DIRECTION_IN; + callable_param_parse(L, &callable->params[i]); + ffi_args[i] =(callable->params[i].dir == GI_DIRECTION_IN) + ? get_ffi_type(&callable->params[i]) : &ffi_type_pointer; + } + + /* Handle 'throws' flag. */ + lua_getfield(L, info, "throws"); + callable->throws = lua_toboolean(L, -1); + lua_pop(L, 1); + if (callable->throws) + ffi_args[i] = &ffi_type_pointer; + + /* Create ffi_cif. */ + if (ffi_prep_cif (&callable->cif, FFI_DEFAULT_ABI, + nargs + callable->throws, ffi_retval, ffi_args) != FFI_OK) + return luaL_error(L, "ffi_prep_cif failed for parsed"); + + /* Attach env table to the returned callable instance. */ + lua_setfenv(L, -2); + return 1; } /* Checks whether given argument is Callable userdata. */ static Callable * -callable_get (lua_State *L, int narg) +callable_get(lua_State *L, int narg) { - luaL_checkstack (L, 3, ""); - if (lua_getmetatable (L, narg)) - { - lua_pushlightuserdata (L, &callable_mt); - lua_rawget (L, LUA_REGISTRYINDEX); - if (lua_rawequal (L, -1, -2)) - { - lua_pop (L, 2); - return lua_touserdata (L, narg); + luaL_checkstack(L, 3, ""); + if (lua_getmetatable(L, narg)) { + lua_pushlightuserdata(L, &callable_mt); + lua_rawget(L, LUA_REGISTRYINDEX); + if (lua_rawequal(L, -1, -2)) { + lua_pop(L, 2); + return lua_touserdata(L, narg); + } } - } - lua_pushfstring (L, "expected lua_gobject.callable, got %s", - lua_typename (L, lua_type (L, narg))); - luaL_argerror (L, narg, lua_tostring (L, -1)); - return NULL; + lua_pushfstring(L, "expected lua_gobject.callable, got %s", + lua_typename(L, lua_type(L, narg))); + luaL_argerror(L, narg, lua_tostring(L, -1)); + return NULL; } static void -callable_param_destroy (Param *param) +callable_param_destroy(Param *param) { - g_clear_pointer (¶m->ti, gi_base_info_unref); - gi_base_info_clear (¶m->ai); + g_clear_pointer(¶m->ti, gi_base_info_unref); + gi_base_info_clear(¶m->ai); } static int -callable_gc (lua_State *L) +callable_gc(lua_State *L) { - int i; + int i; - /* Unref embedded 'info' field. */ - Callable *callable = callable_get (L, 1); - if (callable->info) - gi_base_info_unref (callable->info); + /* Unref embedded 'info' field. */ + Callable *callable = callable_get(L, 1); + if (callable->info) + gi_base_info_unref(callable->info); - /* Destroy all params. */ - for (i = 0; i < callable->nargs; i++) - callable_param_destroy (&callable->params[i]); + /* Destroy all params. */ + for (i = 0; i < callable->nargs; i++) + callable_param_destroy(&callable->params[i]); - callable_param_destroy (&callable->retval); + callable_param_destroy(&callable->retval); - /* Unset the metatable / make the callable unusable */ - lua_pushnil (L); - lua_setmetatable (L, 1); - return 0; + /* Unset the metatable / make the callable unusable */ + lua_pushnil(L); + lua_setmetatable(L, 1); + return 0; } static void -callable_describe (lua_State *L, Callable *callable, FfiClosure *closure) +callable_describe(lua_State *L, Callable *callable, FfiClosure *closure) { - luaL_checkstack (L, 2, ""); - - if (closure == NULL) - lua_pushfstring (L, "%p", callable->address); - else - { - gconstpointer ptr; - lua_rawgeti (L, LUA_REGISTRYINDEX, closure->target_ref); - ptr = lua_topointer (L, -1); - if (ptr != NULL) - lua_pushfstring (L, "%s: %p", luaL_typename (L, -1), - lua_topointer (L, -1)); - else - lua_pushstring (L, luaL_typename (L, -1)); - lua_replace (L, -2); - } - - if (callable->info) - { - lua_pushfstring (L, "lua_gobject.%s (%s): ", - (GI_IS_FUNCTION_INFO (callable->info) ? "fun" : - (GI_IS_SIGNAL_INFO (callable->info) ? "sig" : - (GI_IS_VFUNC_INFO (callable->info) ? "vfn" : "cbk"))), - lua_tostring (L, -1)); - lua_concat (L, lua_gobject_type_get_name (L, GI_BASE_INFO (callable->info)) + 1); - } - else - { - lua_getfenv (L, 1); - lua_rawgeti (L, -1, 0); - lua_replace (L, -2); - lua_pushfstring (L, "lua_gobject.efn (%s): %s", lua_tostring (L, -2), - lua_tostring (L, -1)); - lua_replace (L, -2); - } - - lua_replace (L, -2); + luaL_checkstack(L, 2, ""); + + if (closure == NULL) + lua_pushfstring(L, "%p", callable->address); + else { + gconstpointer ptr; + lua_rawgeti(L, LUA_REGISTRYINDEX, closure->target_ref); + ptr = lua_topointer(L, -1); + if (ptr != NULL) + lua_pushfstring(L, "%s: %p", luaL_typename(L, -1), + lua_topointer(L, -1)); + else + lua_pushstring(L, luaL_typename(L, -1)); + lua_replace(L, -2); + } + + if (callable->info) { + lua_pushfstring(L, "lua_gobject.%s(%s): ", + (GI_IS_FUNCTION_INFO(callable->info) ? "fun" : + (GI_IS_SIGNAL_INFO(callable->info) ? "sig" : + (GI_IS_VFUNC_INFO(callable->info) ? "vfn" : "cbk"))), + lua_tostring(L, -1)); + lua_concat(L, lua_gobject_type_get_name(L, + GI_BASE_INFO(callable->info)) + 1); + } else { + lua_getfenv(L, 1); + lua_rawgeti(L, -1, 0); + lua_replace(L, -2); + lua_pushfstring(L, "lua_gobject.efn(%s): %s", lua_tostring(L, -2), + lua_tostring(L, -1)); + lua_replace(L, -2); + } + + lua_replace(L, -2); } static int -callable_tostring (lua_State *L) +callable_tostring(lua_State *L) { - Callable *callable = callable_get (L, 1); + Callable *callable = callable_get(L, 1); - callable_describe (L, callable, NULL); - return 1; + callable_describe(L, callable, NULL); + return 1; } static int -callable_param_2c (lua_State *L, Param *param, int narg, int parent, - GIArgument *arg, int callable_index, - Callable *callable, void **args) +callable_param_2c(lua_State *L, Param *param, int narg, int parent, + GIArgument *arg, int callable_index, + Callable *callable, void **args) { - int nret = 0; - if (param->kind == PARAM_KIND_ENUM && lua_type (L, narg) != LUA_TNUMBER) - { - /* Convert enum symbolic value to numeric one. */ - lua_getfenv (L, callable_index); - lua_rawgeti (L, -1, param->repotype_index); - lua_pushvalue (L, narg); - lua_call (L, 1, 1); - narg = -1; - } - - if (param->kind != PARAM_KIND_RECORD) - { - if (param->ti) - nret = lua_gobject_marshal_2c (L, param->ti, - param->has_arg_info ? ¶m->ai : NULL, - param->transfer, arg, narg, parent, - callable->info, args + callable->has_self); - else + int nret = 0; + if (param->kind == PARAM_KIND_ENUM + && lua_type(L, narg) != LUA_TNUMBER) { + /* Convert enum symbolic value to numeric one. */ + lua_getfenv(L, callable_index); + lua_rawgeti(L, -1, param->repotype_index); + lua_pushvalue(L, narg); + lua_call(L, 1, 1); + narg = -1; + } + + if (param->kind != PARAM_KIND_RECORD) { - union { GIArgument arg; int i; } *u = (gpointer) arg; - u->i = lua_tointeger (L, narg); + if (param->ti) + nret = lua_gobject_marshal_2c(L, param->ti, + param->has_arg_info ? ¶m->ai : NULL, + param->transfer, arg, narg, parent, + callable->info, args + callable->has_self); + else { + union { GIArgument arg; int i; } *u =(gpointer) arg; + u->i = lua_tointeger(L, narg); + } + + /* Stack cleanup from enum value conversion. */ + if (narg == -1) + lua_pop(L, 2); + } else { + /* Marshal record according to custom information. */ + lua_getfenv(L, callable_index); + lua_rawgeti(L, -1, param->repotype_index); + lua_gobject_record_2c(L, narg, &arg->v_pointer, FALSE, + param->transfer != GI_TRANSFER_NOTHING, TRUE, FALSE); + lua_pop(L, 1); } - /* Stack cleanup from enum value conversion. */ - if (narg == -1) - lua_pop (L, 2); - } - else - { - /* Marshal record according to custom information. */ - lua_getfenv (L, callable_index); - lua_rawgeti (L, -1, param->repotype_index); - lua_gobject_record_2c (L, narg, &arg->v_pointer, FALSE, - param->transfer != GI_TRANSFER_NOTHING, TRUE, FALSE); - lua_pop (L, 1); - } - - return nret; + return nret; } static void -callable_param_2lua (lua_State *L, Param *param, GIArgument *arg, - int parent, int callable_index, - Callable *callable, void **args) +callable_param_2lua(lua_State *L, Param *param, GIArgument *arg, + int parent, int callable_index, + Callable *callable, void **args) { - if (param->kind != PARAM_KIND_RECORD) - { - if (param->ti) - lua_gobject_marshal_2lua (L, param->ti, callable->info ? ¶m->ai : NULL, - param->dir, param->transfer, - arg, parent, callable->info, - args + callable->has_self); - else - { - union { GIArgument arg; ffi_sarg i; } *u = (gpointer) arg; - lua_pushinteger (L, u->i); + if (param->kind != PARAM_KIND_RECORD) { + if (param->ti) + lua_gobject_marshal_2lua( + L, + param->ti, + callable->info ? ¶m->ai : NULL, + param->dir, param->transfer, + arg, parent, callable->info, + args + callable->has_self); + else { + union { GIArgument arg; ffi_sarg i; } *u =(gpointer) arg; + lua_pushinteger(L, u->i); + } + } + + if (param->kind == PARAM_KIND_TI) + return; + + lua_getfenv(L, callable_index); + lua_rawgeti(L, -1, param->repotype_index); + if (param->kind == PARAM_KIND_RECORD) { + /* Marshal record according to custom information. */ + lua_gobject_record_2lua(L, arg->v_pointer, + param->transfer != GI_TRANSFER_NOTHING, parent); + lua_remove(L, -2); + } else { + /* Convert enum numeric value to symbolic one. */ + lua_pushvalue(L, -3); + lua_gettable(L, -2); + lua_replace(L, -4); + lua_pop(L, 2); } - } - - if (param->kind == PARAM_KIND_TI) - return; - - lua_getfenv (L, callable_index); - lua_rawgeti (L, -1, param->repotype_index); - if (param->kind == PARAM_KIND_RECORD) - { - /* Marshal record according to custom information. */ - lua_gobject_record_2lua (L, arg->v_pointer, - param->transfer != GI_TRANSFER_NOTHING, parent); - lua_remove (L, -2); - } - else - { - /* Convert enum numeric value to symbolic one. */ - lua_pushvalue (L, -3); - lua_gettable (L, -2); - lua_replace (L, -4); - lua_pop (L, 2); - } } static int -callable_call (lua_State *L) +callable_call(lua_State *L) { - Param *param; - int i, lua_argi, nret, caller_allocated = 0, nargs; - GIArgument retval, *args; - void **ffi_args, **redirect_out; - GError *err = NULL; - gpointer state_lock = lua_gobject_state_get_lock (L); - Callable *callable = callable_get (L, 1); - - /* Make sure that all unspecified arguments are set as nil; during - marshalling we might create temporary values on the stack, which - can be confused with input arguments expected but not passed by - caller. */ - lua_settop(L, callable->has_self + callable->nargs + 1); - - /* We cannot push more stuff than count of arguments we have. */ - luaL_checkstack (L, callable->nargs, ""); - - /* Prepare data for the call. */ - nargs = callable->nargs + callable->has_self; - args = g_newa (GIArgument, nargs); - redirect_out = g_newa (void *, nargs + callable->throws); - ffi_args = g_newa (void *, nargs + callable->throws); - - /* Prepare 'self', if present. */ - lua_argi = 2; - nret = 0; - if (callable->has_self) - { - GIBaseInfo *parent = gi_base_info_get_container (GI_BASE_INFO (callable->info)); - if (GI_IS_OBJECT_INFO (parent) || GI_IS_INTERFACE_INFO (parent)) - { - args[0].v_pointer = - lua_gobject_object_2c (L, 2, gi_registered_type_info_get_g_type (GI_REGISTERED_TYPE_INFO (parent)), - FALSE, FALSE, FALSE); - nret++; + Param *param; + int i, lua_argi, nret, caller_allocated = 0, nargs; + GIArgument retval, *args; + void **ffi_args, **redirect_out; + GError *err = NULL; + gpointer state_lock = lua_gobject_state_get_lock(L); + Callable *callable = callable_get(L, 1); + + /* Make sure that all unspecified arguments are set as nil; during marshalling we might create temporary values on the stack, which can be confused with input arguments expected but not passed by caller. */ + lua_settop(L, callable->has_self + callable->nargs + 1); + + /* We cannot push more stuff than count of arguments we have. */ + luaL_checkstack(L, callable->nargs, ""); + + /* Prepare data for the call. */ + nargs = callable->nargs + callable->has_self; + args = g_newa(GIArgument, nargs); + redirect_out = g_newa(void *, nargs + callable->throws); + ffi_args = g_newa(void *, nargs + callable->throws); + + /* Prepare 'self', if present. */ + lua_argi = 2; + nret = 0; + if (callable->has_self) { + GIBaseInfo *parent = gi_base_info_get_container( + GI_BASE_INFO(callable->info)); + if (GI_IS_OBJECT_INFO(parent) || GI_IS_INTERFACE_INFO(parent)) { + args[0].v_pointer = + lua_gobject_object_2c(L, 2, + gi_registered_type_info_get_g_type( + GI_REGISTERED_TYPE_INFO(parent)), + FALSE, FALSE, FALSE); + nret++; + } else { + lua_gobject_type_get_repotype(L, G_TYPE_INVALID, parent); + lua_gobject_record_2c(L, 2, &args[0].v_pointer, + FALSE, FALSE, FALSE, FALSE); + nret++; + } + + ffi_args[0] = &args[0]; + lua_argi++; } - else - { - lua_gobject_type_get_repotype (L, G_TYPE_INVALID, parent); - lua_gobject_record_2c (L, 2, &args[0].v_pointer, FALSE, FALSE, FALSE, FALSE); - nret++; + + /* Prepare proper call->ffi_args[] pointing to real args(or redirects in case of inout/out parameters). Note that this loop cannot be merged with following marshalling loop, because during marshalling of closure or arrays marshalling code can read/write values ahead of currently marshalled value. */ + param = &callable->params[0]; + for (i = 0; i < callable->nargs; i++, param++) { + /* Prepare ffi_args and redirection for out/inout parameters. */ + int argi = i + callable->has_self; + if (param->dir == GI_DIRECTION_IN) + ffi_args[argi] = &args[argi]; + else { + ffi_args[argi] = &redirect_out[argi]; + redirect_out[argi] = &args[argi]; + } + + if (param->n_closures > 0) { + args[argi].v_pointer = lua_gobject_closure_allocate(L, + param->n_closures); + if (param->call_scoped_user_data) + /* Add guard which releases closure block after the call. */ + *lua_gobject_guard_create(L, lua_gobject_closure_destroy) + = args[argi].v_pointer; + } } - ffi_args[0] = &args[0]; - lua_argi++; - } - - /* Prepare proper call->ffi_args[] pointing to real args (or - redirects in case of inout/out parameters). Note that this loop - cannot be merged with following marshalling loop, because during - marshalling of closure or arrays marshalling code can read/write - values ahead of currently marshalled value. */ - param = &callable->params[0]; - for (i = 0; i < callable->nargs; i++, param++) - { - /* Prepare ffi_args and redirection for out/inout parameters. */ - int argi = i + callable->has_self; - if (param->dir == GI_DIRECTION_IN) - ffi_args[argi] = &args[argi]; - else - { - ffi_args[argi] = &redirect_out[argi]; - redirect_out[argi] = &args[argi]; + /* Process input parameters. */ + nret = 0; + param = &callable->params[0]; + for (i = 0; i < callable->nargs; i++, param++) + if (!param->internal) { + int argi = i + callable->has_self; + if (param->dir != GI_DIRECTION_OUT) + nret += callable_param_2c(L, param, lua_argi++, 0, &args[argi], + 1, callable, ffi_args); + /* Special handling for out/caller-alloc structures; we have to manually pre-create them and store them on the stack. */ + else if (callable->info && gi_arg_info_is_caller_allocates(¶m->ai) + && lua_gobject_marshal_2c_caller_alloc(L, param->ti, + &args[argi], 0)) { + /* Even when marked as OUT, caller-allocates arguments + behave as if they are actually IN from libffi POV. */ + ffi_args[argi] = &args[argi]; + + /* Move the value on the stack *below* any already present + temporary values. */ + lua_insert(L, -nret - 1); + caller_allocated++; + } else + /* Normal OUT parameters. Ideally we don't have to touch them, but see https://github.com/lgi-devs/lgi/issues/118 */ + memset(&args[argi], 0, sizeof(args[argi])); + } else if (param->internal_user_data) + /* Provide userdata for the callback. */ + args[i + callable->has_self].v_pointer = callable->user_data; + + /* Add error for 'throws' type function. */ + if (callable->throws) { + redirect_out[nargs] = &err; + ffi_args[nargs] = &redirect_out[nargs]; } - if (param->n_closures > 0) - { - args[argi].v_pointer = lua_gobject_closure_allocate (L, param->n_closures); - if (param->call_scoped_user_data) - /* Add guard which releases closure block after the - call. */ - *lua_gobject_guard_create (L, lua_gobject_closure_destroy) = args[argi].v_pointer; + /* Unlock the state. */ + lua_gobject_state_leave(state_lock); + + /* Call the function. */ + ffi_call(&callable->cif, callable->address, &retval, ffi_args); + + /* Heading back to Lua, lock the state back again. */ + lua_gobject_state_enter(state_lock); + + /* Pop any temporary items from the stack which might be stored there by marshalling code. */ + lua_pop(L, nret); + + /* Handle return value. */ + nret = 0; + if (!callable->ignore_retval + && (callable->retval.ti == NULL + || (gi_type_info_get_tag(callable->retval.ti) + != GI_TYPE_TAG_VOID + || gi_type_info_is_pointer(callable->retval.ti)))) { + callable_param_2lua(L, &callable->retval, &retval, LUA_GOBJECT_PARENT_IS_RETVAL, + 1, callable, ffi_args); + nret++; + lua_insert(L, -caller_allocated - 1); + } else if (callable->ignore_retval) { + /* Make sure that returned boolean is converted according to ffi_call rules. */ + union { + GIArgument arg; + ffi_sarg s; + } *ru =(gpointer) &retval; + ru->arg.v_boolean =(gboolean) ru->s; } - } - - /* Process input parameters. */ - nret = 0; - param = &callable->params[0]; - for (i = 0; i < callable->nargs; i++, param++) - if (!param->internal) - { - int argi = i + callable->has_self; - if (param->dir != GI_DIRECTION_OUT) - nret += callable_param_2c (L, param, lua_argi++, 0, &args[argi], - 1, callable, ffi_args); - /* Special handling for out/caller-alloc structures; we have to - manually pre-create them and store them on the stack. */ - else if (callable->info && gi_arg_info_is_caller_allocates (¶m->ai) - && lua_gobject_marshal_2c_caller_alloc (L, param->ti, &args[argi], 0)) - { - /* Even when marked as OUT, caller-allocates arguments - behave as if they are actually IN from libffi POV. */ - ffi_args[argi] = &args[argi]; - - /* Move the value on the stack *below* any already present - temporary values. */ - lua_insert (L, -nret - 1); - caller_allocated++; - } - else - /* Normal OUT parameters. Ideally we don't have to touch - them, but see https://github.com/lgi-devs/lgi/issues/118 */ - memset (&args[argi], 0, sizeof (args[argi])); - } - else if (param->internal_user_data) - /* Provide userdata for the callback. */ - args[i + callable->has_self].v_pointer = callable->user_data; - - /* Add error for 'throws' type function. */ - if (callable->throws) - { - redirect_out[nargs] = &err; - ffi_args[nargs] = &redirect_out[nargs]; - } - - /* Unlock the state. */ - lua_gobject_state_leave (state_lock); - - /* Call the function. */ - ffi_call (&callable->cif, callable->address, &retval, ffi_args); - - /* Heading back to Lua, lock the state back again. */ - lua_gobject_state_enter (state_lock); - - /* Pop any temporary items from the stack which might be stored there by - marshalling code. */ - lua_pop (L, nret); - - /* Handle return value. */ - nret = 0; - if (!callable->ignore_retval - && (callable->retval.ti == NULL - || (gi_type_info_get_tag (callable->retval.ti) != GI_TYPE_TAG_VOID - || gi_type_info_is_pointer (callable->retval.ti)))) - { - callable_param_2lua (L, &callable->retval, &retval, LUA_GOBJECT_PARENT_IS_RETVAL, - 1, callable, ffi_args); - nret++; - lua_insert (L, -caller_allocated - 1); - } - else if (callable->ignore_retval) - { - /* Make sure that returned boolean is converted according to - ffi_call rules. */ - union { - GIArgument arg; - ffi_sarg s; - } *ru = (gpointer) &retval; - ru->arg.v_boolean = (gboolean) ru->s; - } - - /* Check, whether function threw. */ - if (err != NULL) - { - if (nret == 0) - { - lua_pushboolean (L, 0); - nret = 1; + + /* Check, whether function threw. */ + if (err != NULL) { + if (nret == 0) { + lua_pushboolean(L, 0); + nret = 1; + } + + /* Wrap error instance into GLib.Error record. */ + lua_gobject_type_get_repotype(L, G_TYPE_ERROR, NULL); + lua_gobject_record_2lua(L, err, TRUE, 0); + return nret + 1; } - /* Wrap error instance into GLib.Error record. */ - lua_gobject_type_get_repotype (L, G_TYPE_ERROR, NULL); - lua_gobject_record_2lua (L, err, TRUE, 0); - return nret + 1; - } - - /* Process output parameters. */ - param = &callable->params[0]; - for (i = 0; i < callable->nargs; i++, param++) - if (!param->internal && param->dir != GI_DIRECTION_IN) - { - if (callable->info && gi_arg_info_is_caller_allocates (¶m->ai) - && lua_gobject_marshal_2c_caller_alloc (L, param->ti, NULL, - -caller_allocated - nret)) - /* Caller allocated parameter is already marshalled and - lying on the stack. */ - caller_allocated--; - else - { - /* Marshal output parameter. */ - callable_param_2lua (L, param, &args[i + callable->has_self], - 0, 1, callable, ffi_args); - lua_insert (L, -caller_allocated - 1); - } - - /* In case that this callable is in ignore-retval mode and - function actually returned FALSE, replace the already - marshalled return value with NULL. */ - if (callable->ignore_retval && !retval.v_boolean) - { - lua_pushnil (L); - lua_replace (L, -caller_allocated - 2); - } - - nret++; - } - - /* When function can throw and we are not returning anything, be - sure to return at least 'true', so that caller can check for - error in a usual way (i.e. by Lua's assert() call). */ - if (nret == 0 && callable->throws) - { - lua_pushboolean (L, 1); - nret = 1; - } - - g_assert (caller_allocated == 0); - return nret; + /* Process output parameters. */ + param = &callable->params[0]; + for (i = 0; i < callable->nargs; i++, param++) + if (!param->internal && param->dir != GI_DIRECTION_IN) + { + if (callable->info && gi_arg_info_is_caller_allocates(¶m->ai) + && lua_gobject_marshal_2c_caller_alloc(L, + param->ti, NULL, -caller_allocated - nret)) + /* Caller allocated parameter is already marshalled and lying on the stack. */ + caller_allocated--; + else { + /* Marshal output parameter. */ + callable_param_2lua(L, param, &args[i + callable->has_self], + 0, 1, callable, ffi_args); + lua_insert(L, -caller_allocated - 1); + } + + /* In case that this callable is in ignore-retval mode and function actually returned FALSE, replace the already marshalled return value with NULL. */ + if (callable->ignore_retval && !retval.v_boolean) { + lua_pushnil(L); + lua_replace(L, -caller_allocated - 2); + } + + nret++; + } + + /* When function can throw and we are not returning anything, be sure to return at least 'true', so that caller can check for error in a usual way(i.e. by Lua's assert() call). */ + if (nret == 0 && callable->throws) { + lua_pushboolean(L, 1); + nret = 1; + } + + g_assert(caller_allocated == 0); + return nret; } static int -callable_index (lua_State *L) +callable_index(lua_State *L) { - Callable *callable = callable_get (L, 1); - const gchar *verb = lua_tostring (L, 2); - if (g_strcmp0 (verb, "info") == 0) - return lua_gobject_gi_info_new (L, gi_base_info_ref (callable->info)); - else if (g_strcmp0 (verb, "params") == 0) - { - int index = 1, i; - Param *param; - - lua_newtable (L); - if (callable->has_self) - { - lua_newtable (L); - lua_pushboolean (L, 1); - lua_setfield (L, -2, "in"); - lua_rawseti (L, -2, index++); + Callable *callable = callable_get(L, 1); + const gchar *verb = lua_tostring(L, 2); + if (g_strcmp0(verb, "info") == 0) + return lua_gobject_gi_info_new(L, gi_base_info_ref(callable->info)); + else if (g_strcmp0(verb, "params") == 0) { + int index = 1, i; + Param *param; + + lua_newtable(L); + if (callable->has_self) { + lua_newtable(L); + lua_pushboolean(L, 1); + lua_setfield(L, -2, "in"); + lua_rawseti(L, -2, index++); + } + for (i = 0, param = callable->params; i < callable->nargs; i++, param++) + if (!param->internal) { + lua_newtable(L); + /* Add name. */ + if (param->has_arg_info) { + lua_pushstring(L, gi_base_info_get_name(GI_BASE_INFO(¶m->ai))); + lua_setfield(L, -2, "name"); + } + + /* Add typeinfo. */ + if (param->ti) { + lua_gobject_gi_info_new(L, gi_base_info_ref(param->ti)); + lua_setfield(L, -2, "typeinfo"); + } + + /* Add in.out info. */ + if (param->dir == GI_DIRECTION_IN || + param->dir == GI_DIRECTION_INOUT) { + lua_pushboolean(L, 1); + lua_setfield(L, -2, "in"); + } + if (param->dir == GI_DIRECTION_OUT || + param->dir == GI_DIRECTION_INOUT) { + lua_pushboolean(L, 1); + lua_setfield(L, -2, "out"); + } + lua_rawseti(L, -2, index++); + } + return 1; + } else if (g_strcmp0(verb, "user_data") == 0) { + lua_pushlightuserdata(L, callable->user_data); + return 1; } - for (i = 0, param = callable->params; i < callable->nargs; i++, param++) - if (!param->internal) - { - lua_newtable (L); - /* Add name. */ - if (param->has_arg_info) - { - lua_pushstring (L, gi_base_info_get_name (GI_BASE_INFO (¶m->ai))); - lua_setfield (L, -2, "name"); - } - - /* Add typeinfo. */ - if (param->ti) - { - lua_gobject_gi_info_new (L, gi_base_info_ref (param->ti)); - lua_setfield (L, -2, "typeinfo"); - } - - /* Add in.out info. */ - if (param->dir == GI_DIRECTION_IN || - param->dir == GI_DIRECTION_INOUT) - { - lua_pushboolean (L, 1); - lua_setfield (L, -2, "in"); - } - if (param->dir == GI_DIRECTION_OUT || - param->dir == GI_DIRECTION_INOUT) - { - lua_pushboolean (L, 1); - lua_setfield (L, -2, "out"); - } - lua_rawseti (L, -2, index++); - } - return 1; - } - else if (g_strcmp0 (verb, "user_data") == 0) - { - lua_pushlightuserdata (L, callable->user_data); - return 1; - } - - return 0; + + return 0; } static int -callable_newindex (lua_State *L) +callable_newindex(lua_State *L) { - Callable *callable = callable_get (L, 1); - if (g_strcmp0 (lua_tostring (L, 2), "user_data") == 0) - callable->user_data = lua_touserdata (L, 3); + Callable *callable = callable_get(L, 1); + if (g_strcmp0(lua_tostring(L, 2), "user_data") == 0) + callable->user_data = lua_touserdata(L, 3); - return 0; + return 0; } static const struct luaL_Reg callable_reg[] = { - { "__gc", callable_gc }, - { "__tostring", callable_tostring }, - { "__call", callable_call }, - { "__index", callable_index }, - { "__newindex", callable_newindex }, - { NULL, NULL } + { "__gc", callable_gc }, + { "__tostring", callable_tostring }, + { "__call", callable_call }, + { "__index", callable_index }, + { "__newindex", callable_newindex }, + { NULL, NULL } }; static int -marshal_arguments (lua_State *L, void **args, int callable_index, Callable *callable) +marshal_arguments(lua_State *L, void **args, int callable_index, Callable *callable) { - Param *param; - int npos = 0, i; - - /* Marshall 'self' argument, if it is present. */ - if (callable->has_self) - { - GIBaseInfo *parent = gi_base_info_get_container (GI_BASE_INFO (callable->info)); - gpointer addr = ((GIArgument*) args[0])->v_pointer; - npos++; - if (GI_IS_OBJECT_INFO (parent) || GI_IS_INTERFACE_INFO (parent)) - lua_gobject_object_2lua (L, addr, FALSE, FALSE); - else if (GI_IS_STRUCT_INFO (parent) || GI_IS_UNION_INFO (parent)) - { - lua_gobject_type_get_repotype (L, G_TYPE_INVALID, parent); - lua_gobject_record_2lua (L, addr, FALSE, 0); + Param *param; + int npos = 0, i; + + /* Marshall 'self' argument, if it is present. */ + if (callable->has_self) { + GIBaseInfo *parent = gi_base_info_get_container(GI_BASE_INFO(callable->info)); + gpointer addr =((GIArgument*) args[0])->v_pointer; + npos++; + if (GI_IS_OBJECT_INFO(parent) || GI_IS_INTERFACE_INFO(parent)) + lua_gobject_object_2lua(L, addr, FALSE, FALSE); + else if (GI_IS_STRUCT_INFO(parent) || GI_IS_UNION_INFO(parent)) { + lua_gobject_type_get_repotype(L, G_TYPE_INVALID, parent); + lua_gobject_record_2lua(L, addr, FALSE, 0); + } else + g_assert_not_reached(); } - else - g_assert_not_reached (); - } - - /* Marshal input arguments to lua. */ - param = callable->params; - for (i = 0; i < callable->nargs; ++i, ++param) - if (!param->internal && param->dir != GI_DIRECTION_OUT) - { - if G_LIKELY (i != 3 || !callable->is_closure_marshal) - { - GIArgument *real_arg = args[i + callable->has_self]; - GIArgument arg_value; - - if (param->dir == GI_DIRECTION_INOUT) - { - arg_value = *(GIArgument *) real_arg->v_pointer; - real_arg = &arg_value; - } - - callable_param_2lua (L, param, real_arg, 0, - callable_index, callable, - args + callable->has_self); - } - else - { - /* Workaround incorrectly annotated but crucial - ClosureMarshal callback. Its 3rd argument is actually - an array of GValue, not a single GValue as missing - annotation suggests. */ - guint i, nvals = ((GIArgument *)args[2])->v_uint32; - GValue* vals = ((GIArgument *)args[3])->v_pointer; - lua_createtable (L, nvals, 0); - for (i = 0; i < nvals; ++i) - { - lua_pushinteger (L, i + 1); - lua_gobject_type_get_repotype (L, G_TYPE_VALUE, NULL); - lua_gobject_record_2lua (L, &vals[i], FALSE, 0); - lua_settable (L, -3); - } - } - npos++; - } - - return npos; + + /* Marshal input arguments to lua. */ + param = callable->params; + for (i = 0; i < callable->nargs; ++i, ++param) + if (!param->internal && param->dir != GI_DIRECTION_OUT) { + if G_LIKELY(i != 3 || !callable->is_closure_marshal) { + GIArgument *real_arg = args[i + callable->has_self]; + GIArgument arg_value; + + if (param->dir == GI_DIRECTION_INOUT) { + arg_value = *(GIArgument *) real_arg->v_pointer; + real_arg = &arg_value; + } + + callable_param_2lua(L, param, real_arg, 0, + callable_index, callable, args + callable->has_self); + } else { + /* Workaround incorrectly annotated but crucial ClosureMarshal callback. Its 3rd argument is actually an array of GValue, not a single GValue as missing annotation suggests. */ + guint i, nvals =((GIArgument *)args[2])->v_uint32; + GValue* vals =((GIArgument *)args[3])->v_pointer; + lua_createtable(L, nvals, 0); + for (i = 0; i < nvals; ++i) { + lua_pushinteger(L, i + 1); + lua_gobject_type_get_repotype(L, G_TYPE_VALUE, NULL); + lua_gobject_record_2lua(L, &vals[i], FALSE, 0); + lua_settable(L, -3); + } + } + npos++; + } + + return npos; } static void -marshal_return_values (lua_State *L, void *ret, void **args, int callable_index, Callable *callable, int npos) +marshal_return_values(lua_State *L, void *ret, void **args, int callable_index, Callable *callable, int npos) { - int to_pop, i; - GITypeTag tag; - Param *param; - - /* Make sure that all unspecified returns and outputs are set as - nil; during marshalling we might create temporary values on - the stack, which can be confused with output values expected - but not passed by caller. */ - lua_settop(L, lua_gettop (L) + callable->has_self + callable->nargs + 1); - - /* Marshal return value from Lua. */ - tag = gi_type_info_get_tag (callable->retval.ti); - if (tag != GI_TYPE_TAG_VOID - || gi_type_info_is_pointer (callable->retval.ti)) - { - if (callable->ignore_retval) - /* Return value should be ignored on Lua side, so we have - to synthesize the return value for C side. We should - return FALSE if next output argument is nil. */ - *(ffi_sarg *) ret = lua_isnoneornil (L, npos) ? FALSE : TRUE; - else - { - to_pop = callable_param_2c (L, &callable->retval, npos, - LUA_GOBJECT_PARENT_IS_RETVAL, ret, - callable_index, callable, - args + callable->has_self); - if (to_pop != 0) - { - g_warning ("cbk `%s.%s': return (transfer none) %d, unsafe!", - gi_base_info_get_namespace (GI_BASE_INFO (callable->info)), - gi_base_info_get_name (GI_BASE_INFO (callable->info)), to_pop); - lua_pop (L, to_pop); - } - - npos++; + int to_pop, i; + GITypeTag tag; + Param *param; + + /* Make sure that all unspecified returns and outputs are set as + nil; during marshalling we might create temporary values on + the stack, which can be confused with output values expected + but not passed by caller. */ + lua_settop(L, lua_gettop(L) + callable->has_self + callable->nargs + 1); + + /* Marshal return value from Lua. */ + tag = gi_type_info_get_tag(callable->retval.ti); + if (tag != GI_TYPE_TAG_VOID + || gi_type_info_is_pointer(callable->retval.ti)) { + if (callable->ignore_retval) + /* Return value should be ignored on Lua side, so we have to synthesize the return value for C side. We should return FALSE if next output argument is nil. */ + *(ffi_sarg *) ret = lua_isnoneornil(L, npos) ? FALSE : TRUE; + else { + to_pop = callable_param_2c(L, &callable->retval, npos, + LUA_GOBJECT_PARENT_IS_RETVAL, ret, + callable_index, callable, + args + callable->has_self); + if (to_pop != 0) { + g_warning("cbk `%s.%s': return(transfer none) %d, unsafe!", + gi_base_info_get_namespace( + GI_BASE_INFO(callable->info)), + gi_base_info_get_name( + GI_BASE_INFO(callable->info)), to_pop); + lua_pop(L, to_pop); + } + + npos++; + } + } + + /* Marshal output arguments from Lua. */ + param = callable->params; + for (i = 0; i < callable->nargs; ++i, ++param) + if (!param->internal && param->dir != GI_DIRECTION_IN) { + gpointer *arg = args[i + callable->has_self]; + gboolean caller_alloc = + callable->info && gi_arg_info_is_caller_allocates(¶m->ai) + && gi_type_info_get_tag(param->ti) == GI_TYPE_TAG_INTERFACE; + to_pop = callable_param_2c(L, param, npos, + caller_alloc ? LUA_GOBJECT_PARENT_CALLER_ALLOC : 0, + *arg, callable_index, callable, args + callable->has_self); + if (to_pop != 0) { + g_warning("cbk %s.%s: arg `%s'(transfer none) %d, unsafe!", + gi_base_info_get_namespace(GI_BASE_INFO(callable->info)), + gi_base_info_get_name(GI_BASE_INFO(callable->info)), + gi_base_info_get_name(GI_BASE_INFO(¶m->ai)), to_pop); + lua_pop(L, to_pop); + } + + npos++; } - } - - /* Marshal output arguments from Lua. */ - param = callable->params; - for (i = 0; i < callable->nargs; ++i, ++param) - if (!param->internal && param->dir != GI_DIRECTION_IN) - { - gpointer *arg = args[i + callable->has_self]; - gboolean caller_alloc = - callable->info && gi_arg_info_is_caller_allocates (¶m->ai) - && gi_type_info_get_tag (param->ti) == GI_TYPE_TAG_INTERFACE; - to_pop = callable_param_2c (L, param, npos, caller_alloc - ? LUA_GOBJECT_PARENT_CALLER_ALLOC : 0, *arg, - callable_index, callable, - args + callable->has_self); - if (to_pop != 0) - { - g_warning ("cbk %s.%s: arg `%s' (transfer none) %d, unsafe!", - gi_base_info_get_namespace (GI_BASE_INFO (callable->info)), - gi_base_info_get_name (GI_BASE_INFO (callable->info)), - gi_base_info_get_name (GI_BASE_INFO (¶m->ai)), to_pop); - lua_pop (L, to_pop); - } - - npos++; - } } static void -marshal_return_error (lua_State *L, void *ret, void **args, Callable *callable) +marshal_return_error(lua_State *L, void *ret, void **args, Callable *callable) { - /* If the function is expected to return errors, create proper - error. */ - GError **err = ((GIArgument *) args[callable->has_self + - callable->nargs])->v_pointer; - - /* Check, whether thrown error is actually GLib.Error instance. */ - lua_gobject_type_get_repotype (L, G_TYPE_ERROR, NULL); - lua_gobject_record_2c (L, -2, err, FALSE, TRUE, TRUE, TRUE); - if (*err == NULL) - { - /* Nope, so come up with something funny. */ - GQuark q = g_quark_from_static_string ("lua_gobject-callback-error-quark"); - g_set_error_literal (err, q, 1, lua_tostring (L, -1)); - lua_pop (L, 1); - } - - /* Such function should usually return FALSE, so do it. */ - if (gi_type_info_get_tag (callable->retval.ti) == GI_TYPE_TAG_BOOLEAN) - *(gboolean *) ret = FALSE; + /* If the function is expected to return errors, create proper error. */ + GError **err =((GIArgument *) args[callable->has_self + + callable->nargs])->v_pointer; + + /* Check, whether thrown error is actually GLib.Error instance. */ + lua_gobject_type_get_repotype(L, G_TYPE_ERROR, NULL); + lua_gobject_record_2c(L, -2, err, FALSE, TRUE, TRUE, TRUE); + if (*err == NULL) { + /* Nope, so come up with something funny. */ + GQuark q = g_quark_from_static_string( + "lua_gobject-callback-error-quark"); + g_set_error_literal(err, q, 1, lua_tostring(L, -1)); + lua_pop(L, 1); + } + + /* Such function should usually return FALSE, so do it. */ + if (gi_type_info_get_tag(callable->retval.ti) == GI_TYPE_TAG_BOOLEAN) + *(gboolean *) ret = FALSE; } /* Closure callback, called by libffi when C code wants to invoke Lua - callback. */ + callback. */ static void -closure_callback (ffi_cif *cif, void *ret, void **args, void *closure_arg) +closure_callback(ffi_cif *cif, void *ret, void **args, void *closure_arg) { - Callable *callable; - int callable_index; - FfiClosure *closure = closure_arg; - FfiClosureBlock *block = closure->block; - gint res = 0, npos, stacktop, extra_args = 0; - gboolean call; - lua_State *L; - lua_State *marshal_L; - (void)cif; - - /* Get access to proper Lua context. */ - lua_gobject_state_enter (block->callback.state_lock); - lua_rawgeti (block->callback.L, LUA_REGISTRYINDEX, block->callback.thread_ref); - L = lua_tothread (block->callback.L, -1); - call = (closure->target_ref != LUA_NOREF); - if (call) - { - /* We will call target method, prepare context/thread to do - it. */ - if (lua_status (L) != 0) - { - /* Thread is not in usable state for us, it is suspended, we - cannot afford to resume it, because it is possible that - the routine we are about to call is actually going to - resume it. Create new thread instead and switch closure - to its context. */ - lua_State *newL = lua_newthread (L); - lua_rawseti (L, LUA_REGISTRYINDEX, block->callback.thread_ref); - L = newL; + Callable *callable; + int callable_index; + FfiClosure *closure = closure_arg; + FfiClosureBlock *block = closure->block; + gint res = 0, npos, stacktop, extra_args = 0; + gboolean call; + lua_State *L; + lua_State *marshal_L; + (void)cif; + + /* Get access to proper Lua context. */ + lua_gobject_state_enter(block->callback.state_lock); + lua_rawgeti(block->callback.L, + LUA_REGISTRYINDEX, block->callback.thread_ref); + L = lua_tothread(block->callback.L, -1); + call =(closure->target_ref != LUA_NOREF); + if (call) { + /* We will call target method, prepare context/thread to do it. */ + if (lua_status(L) != 0) + { + /* Thread is not in usable state for us, it is suspended, we cannot afford to resume it, because it is possible that the routine we are about to call is actually going to resume it. Create new thread instead and switch closure to its context. */ + lua_State *newL = lua_newthread(L); + lua_rawseti(L, LUA_REGISTRYINDEX, block->callback.thread_ref); + L = newL; + } + lua_pop(block->callback.L, 1); + block->callback.L = L; + + /* Remember stacktop, this is the position on which we should + expect return values(note that callback_prepare_call already + might have pushed function to be executed to the stack). */ + stacktop = lua_gettop(L); + + /* Store function to be invoked to the stack. */ + lua_rawgeti(L, LUA_REGISTRYINDEX, closure->target_ref); + } else { + /* Cleanup the stack of the original thread. */ + lua_pop(block->callback.L, 1); + stacktop = lua_gettop(L); + if (lua_status(L) == 0) { + /* Thread is not suspended yet, so it contains initial function at the top of the stack, so count with it. */ + stacktop--; + extra_args++; + } } - lua_pop (block->callback.L, 1); - block->callback.L = L; - - /* Remember stacktop, this is the position on which we should - expect return values (note that callback_prepare_call already - might have pushed function to be executed to the stack). */ - stacktop = lua_gettop (L); - - /* Store function to be invoked to the stack. */ - lua_rawgeti (L, LUA_REGISTRYINDEX, closure->target_ref); - } - else - { - /* Cleanup the stack of the original thread. */ - lua_pop (block->callback.L, 1); - stacktop = lua_gettop (L); - if (lua_status (L) == 0) - { - /* Thread is not suspended yet, so it contains initial - function at the top of the stack, so count with it. */ - stacktop--; - extra_args++; + + /* Pick a coroutine used for marshalling */ + marshal_L = L; + if (lua_status(marshal_L) == LUA_YIELD) { + lua_pushlightuserdata(L, &marshalling_L_address); + lua_rawget(L, LUA_REGISTRYINDEX); + marshal_L = lua_tothread(L, -1); + lua_pop(L, 1); + g_assert(lua_gettop(marshal_L) == 0); } - } - - /* Pick a coroutine used for marshalling */ - marshal_L = L; - if (lua_status (marshal_L) == LUA_YIELD) - { - lua_pushlightuserdata (L, &marshalling_L_address); - lua_rawget (L, LUA_REGISTRYINDEX); - marshal_L = lua_tothread (L, -1); - lua_pop (L, 1); - g_assert (lua_gettop (marshal_L) == 0); - } - - /* Get access to Callable structure. */ - lua_rawgeti (marshal_L, LUA_REGISTRYINDEX, closure->callable_ref); - callable = lua_touserdata (marshal_L, -1); - callable_index = lua_gettop (marshal_L); - - npos = marshal_arguments (marshal_L, args, callable_index, callable); - - /* Remove callable userdata from callable_index, otherwise they mess - up carefully prepared stack structure. */ - lua_remove (marshal_L, callable_index); - - /* Call it. */ - lua_xmove (marshal_L, L, npos + extra_args); - if (L != marshal_L) - g_assert (lua_gettop (marshal_L) == 0); - if (call) - { - if (callable->throws) - res = lua_pcall (L, npos, LUA_MULTRET, 0); - else if (lua_pcall (L, npos, LUA_MULTRET, 0) != 0) - { - callable_describe (L, callable, closure); - g_warning ("Error raised while calling '%s': %s", - lua_tostring (L, -1), lua_tostring (L, -2)); - lua_pop (L, 2); - } - } - else - { + + /* Get access to Callable structure. */ + lua_rawgeti(marshal_L, LUA_REGISTRYINDEX, closure->callable_ref); + callable = lua_touserdata(marshal_L, -1); + callable_index = lua_gettop(marshal_L); + + npos = marshal_arguments(marshal_L, args, callable_index, callable); + + /* Remove callable userdata from callable_index, otherwise they mess up carefully prepared stack structure. */ + lua_remove(marshal_L, callable_index); + + /* Call it. */ + lua_xmove(marshal_L, L, npos + extra_args); + if (L != marshal_L) + g_assert(lua_gettop(marshal_L) == 0); + if (call) { + if (callable->throws) + res = lua_pcall(L, npos, LUA_MULTRET, 0); + else if (lua_pcall(L, npos, LUA_MULTRET, 0) != 0) { + callable_describe(L, callable, closure); + g_warning("Error raised while calling '%s': %s", + lua_tostring(L, -1), lua_tostring(L, -2)); + lua_pop(L, 2); + } + } else { #if LUA_VERSION_NUM >= 504 - int nresults; - res = lua_resume (L, NULL, npos, &nresults); + int nresults; + res = lua_resume(L, NULL, npos, &nresults); #elif LUA_VERSION_NUM >= 502 - res = lua_resume (L, NULL, npos); + res = lua_resume(L, NULL, npos); #else - res = lua_resume (L, npos); + res = lua_resume(L, npos); #endif - if (res == LUA_YIELD) - /* For our purposes is YIELD the same as if the coro really - returned. */ - res = 0; - else if (res == LUA_ERRRUN && !callable->throws) - { - /* If closure is not allowed to return errors and coroutine - finished with error, rethrow the error in the context of - the original thread. */ - lua_xmove (L, block->callback.L, 1); - lua_error (block->callback.L); + if (res == LUA_YIELD) + /* For our purposes is YIELD the same as if the coro really returned. */ + res = 0; + else if (res == LUA_ERRRUN && !callable->throws) { + /* If closure is not allowed to return errors and coroutine finished with error, rethrow the error in the context of the original thread. */ + lua_xmove(L, block->callback.L, 1); + lua_error(block->callback.L); + } + + /* If coroutine somehow consumed more than expected(?), do not + blow up, adjust to the new situation. */ + if (stacktop > lua_gettop(L)) + stacktop = lua_gettop(L); } - /* If coroutine somehow consumed more than expected(?), do not - blow up, adjust to the new situation. */ - if (stacktop > lua_gettop (L)) - stacktop = lua_gettop (L); - } - - lua_xmove (L, marshal_L, lua_gettop(L) - stacktop); - - /* Reintroduce callable to the stack, we might need it during - marshalling of the response. Put it right before all returns. */ - lua_rawgeti (marshal_L, LUA_REGISTRYINDEX, closure->callable_ref); - lua_insert (marshal_L, stacktop + 1); - callable_index = stacktop + 1; - npos = stacktop + 2; - - /* Check, whether we can report an error here. */ - if (res == 0) - marshal_return_values (marshal_L, ret, args, callable_index, callable, npos); - else - marshal_return_error (marshal_L, ret, args, callable); - - /* If the closure is marked as autodestroy, destroy it now. Note that it is - unfortunately not possible to destroy it directly here, because we would - delete the code under our feet and crash and burn :-(. Instead, we create - marshal guard and leave it to GC to destroy the closure later. */ - if (closure->autodestroy) - *lua_gobject_guard_create (L, lua_gobject_closure_destroy) = block; - - /* This is NOT called by Lua, so we better leave the Lua stack we - used pretty much tidied. */ - lua_settop (L, stacktop); - if (L != marshal_L) - lua_settop (marshal_L, 0); - - /* Going back to C code, release the state synchronization. */ - lua_gobject_state_leave (block->callback.state_lock); + lua_xmove(L, marshal_L, lua_gettop(L) - stacktop); + + /* Reintroduce callable to the stack, we might need it during marshalling of the response. Put it right before all returns. */ + lua_rawgeti(marshal_L, LUA_REGISTRYINDEX, closure->callable_ref); + lua_insert(marshal_L, stacktop + 1); + callable_index = stacktop + 1; + npos = stacktop + 2; + + /* Check, whether we can report an error here. */ + if (res == 0) + marshal_return_values(marshal_L, ret, args, callable_index, callable, npos); + else + marshal_return_error(marshal_L, ret, args, callable); + + /* If the closure is marked as autodestroy, destroy it now. Note that it is unfortunately not possible to destroy it directly here, because we would delete the code under our feet and crash and burn :-(. Instead, we create marshal guard and leave it to GC to destroy the closure later. */ + if (closure->autodestroy) + *lua_gobject_guard_create(L, lua_gobject_closure_destroy) = block; + + /* This is NOT called by Lua, so we better leave the Lua stack we used pretty much tidied. */ + lua_settop(L, stacktop); + if (L != marshal_L) + lua_settop(marshal_L, 0); + + /* Going back to C code, release the state synchronization. */ + lua_gobject_state_leave(block->callback.state_lock); } /* Destroys specified closure. */ void -lua_gobject_closure_destroy (gpointer user_data) +lua_gobject_closure_destroy(gpointer user_data) { - FfiClosureBlock* block = user_data; - lua_State *L = block->callback.L; - FfiClosure *closure; - int i; - - for (i = block->closures_count - 1; i >= -1; --i) - { - closure = (i < 0) ? &block->ffi_closure : block->ffi_closures[i]; - if (closure->created) - { - luaL_unref (L, LUA_REGISTRYINDEX, closure->callable_ref); - luaL_unref (L, LUA_REGISTRYINDEX, closure->target_ref); + FfiClosureBlock* block = user_data; + lua_State *L = block->callback.L; + FfiClosure *closure; + int i; + + for (i = block->closures_count - 1; i >= -1; --i) { + closure =(i < 0) ? &block->ffi_closure : block->ffi_closures[i]; + if (closure->created) { + luaL_unref(L, LUA_REGISTRYINDEX, closure->callable_ref); + luaL_unref(L, LUA_REGISTRYINDEX, closure->target_ref); + } + if (i < 0) + luaL_unref(L, LUA_REGISTRYINDEX, block->callback.thread_ref); + ffi_closure_free(closure); } - if (i < 0) - luaL_unref (L, LUA_REGISTRYINDEX, block->callback.thread_ref); - ffi_closure_free (closure); - } } -/* Creates container block for allocated closures. Returns address of - the block, suitable as user_data parameter. */ +/* Creates container block for allocated closures. Returns address of the block, suitable as user_data parameter. */ gpointer -lua_gobject_closure_allocate (lua_State *L, int count) +lua_gobject_closure_allocate(lua_State *L, int count) { - gpointer call_addr; - int i; - - /* Allocate header block. */ - FfiClosureBlock *block = - ffi_closure_alloc (offsetof (FfiClosureBlock, ffi_closures) - + (--count * sizeof (FfiClosure*)), &call_addr); - block->ffi_closure.created = 0; - block->ffi_closure.call_addr = call_addr; - block->ffi_closure.block = block; - block->closures_count = count; - - /* Allocate all additional closures. */ - for (i = 0; i < count; ++i) - { - block->ffi_closures[i] = ffi_closure_alloc (sizeof (FfiClosure), - &call_addr); - block->ffi_closures[i]->created = 0; - block->ffi_closures[i]->call_addr = call_addr; - block->ffi_closures[i]->block = block; - } - - /* Store reference to target Lua thread. */ - block->callback.L = L; - lua_pushthread (L); - block->callback.thread_ref = luaL_ref (L, LUA_REGISTRYINDEX); - - /* Retrieve and remember state lock. */ - block->callback.state_lock = lua_gobject_state_get_lock (L); - return block; + gpointer call_addr; + int i; + + /* Allocate header block. */ + FfiClosureBlock *block = + ffi_closure_alloc(offsetof(FfiClosureBlock, ffi_closures) + +(--count * sizeof(FfiClosure*)), &call_addr); + block->ffi_closure.created = 0; + block->ffi_closure.call_addr = call_addr; + block->ffi_closure.block = block; + block->closures_count = count; + + /* Allocate all additional closures. */ + for (i = 0; i < count; ++i) { + block->ffi_closures[i] = ffi_closure_alloc(sizeof(FfiClosure), &call_addr); + block->ffi_closures[i]->created = 0; + block->ffi_closures[i]->call_addr = call_addr; + block->ffi_closures[i]->block = block; + } + + /* Store reference to target Lua thread. */ + block->callback.L = L; + lua_pushthread(L); + block->callback.thread_ref = luaL_ref(L, LUA_REGISTRYINDEX); + + /* Retrieve and remember state lock. */ + block->callback.state_lock = lua_gobject_state_get_lock(L); + return block; } /* Creates closure from Lua function to be passed to C. */ gpointer -lua_gobject_closure_create (lua_State *L, gpointer user_data, - int target, gboolean autodestroy) +lua_gobject_closure_create(lua_State *L, gpointer user_data, + int target, gboolean autodestroy) { - FfiClosureBlock* block = user_data; - FfiClosure *closure; - Callable *callable; - gpointer call_addr; - int i; - - /* Find pointer to target FfiClosure. */ - for (closure = &block->ffi_closure, i = 0; closure->created; ++i) - { - g_assert (i < block->closures_count); - closure = block->ffi_closures[i]; - } - - /* Prepare callable and store reference to it. */ - callable = lua_touserdata (L, -1); - call_addr = closure->call_addr; - closure->created = 1; - closure->autodestroy = autodestroy; - closure->callable_ref = luaL_ref (L, LUA_REGISTRYINDEX); - if (!lua_isthread (L, target)) - { - lua_pushvalue (L, target); - closure->target_ref = luaL_ref (L, LUA_REGISTRYINDEX); - } - else - { - /* Switch thread_ref to actual target thread. */ - lua_pushvalue (L, target); - lua_rawseti (L, LUA_REGISTRYINDEX, block->callback.thread_ref); - closure->target_ref = LUA_NOREF; - } - - /* Create closure. */ - if (ffi_prep_closure_loc (&closure->ffi_closure, &callable->cif, - closure_callback, closure, call_addr) != FFI_OK) - { - lua_concat (L, lua_gobject_type_get_name (L, GI_BASE_INFO (callable->info))); - luaL_error (L, "failed to prepare closure for `%'", lua_tostring (L, -1)); - return NULL; - } - - return call_addr; + FfiClosureBlock* block = user_data; + FfiClosure *closure; + Callable *callable; + gpointer call_addr; + int i; + + /* Find pointer to target FfiClosure. */ + for (closure = &block->ffi_closure, i = 0; closure->created; ++i) { + g_assert(i < block->closures_count); + closure = block->ffi_closures[i]; + } + + /* Prepare callable and store reference to it. */ + callable = lua_touserdata(L, -1); + call_addr = closure->call_addr; + closure->created = 1; + closure->autodestroy = autodestroy; + closure->callable_ref = luaL_ref(L, LUA_REGISTRYINDEX); + if (!lua_isthread(L, target)) { + lua_pushvalue(L, target); + closure->target_ref = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + /* Switch thread_ref to actual target thread. */ + lua_pushvalue(L, target); + lua_rawseti(L, LUA_REGISTRYINDEX, block->callback.thread_ref); + closure->target_ref = LUA_NOREF; + } + + /* Create closure. */ + if (ffi_prep_closure_loc(&closure->ffi_closure, &callable->cif, + closure_callback, closure, call_addr) != FFI_OK) { + lua_concat(L, lua_gobject_type_get_name(L, + GI_BASE_INFO(callable->info))); + luaL_error(L, "failed to prepare closure for `%'", lua_tostring(L, -1)); + return NULL; + } + + return call_addr; } /* Creates new Callable instance according to given gi.info. Lua prototype: - callable = callable.new(callable_info[, addr]) or - callable = callable.new(description_table[, addr]) */ +callable = callable.new(callable_info[, addr]) or +callable = callable.new(description_table[, addr]) */ static int -callable_new (lua_State *L) +callable_new(lua_State *L) { - gpointer addr = lua_touserdata (L, 2); - if (lua_istable (L, 1)) - return lua_gobject_callable_parse (L, 1, addr); - else - return lua_gobject_callable_create (L, *(GICallableInfo **) - luaL_checkudata (L, 1, LUA_GOBJECT_GI_INFO), - addr); + gpointer addr = lua_touserdata(L, 2); + if (lua_istable(L, 1)) + return lua_gobject_callable_parse(L, 1, addr); + else + return lua_gobject_callable_create(L, *(GICallableInfo **) + luaL_checkudata(L, 1, LUA_GOBJECT_GI_INFO), + addr); } /* Callable module public API table. */ static const luaL_Reg callable_api_reg[] = { - { "new", callable_new }, - { NULL, NULL } + { "new", callable_new }, + { NULL, NULL } }; void -lua_gobject_callable_init (lua_State *L) +lua_gobject_callable_init(lua_State *L) { - /* Create a thread for marshalling arguments to yielded threads, register it - * so that it is not GC'd. */ - lua_pushlightuserdata (L, &marshalling_L_address); - lua_newthread (L); - lua_rawset (L, LUA_REGISTRYINDEX); - - /* Register callable metatable. */ - lua_pushlightuserdata (L, &callable_mt); - lua_newtable (L); - luaL_register (L, NULL, callable_reg); - lua_rawset (L, LUA_REGISTRYINDEX); - - /* Create cache for callables. */ - lua_gobject_cache_create (L, &callable_cache, NULL); - - /* Create public api for callable module. */ - lua_newtable (L); - luaL_register (L, NULL, callable_api_reg); - lua_setfield (L, -2, "callable"); + /* Create a thread for marshalling arguments to yielded threads, register it so that it is not GC'd. */ + lua_pushlightuserdata(L, &marshalling_L_address); + lua_newthread(L); + lua_rawset(L, LUA_REGISTRYINDEX); + + /* Register callable metatable. */ + lua_pushlightuserdata(L, &callable_mt); + lua_newtable(L); + luaL_register(L, NULL, callable_reg); + lua_rawset(L, LUA_REGISTRYINDEX); + + /* Create cache for callables. */ + lua_gobject_cache_create(L, &callable_cache, NULL); + + /* Create public api for callable module. */ + lua_newtable(L); + luaL_register(L, NULL, callable_api_reg); + lua_setfield(L, -2, "callable"); } - diff --git a/LuaGObject/class.lua b/LuaGObject/class.lua index f834cd66..6cb34b3f 100644 --- a/LuaGObject/class.lua +++ b/LuaGObject/class.lua @@ -1,17 +1,13 @@ ------------------------------------------------------------------------------- --- -- LGI Support for generic GType objects and interfaces -- -- Copyright (c) 2010, 2011, 2012, 2013 Pavel Holejsovsky -- Licensed under the MIT license: -- http://www.opensource.org/licenses/mit-license.php --- ------------------------------------------------------------------------------- local type, tostring, rawget, rawset, pairs, select, -getmetatable, setmetatable, error, assert - = type, tostring, rawget, rawset, pairs, select, - getmetatable, setmetatable, error, assert + getmetatable, setmetatable, error, assert + = type, tostring, rawget, rawset, pairs, select, + getmetatable, setmetatable, error, assert local string = require 'string' local core = require 'LuaGObject.core' @@ -24,21 +20,21 @@ local GObject = assert(gi.require('GObject')) -- Implementation of class and interface component loading. local class = { - class_mt = component.mt:clone( - 'class', { '_virtual', '_property', '_signal', - '_method', '_constant', '_field' }), - interface_mt = component.mt:clone( - 'interface', { '_virtual', '_property', '_signal', - '_method', '_constant' }), + class_mt = component.mt:clone( + 'class', { '_virtual', '_property', '_signal', + '_method', '_constant', '_field' }), + interface_mt = component.mt:clone( + 'interface', { '_virtual', '_property', '_signal', + '_method', '_constant' }), } local type_class_peek = core.callable.new { - addr = GObject.resolve.g_type_class_peek, - ret = ti.ptr, ti.GType + addr = GObject.resolve.g_type_class_peek, + ret = ti.ptr, ti.GType } local type_interface_peek = core.callable.new { - addr = GObject.resolve.g_type_interface_peek, - ret = ti.ptr, ti.ptr, ti.GType + addr = GObject.resolve.g_type_interface_peek, + ret = ti.ptr, ti.ptr, ti.GType } local type_class = component.create(nil, record.struct_mt) @@ -48,347 +44,340 @@ ffi.load_fields(type_instance, { { 'g_class', type_class, ptr = true } }) -- Checks whether given argument is type of this class. function class.class_mt:is_type_of(instance) - if type(instance) == 'userdata' then - local instance_type = core.object.query(instance, 'repo') - while instance_type do - if instance_type == self - or instance_type._implements[self._name] == self then - return true - end - instance_type = rawget(instance_type, '_parent') - end - end - return false + if type(instance) == 'userdata' then + local instance_type = core.object.query(instance, 'repo') + while instance_type do + if instance_type == self + or instance_type._implements[self._name] == self then + return true + end + instance_type = rawget(instance_type, '_parent') + end + end + return false end class.interface_mt.is_type_of = class.class_mt.is_type_of local function load_signal_name(name) - name = name:match('^on_(.+)$') - return name and name:gsub('_', '-') + name = name:match('^on_(.+)$') + return name and name:gsub('_', '-') end local function load_signal_name_reverse(name) - return 'on_' .. name:gsub('%-', '_') + return 'on_' .. name:gsub('%-', '_') end local function load_vfunc_name(name) - return name:match('^do_(.+)$') + return name:match('^do_(.+)$') end local function load_vfunc_name_reverse(name) - return 'do_' .. name + return 'do_' .. name end local function load_method(mi) - local flags = mi.flags - if not flags.is_getter and not flags.is_setter then - return core.callable.new(mi) - end + local flags = mi.flags + if not flags.is_getter and not flags.is_setter then + return core.callable.new(mi) + end end local function load_properties(info) - return component.get_category( - info.properties, nil, - function(name) return string.gsub(name, '_', '-') end, - function(name) return string.gsub(name, '%-', '_') end) + return component.get_category( + info.properties, nil, + function(name) return string.gsub(name, '_', '-') end, + function(name) return string.gsub(name, '%-', '_') end) end local function find_constructor(info) - -- Check that ctor exists and return value conforms to info type. - local ctor = gi[info.namespace][core.uncamel(info.name)] - if ctor then - local ret = ctor.return_type.interface - for walk in function(_, c) return c.parent end, nil, info do - if ret and walk == ret then - ctor = core.callable.new(ctor) - return function(self, ...) return ctor(...) end - end - end - end + -- Check that ctor exists and return value conforms to info type. + local ctor = gi[info.namespace][core.uncamel(info.name)] + if ctor then + local ret = ctor.return_type.interface + for walk in function(_, c) return c.parent end, nil, info do + if ret and walk == ret then + ctor = core.callable.new(ctor) + return function(self, ...) return ctor(...) end + end + end + end end -- Resolver for classes, recursively resolves also all parents and -- implemented interfaces. function class.class_mt:_resolve(recursive) - -- Resolve itself using inherited implementation. - component.mt._resolve(self) - - -- Go to parent and implemented interfaces and resolve them too. - if recursive then - for _, iface in pairs(self._implements or {}) do - iface:_resolve(recursive) - end - if self._parent then - self._parent:_resolve(recursive) - end - end - return self + -- Resolve itself using inherited implementation. + component.mt._resolve(self) + + -- Go to parent and implemented interfaces and resolve them too. + if recursive then + for _, iface in pairs(self._implements or {}) do + iface:_resolve(recursive) + end + if self._parent then + self._parent:_resolve(recursive) + end + end + return self end -- _element implementation for objects, checks parent and implemented -- interfaces if element cannot be found in current typetable. -local internals = { _native = true, _type = true, _gtype = true, - _class = true, class = true } +local internals = { + _native = true, + _type = true, + _gtype = true, + _class = true, + class = true, +} function class.class_mt:_element(instance, symbol) - -- Special handling of internal symbols. - if instance and internals[symbol] then return symbol, symbol end - - -- Check default implementation. - local element, category = component.mt._element(self, instance, symbol) - if element then return element, category end - - -- Check parent and all implemented interfaces. - local parent = rawget(self, '_parent') - if parent then - element, category = parent:_element(instance, symbol) - if element then return element, category end - end - local implements = rawget(self, '_implements') or {} - for _, implemented in pairs(implements or {}) do - element, category = implemented:_element(instance, symbol, self) - if element then return element, category end - end + -- Special handling of internal symbols. + if instance and internals[symbol] then return symbol, symbol end + + -- Check default implementation. + local element, category = component.mt._element(self, instance, symbol) + if element then return element, category end + + -- Check parent and all implemented interfaces. + local parent = rawget(self, '_parent') + if parent then + element, category = parent:_element(instance, symbol) + if element then return element, category end + end + local implements = rawget(self, '_implements') or {} + for _, implemented in pairs(implements or {}) do + element, category = implemented:_element(instance, symbol, self) + if element then return element, category end + end end --- Implementation of field accessor. Note that compound fields are --- not supported in classes (because they are not seen in the wild and --- I'm lazy). +-- Implementation of field accessor. Note that compound fields are not supported in classes (because they are not seen in the wild and I'm lazy). function class.class_mt:_access_field(instance, field, ...) - return core.object.field(instance, field, ...) + return core.object.field(instance, field, ...) end -- Add accessor '_native' handling. function class.class_mt:_access_native(instance) - return core.object.query(instance, 'addr') + return core.object.query(instance, 'addr') end -- Add accessor '_type' handling. function class.class_mt:_access_type(instance) - return core.object.query(instance, 'repo') + return core.object.query(instance, 'repo') end -- Add accessor '_gtype' handling. function class.class_mt:_access_gtype(instance) - -- Cast address of the instance to TypeInstance to get to type info. - local ti = core.record.new(type_instance, - core.object.query(instance, 'addr')) - return ti.g_class.g_type + -- Cast address of the instance to TypeInstance to get to type info. + local ti = core.record.new(type_instance, core.object.query(instance, 'addr')) + return ti.g_class.g_type end -- Add accessor '_class' handling. function class.class_mt:_access_class(instance) - local gtype = class.class_mt._access_gtype(self, instance) - return core.record.new(self._class, type_class_peek(gtype)) + local gtype = class.class_mt._access_gtype(self, instance) + return core.record.new(self._class, type_class_peek(gtype)) end class.class_mt._accessclass = class.class_mt._access_class -- Add accessor '_virtual' handling. function class.class_mt:_access_virtual(instance, vfi) - local class_struct - local container = vfi.container - if container.is_interface then - local gtype = class.class_mt._access_gtype(self, instance) - local ptr = type_interface_peek(type_class_peek(gtype), container.gtype) - class_struct = core.record.new(core.index[container.gtype]._class, ptr) - else - class_struct = class.class_mt._access_class(self, instance) - end - - -- Retrieve proper method from the class struct. - return class_struct[vfi.name] + local class_struct + local container = vfi.container + if container.is_interface then + local gtype = class.class_mt._access_gtype(self, instance) + local ptr = type_interface_peek(type_class_peek(gtype), container.gtype) + class_struct = core.record.new(core.index[container.gtype]._class, ptr) + else + class_struct = class.class_mt._access_class(self, instance) + end + + -- Retrieve proper method from the class struct. + return class_struct[vfi.name] end --- Add __index for _virtual handling. Convert vfi baseinfo into real --- callable pointer according to the target type. +-- Add __index for _virtual handling. Convert vfi baseinfo into real callable pointer according to the target type. function class.class_mt:_index_virtual(vfi) - -- Get proper class struct, either from class or interface. - local ptr, class_struct = type_class_peek(self._gtype) - if not ptr then return nil end - local container = vfi.container - if container.is_interface then - local gtype = container._gtype - local ptr = type_interface_peek(ptr, gtype) - class_struct = core.record.new(core.index[gtype]._class, ptr) - else - class_struct = core.record.new(self._class, ptr) - end - - -- Retrieve proper method from the class struct. - return class_struct[vfi.name] + -- Get proper class struct, either from class or interface. + local ptr, class_struct = type_class_peek(self._gtype) + if not ptr then return nil end + local container = vfi.container + if container.is_interface then + local gtype = container._gtype + local ptr = type_interface_peek(ptr, gtype) + class_struct = core.record.new(core.index[gtype]._class, ptr) + else + class_struct = core.record.new(self._class, ptr) + end + + -- Retrieve proper method from the class struct. + return class_struct[vfi.name] end function class.load_interface(namespace, info) - -- Load all components of the interface. - local interface = component.create(info, class.interface_mt) - interface._property = load_properties(info) - interface._method = component.get_category(info.methods, load_method) - interface._signal = component.get_category( - info.signals, nil, load_signal_name, load_signal_name_reverse) - interface._constant = component.get_category(info.constants, core.constant) - local type_struct = info.type_struct - if type_struct then - interface._virtual = component.get_category( - info.vfuncs, nil, load_vfunc_name, load_vfunc_name_reverse) - interface._class = record.load(type_struct) - interface._class._gtype = interface._gtype - interface._class._allow = true - interface._class._parent = core.repo.GObject.TypeInterface - end - interface._new = find_constructor(info) - return interface + -- Load all components of the interface. + local interface = component.create(info, class.interface_mt) + interface._property = load_properties(info) + interface._method = component.get_category(info.methods, load_method) + interface._signal = component.get_category( + info.signals, nil, load_signal_name, load_signal_name_reverse) + interface._constant = component.get_category(info.constants, core.constant) + local type_struct = info.type_struct + if type_struct then + interface._virtual = component.get_category( + info.vfuncs, nil, load_vfunc_name, load_vfunc_name_reverse) + interface._class = record.load(type_struct) + interface._class._gtype = interface._gtype + interface._class._allow = true + interface._class._parent = core.repo.GObject.TypeInterface + end + interface._new = find_constructor(info) + return interface end function class.load_class(namespace, info) - -- Find parent record, if available. - local parent_info, parent = info.parent - if parent_info then - local ns, name = parent_info.namespace, parent_info.name - if ns ~= namespace._name or name ~= info.name then - parent = core.repo[ns][name] - end - end - - -- Create class instance, copy mt from parent, if parent exists, - -- otherwise defaults to class_mt. - local class = component.create( - info, parent and getmetatable(parent) or class.class_mt) - class._parent = parent - class._property = load_properties(info) - class._method = component.get_category(info.methods, load_method) - class._signal = component.get_category( - info.signals, nil, load_signal_name, load_signal_name_reverse) - class._constant = component.get_category(info.constants, core.constant) - class._field = component.get_category(info.fields) - local type_struct = info.type_struct - if type_struct then - class._virtual = component.get_category( - info.vfuncs, nil, load_vfunc_name, load_vfunc_name_reverse) - class._class = record.load(type_struct) - class._class._gtype = class._gtype - class._class._allow = true - class._class._parent = - parent and parent._class or core.repo.GObject.TypeClass - end - - -- Populate inheritance information (_implements and _parent fields). - local interfaces, implements = info.interfaces, {} - for i = 1, #interfaces do - local iface = interfaces[i] - implements[iface.fullname] = core.repo[iface.namespace][iface.name] - end - class._implements = implements - class._new = find_constructor(info) - return class + -- Find parent record, if available. + local parent_info, parent = info.parent + if parent_info then + local ns, name = parent_info.namespace, parent_info.name + if ns ~= namespace._name or name ~= info.name then + parent = core.repo[ns][name] + end + end + + -- Create class instance, copy mt from parent, if parent exists, otherwise defaults to class_mt. + local class = component.create( + info, parent and getmetatable(parent) or class.class_mt) + class._parent = parent + class._property = load_properties(info) + class._method = component.get_category(info.methods, load_method) + class._signal = component.get_category( + info.signals, nil, load_signal_name, load_signal_name_reverse) + class._constant = component.get_category(info.constants, core.constant) + class._field = component.get_category(info.fields) + local type_struct = info.type_struct + if type_struct then + class._virtual = component.get_category( + info.vfuncs, nil, load_vfunc_name, load_vfunc_name_reverse) + class._class = record.load(type_struct) + class._class._gtype = class._gtype + class._class._allow = true + class._class._parent = + parent and parent._class or core.repo.GObject.TypeClass + end + + -- Populate inheritance information (_implements and _parent fields). + local interfaces, implements = info.interfaces, {} + for i = 1, #interfaces do + local iface = interfaces[i] + implements[iface.fullname] = core.repo[iface.namespace][iface.name] + end + class._implements = implements + class._new = find_constructor(info) + return class end local register_static = core.callable.new(GObject.type_register_static) local type_query = core.callable.new(GObject.type_query) local type_add_interface_static = core.callable.new( - GObject.type_add_interface_static) + GObject.type_add_interface_static) function class.class_mt:derive(typename, ifaces) - -- Prepare repotable for newly registered class. - local new_class = setmetatable( - { - _parent = self, _override = {}, _guard = {}, _implements = {}, - _property = {}, _element = class.derived_mt._element, - _property_get = {}, _property_set = {}, - _class = self._class, _name = typename - }, - class.derived_mt) - - -- Create class-initialization closure, which assigns pointers to - -- all known overriden virtual methods. - local function class_init(class_addr) - -- Create instance of real class. - local class_addr = core.record.query(class_addr, "addr") or class_addr - local class_struct = core.record.new(new_class._class, class_addr) - - -- Iterate through all overrides and assign to the virtual callbacks. - for name, addr in pairs(new_class._override) do - if type(addr) == 'userdata' then - class_struct[name] = addr - end - end - - -- If type specified _class_init method, invoke it. - local _class_init = new_class._class_init - if _class_init then - _class_init(new_class, class_struct) - end - end - local class_init_guard, class_init_addr = core.marshal.callback( - GObject.ClassInitFunc, class_init) - new_class._guard._class_init = class_init_guard - - -- Create instance initialization function. Note that we do not - -- pass directly user's method, because user will probably set it - -- later after the type is already created, but we need to pass its - -- address right now during type initialization. Therefore, a stub - -- which looks up the init method of the type dynamically is used - -- instead. - local function instance_init(instance) - local _init = rawget(new_class, '_init') - if _init then - -- Convert instance to real type and call init with it. - _init(core.object.new(core.record.query(instance, 'addr'), - false, true)) - end - end - local instance_init_guard, instance_init_addr = core.marshal.callback( - GObject.InstanceInitFunc, instance_init) - new_class._guard._instance_init = instance_init_guard - - -- Prepare GTypeInfo with the registration. - local parent_info = type_query(self._gtype) - local type_info = core.repo.GObject.TypeInfo { - class_size = parent_info.class_size, - class_init = class_init_addr, - instance_size = parent_info.instance_size, - instance_init = instance_init_addr, - } - - -- Create the name to register with the GType system. - local g_typename = typename:gsub('%.', '') .. core.id - - -- Register new type with GType system. - local gtype = register_static(self._gtype, g_typename, type_info, {}) - rawset(new_class, '_gtype', core.gtype(gtype)) - if not new_class._gtype then - error(("failed to derive `%s' from `%s'"):format(typename, self._name)) - end - - -- Add newly registered type into the LuaGObject type index. - core.index[new_class._gtype] = new_class - - -- Create interface initialization closures. - for _, iface in pairs(ifaces or {}) do - local override = {} - new_class._override[iface._name] = override - new_class._implements[iface._name] = iface - - -- Prepare interface initialization closure. - local function iface_init(iface_addr) - iface_addr = core.record.query(iface_addr, "addr") or iface_addr - local iface_struct = core.record.new(iface._class, iface_addr) - - -- Iterate through all interface overrides and assign to the - -- virtual callbacks. - for name, addr in pairs(override) do - iface_struct[name] = addr - end - end - local iface_init_guard, iface_init_addr = core.marshal.callback( - GObject.InterfaceInitFunc, iface_init) - new_class._guard['_iface_init_' .. iface._name] = iface_init_guard - - -- Hook up interface to the registered class. - local iface_info = core.repo.GObject.InterfaceInfo { - interface_init = iface_init_addr, - } - type_add_interface_static(new_class, iface, iface_info) - end - - return new_class + -- Prepare repotable for newly registered class. + local new_class = setmetatable({ + _parent = self, _override = {}, _guard = {}, _implements = {}, + _property = {}, _element = class.derived_mt._element, + _property_get = {}, _property_set = {}, + _class = self._class, _name = typename, + }, + class.derived_mt) + + -- Create class-initialization closure, which assigns pointers to all known overriden virtual methods. + local function class_init(class_addr) + -- Create instance of real class. + local class_addr = core.record.query(class_addr, "addr") or class_addr + local class_struct = core.record.new(new_class._class, class_addr) + + -- Iterate through all overrides and assign to the virtual callbacks. + for name, addr in pairs(new_class._override) do + if type(addr) == 'userdata' then + class_struct[name] = addr + end + end + + -- If type specified _class_init method, invoke it. + local _class_init = new_class._class_init + if _class_init then + _class_init(new_class, class_struct) + end + end + local class_init_guard, class_init_addr = core.marshal.callback( + GObject.ClassInitFunc, class_init) + new_class._guard._class_init = class_init_guard + + -- Create instance initialization function. Note that we do not pass directly user's method, because user will probably set it later after the type is already created, but we need to pass its address right now during type initialization. Therefore, a stub which looks up the init method of the type dynamically is used instead. + local function instance_init(instance) + local _init = rawget(new_class, '_init') + if _init then + -- Convert instance to real type and call init with it. + _init(core.object.new(core.record.query(instance, 'addr'), + false, true)) + end + end + local instance_init_guard, instance_init_addr = core.marshal.callback( + GObject.InstanceInitFunc, instance_init) + new_class._guard._instance_init = instance_init_guard + + -- Prepare GTypeInfo with the registration. + local parent_info = type_query(self._gtype) + local type_info = core.repo.GObject.TypeInfo { + class_size = parent_info.class_size, + class_init = class_init_addr, + instance_size = parent_info.instance_size, + instance_init = instance_init_addr, + } + + -- Create the name to register with the GType system. + local g_typename = typename:gsub('%.', '') .. core.id + + -- Register new type with GType system. + local gtype = register_static(self._gtype, g_typename, type_info, {}) + rawset(new_class, '_gtype', core.gtype(gtype)) + if not new_class._gtype then + error(("failed to derive `%s' from `%s'"):format(typename, self._name)) + end + + -- Add newly registered type into the LuaGObject type index. + core.index[new_class._gtype] = new_class + + -- Create interface initialization closures. + for _, iface in pairs(ifaces or {}) do + local override = {} + new_class._override[iface._name] = override + new_class._implements[iface._name] = iface + + -- Prepare interface initialization closure. + local function iface_init(iface_addr) + iface_addr = core.record.query(iface_addr, "addr") or iface_addr + local iface_struct = core.record.new(iface._class, iface_addr) + + -- Iterate through all interface overrides and assign to the + -- virtual callbacks. + for name, addr in pairs(override) do + iface_struct[name] = addr + end + end + local iface_init_guard, iface_init_addr = core.marshal.callback( + GObject.InterfaceInitFunc, iface_init) + new_class._guard['_iface_init_' .. iface._name] = iface_init_guard + + -- Hook up interface to the registered class. + local iface_info = core.repo.GObject.InterfaceInfo { + interface_init = iface_init_addr, + } + type_add_interface_static(new_class, iface, iface_info) + end + + return new_class end class.derived_mt = class.class_mt:clone('derived', {}) @@ -396,52 +385,49 @@ class.derived_mt = class.class_mt:clone('derived', {}) -- Support for 'priv' pseudomember, holding table with user -- implementation data. function class.derived_mt:_element(instance, symbol) - -- Special handling of 'priv' attribute. - if instance and symbol == 'priv' then return symbol, '_priv' end + -- Special handling of 'priv' attribute. + if instance and symbol == 'priv' then return symbol, '_priv' end - -- Check default implementation. - local element, category = class.class_mt._element(self, instance, symbol) - if element then return element, category end + -- Check default implementation. + local element, category = class.class_mt._element(self, instance, symbol) + if element then return element, category end end function class.derived_mt:_access_priv(instance, name, ...) - if select('#', ...) > 0 then - error(("%s: cannot assign `%s'"):format(self._name, name), 5) - end - return core.object.env(instance) + if select('#', ...) > 0 then + error(("%s: cannot assign `%s'"):format(self._name, name), 5) + end + return core.object.env(instance) end --- Overload __newindex to catch assignment to virtual - this causes --- installation of new virtual method +-- Overload __newindex to catch assignment to virtual - this causes installation of new virtual method function class.derived_mt:__newindex(name, target) - -- Use _element method to get category to write to. - local _element = (rawget(self, '_element') - or rawget(getmetatable(self), '_element')) - local value, category = _element(self, nil, name) - - if category == '_virtual' then - -- Overriding virtual method. Prepare callback to the target and - -- store it to the _override type helper subtable. - name = load_vfunc_name(name) - local container = value.container - local class_struct, override - if container.is_interface then - class_struct = core.index[container.gtype] - override = self._override[class_struct._name] - class_struct = class_struct._class - else - class_struct = self._class - override = self._override - end - local guard, vfunc = core.marshal.callback( - class_struct[name].callable, target) - override[name] = vfunc - self._guard[container.name .. ':' .. name] = guard - else - -- Simply assign to type. This most probably means adding new - -- member function to the class (or some static member). - rawset(self, name, target) - end + -- Use _element method to get category to write to. + local _element = (rawget(self, '_element') + or rawget(getmetatable(self), '_element')) + local value, category = _element(self, nil, name) + + if category == '_virtual' then + -- Overriding virtual method. Prepare callback to the target and store it to the _override type helper subtable. + name = load_vfunc_name(name) + local container = value.container + local class_struct, override + if container.is_interface then + class_struct = core.index[container.gtype] + override = self._override[class_struct._name] + class_struct = class_struct._class + else + class_struct = self._class + override = self._override + end + local guard, vfunc = core.marshal.callback( + class_struct[name].callable, target) + override[name] = vfunc + self._guard[container.name .. ':' .. name] = guard + else + -- Simply assign to type. This most probably means adding new member function to the class (or some static member). + rawset(self, name, target) + end end return class diff --git a/LuaGObject/component.lua b/LuaGObject/component.lua index 8e7e2f22..bbc2e013 100644 --- a/LuaGObject/component.lua +++ b/LuaGObject/component.lua @@ -1,332 +1,291 @@ ------------------------------------------------------------------------------- --- --- LuaGObject Basic repo type component implementation --- --- Copyright (c) 2010, 2011, 2012, 2013, 2016 Pavel Holejsovsky --- Licensed under the MIT license: --- http://www.opensource.org/licenses/mit-license.php --- ------------------------------------------------------------------------------- +-- LuaGObject Basic repo type component implementation +-- Copyright (c) 2010, 2011, 2012, 2013, 2016 Pavel Holejsovsky +-- Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php local assert, pcall, setmetatable, getmetatable, pairs, next, rawget, rawset, -type, select, error - = assert, pcall, setmetatable, getmetatable, pairs, next, rawget, rawset, -type, select, error + type, select, error + = assert, pcall, setmetatable, getmetatable, pairs, next, rawget, rawset, + type, select, error local table = require 'table' local string = require 'string' local core = require 'LuaGObject.core' --- Generic component metatable. Component is any entity in the repo, --- e.g. record, object, enum, etc. +-- Generic component metatable. Component is any entity in the repo, e.g. record, object, enum, etc. local component = { mt = {} } --- Creates new component table by cloning all contents and setting --- Gets table for category of compound (i.e. _field of struct or _property --- for class etc). Installs metatable which performs on-demand lookup of --- symbols. +-- Creates new component table by cloning all contents and setting Gets table for category of compound (i.e. _field of struct or _property for class etc). Installs metatable which performs on-demand lookup of symbols. function component.get_category(children, xform_value, - xform_name, xform_name_reverse) - -- Either none or both transform methods must be provided. - assert(not xform_name or xform_name_reverse) - - -- Early shortcircuit; no elements, no table needed at all. - if #children == 0 then return nil end - - -- Index contains array of indices which were still not retrieved - -- from 'children' table, and table part contains name->index - -- mapping. - local index, mt = {}, {} - for i = 1, #children do index[i] = i end - - -- Fully resolves the category (i.e. loads everything remaining to - -- be loaded in given category) and disconnects on-demand loading - -- metatable. - local function resolve(category) - -- Load al values from unknown indices. - local ei, en, val - local function xvalue(arg) - if not xform_value then return arg end - if arg then - local ok, res = pcall(xform_value, arg) - return ok and res - end - end - - while #index > 0 do - ei = children[table.remove(index)] - val = xvalue(ei) - if val then - en = ei.name - en = not xform_name_reverse and en or xform_name_reverse(en) - if en then category[en] = val end - end - end - - -- The non-numeric indices still need to be iterated on, if any exist. - for en, idx in pairs(index) do - val = xvalue(children[idx]) - local name = not xform_name_reverse and en or xform_name_reverse(en) - if name then category[name] = val end - end - - -- Metatable is no longer needed, disconnect it. - return setmetatable(category, nil) - end - - function mt:__index(requested_name) - -- Check if closure for fully resolving the category is needed. - if requested_name == '_resolve' then return resolve end - - -- Transform name by transform function. - local name = not xform_name and requested_name - or xform_name(requested_name) - if not name then return end - - -- Check, whether we already know its index. - local idx, val = index[name] - if idx then - -- We know at least the index, so get info directly. - val = children[idx] - index[name] = nil - else - -- Not yet, go through unknown indices and try to find the - -- name. - while #index > 0 do - idx = table.remove(index) - val = children[idx] - local en = val.name - if en == name then break end - val = nil - index[en] = idx - end - end - - -- If there is nothing in the index, we can disconnect - -- metatable, because everything is already loaded. - if not next(index) then - setmetatable(self, nil) - end - - -- Transform found value and store it into the category (self) - -- table. - if not val then return nil end - if xform_value then val = xform_value(val) end - if not val then return nil end - self[requested_name] = val - return val - end - return setmetatable({}, mt) + xform_name, xform_name_reverse) + -- Either none or both transform methods must be provided. + assert(not xform_name or xform_name_reverse) + + -- Early shortcircuit; no elements, no table needed at all. + if #children == 0 then return nil end + + -- Index contains array of indices which were still not retrieved from 'children' table, and table part contains name->index mapping. + local index, mt = {}, {} + for i = 1, #children do index[i] = i end + + -- Fully resolves the category (i.e. loads everything remaining to be loaded in given category) and disconnects on-demand loading metatable. + local function resolve(category) + -- Load al values from unknown indices. + local ei, en, val + local function xvalue(arg) + if not xform_value then return arg end + if arg then + local ok, res = pcall(xform_value, arg) + return ok and res + end + end + + while #index > 0 do + ei = children[table.remove(index)] + val = xvalue(ei) + if val then + en = ei.name + en = not xform_name_reverse and en or xform_name_reverse(en) + if en then category[en] = val end + end + end + + -- The non-numeric indices still need to be iterated on, if any exist. + for en, idx in pairs(index) do + val = xvalue(children[idx]) + local name = not xform_name_reverse and en + or xform_name_reverse(en) + if name then category[name] = val end + end + + -- Metatable is no longer needed, disconnect it. + return setmetatable(category, nil) + end + + function mt:__index(requested_name) + -- Check if closure for fully resolving the category is needed. + if requested_name == '_resolve' then return resolve end + + -- Transform name by transform function. + local name = not xform_name and requested_name + or xform_name(requested_name) + if not name then return end + + -- Check, whether we already know its index. + local idx, val = index[name] + if idx then + -- We know at least the index, so get info directly. + val = children[idx] + index[name] = nil + else + -- Not yet, go through unknown indices and try to find the name. + while #index > 0 do + idx = table.remove(index) + val = children[idx] + local en = val.name + if en == name then break end + val = nil + index[en] = idx + end + end + + -- If there is nothing in the index, we can disconnect metatable, because everything is already loaded. + if not next(index) then + setmetatable(self, nil) + end + + -- Transform found value and store it into the category (self) table. + if not val then return nil end + if xform_value then val = xform_value(val) end + if not val then return nil end + self[requested_name] = val + return val + end + return setmetatable({}, mt) end --- Creates new component table by cloning all contents and setting --- categories table. +-- Creates new component table by cloning all contents and setting categories table. function component.mt:clone(type, categories) - local new_component = {} - for key, value in pairs(self) do new_component[key] = value end - new_component._type = type - if categories then - table.insert(categories, 1, '_attribute') - new_component._categories = categories - end - return new_component + local new_component = {} + for key, value in pairs(self) do new_component[key] = value end + new_component._type = type + if categories then + table.insert(categories, 1, '_attribute') + new_component._categories = categories + end + return new_component end -- __call implementation, uses _new method to create new instance of -- component type. function component.mt:__call(...) - return self:_new(...) + return self:_new(...) end --- Fully resolves the whole typetable, i.e. load all symbols normally --- loaded on-demand at once. Returns self, so that resolve can be --- easily chained for the caller. +-- Fully resolves the whole typetable, i.e. load all symbols normally oaded on-demand at once. Returns self, so that resolve can be easily chained for the caller. function component.mt:_resolve() - local categories = self._categories or {} - for i = 1, #categories do - -- Invoke '_resolve' function for all category tables, if they have it. - local category = rawget(self, categories[i]) - local resolve = type(category) == 'table' and category._resolve - if resolve then resolve(category) end - end - return self + local categories = self._categories or {} + for i = 1, #categories do + -- Invoke '_resolve' function for all category tables, if they have it. + local category = rawget(self, categories[i]) + local resolve = type(category) == 'table' and category._resolve + if resolve then resolve(category) end + end + return self end --- Implementation of _access method, which is called by _core when --- instance of repo-based type is accessed for reading or writing. +-- Implementation of _access method, which is called by _core when instance of repo-based type is accessed for reading or writing. function component.mt:_access(instance, symbol, ...) - -- Invoke _element, which converts symbol to element and category. - local element, category = self:_element(instance, symbol) - if not element then - error(("%s: no `%s'"):format(self._name, tostring(symbol)), 3) - end - - -- Get category handler to be used, and invoke it. - if category then - local handler = self['_access' .. category] - if handler then return handler(self, instance, element, ...) end - end - - -- If specific accessor does not exist, consider the element to be - -- 'static const' attribute of the class. This works well for - -- methods, constants and assorted other elements added manually - -- into the class by overrides. - if select('#', ...) > 0 then - error(("%s: `%s' is not writable"):format(self._name, symbol), 4) - end - return element + -- Invoke _element, which converts symbol to element and category. + local element, category = self:_element(instance, symbol) + if not element then + error(("%s: no `%s'"):format(self._name, tostring(symbol)), 3) + end + + -- Get category handler to be used, and invoke it. + if category then + local handler = self['_access' .. category] + if handler then return handler(self, instance, element, ...) end + end + + -- If specific accessor does not exist, consider the element to be 'static const' attribute of the class. This works well for methods, constants and assorted other elements added manually into the class by overrides. + if select('#', ...) > 0 then + error(("%s: `%s' is not writable"):format(self._name, symbol), 4) + end + return element end --- Keyword translation dictionary. Used for translating Lua keywords --- which might appear as symbols in typelibs into Lua-neutral identifiers. +-- Keyword translation dictionary. Used for translating Lua keywords which might appear as symbols in typelibs into Lua-neutral identifiers. local keyword_dictionary = { - _end = 'end', _do = 'do', _then = 'then', _elseif = 'elseif', _in = 'in', - _local = 'local', _function = 'function', _nil = 'nil', _false = 'false', - _true = 'true', _and = 'and', _or = 'or', _not = 'not', _global = 'global', + _end = 'end', _do = 'do', _then = 'then', _elseif = 'elseif', _in = 'in', + _local = 'local', _function = 'function', _nil = 'nil', _false = 'false', + _true = 'true', _and = 'and', _or = 'or', _not = 'not', _global = 'global', } --- Retrieves (element, category) pair from given componenttable and --- instance for given symbol. +-- Retrieves (element, category) pair from given componenttable and instance for given symbol. function component.mt:_element(instance, symbol, origin) - -- This generic version can work only with strings. Refuse - -- everything other, hoping that some more specialized _element - -- implementation will handle it. - if type(symbol) ~= 'string' then return end - - -- Check keyword translation dictionary. If the symbol can be - -- found there, try to lookup translated symbol. - symbol = keyword_dictionary[symbol] or symbol - - -- Check whether symbol is directly accessible in the component. - local element = rawget(self, symbol) - if element then return element end - - -- Check whether symbol is accessible in cached directory of the - -- component, packed as element value and category - local cached = rawget(self, '_cached') - if cached then - element = cached[symbol] - if element then return element[1], element[2] end - end - - -- Decompose symbol name, in case that it contains category prefix - -- (e.g. '_field_name' when requesting explicitely field called - -- name). - local category, name = string.match(symbol, '^(_.-)_(.*)$') - if category and name and category ~= '_access' then - -- Check requested category. - local cat = rawget(self, category) - element = cat and cat[name] - elseif string.sub(symbol, 1, 1) ~= '_' then - -- Check all available categories. - local categories = self._categories or {} - for i = 1, #categories do - category = categories[i] - local cat = rawget(self, category) - element = cat and cat[symbol] - if element then break end - end - end - if element then - -- Make sure that table-based attributes have symbol name, so - -- that potential errors contain the name of referenced - -- attribute. - if type(element) == 'table' and category == '_attribute' then - element._name = element._name or symbol - end - - -- If possible, cache the element in root table. - if not category or not (origin or self)['_access' .. category] then - -- No category or no special category handler is present, - -- store it directly, which results in fastest access. This - -- is most typical for methods. - self[symbol] = element - else - -- Store into _cached table, because we have to preserve the - -- category. - if not cached then - cached = {} - self._cached = cached - end - cached[symbol] = { element, category } - end - - return element, category - end + -- This generic version can work only with strings. Refuse everything other, hoping that some more specialized _element implementation will handle it. + if type(symbol) ~= 'string' then return end + + -- Check keyword translation dictionary. If the symbol can be found there, try to lookup translated symbol. + symbol = keyword_dictionary[symbol] or symbol + + -- Check whether symbol is directly accessible in the component. + local element = rawget(self, symbol) + if element then return element end + + -- Check whether symbol is accessible in cached directory of the component, packed as element value and category + local cached = rawget(self, '_cached') + if cached then + element = cached[symbol] + if element then return element[1], element[2] end + end + + -- Decompose symbol name, in case that it contains category prefix (e.g. '_field_name' when requesting explicitely field called name). + local category, name = string.match(symbol, '^(_.-)_(.*)$') + if category and name and category ~= '_access' then + -- Check requested category. + local cat = rawget(self, category) + element = cat and cat[name] + elseif string.sub(symbol, 1, 1) ~= '_' then + -- Check all available categories. + local categories = self._categories or {} + for i = 1, #categories do + category = categories[i] + local cat = rawget(self, category) + element = cat and cat[symbol] + if element then break end + end + end + if element then + -- Make sure that table-based attributes have symbol name, so that potential errors contain the name of referenced attribute. + if type(element) == 'table' and category == '_attribute' then + element._name = element._name or symbol + end + + -- If possible, cache the element in root table. + if not category or not (origin or self)['_access' .. category] then + -- No category or no special category handler is present, store it directly, which results in fastest access. This is most typical for methods. + self[symbol] = element + else + -- Store into _cached table, because we have to preserve the category. + if not cached then + cached = {} + self._cached = cached + end + cached[symbol] = { element, category } + end + + return element, category + end end -- __index implementation, uses _element method to perform lookup. function component.mt:__index(key) - -- First try to invoke our own _element method. - local _element, mt = rawget(self, '_element') - if not _element then - mt = getmetatable(self) - _element = rawget(mt, '_element') - end - local value, category = _element(self, nil, key) - if value then - if category then - -- Mangle the result by type-specific '_index_' - -- method, if present. - local index_name = '_index' .. category - local index = rawget(self, index_name) - if not index then - if not mt then mt = getmetatable(self) end - if mt then index = rawget(mt, index_name) end - end - if index then value = index(self, value) end - end - return value - end - - -- If not found as object element, examine the metatable itself. - return rawget(mt or getmetatable(self), key) + -- First try to invoke our own _element method. + local _element, mt = rawget(self, '_element') + if not _element then + mt = getmetatable(self) + _element = rawget(mt, '_element') + end + local value, category = _element(self, nil, key) + if value then + if category then + -- Mangle the result by type-specific '_index_' method, if present. + local index_name = '_index' .. category + local index = rawget(self, index_name) + if not index then + if not mt then mt = getmetatable(self) end + if mt then index = rawget(mt, index_name) end + end + if index then value = index(self, value) end + end + return value + end + + -- If not found as object element, examine the metatable itself. + return rawget(mt or getmetatable(self), key) end --- Implementation of attribute accessor. Attribute is either function --- to be directly invoked, or table containing set and get functions. +-- Implementation of attribute accessor. Attribute is either function to be directly invoked, or table containing set and get functions. function component.mt:_access_attribute(instance, element, ...) - -- If element is a table, assume that this table contains 'get' and - -- 'set' methods. Dispatch to them, and error out if they are - -- missing. - if type(element) == 'table' then - local mode = select('#', ...) == 0 and 'get' or 'set' - if not element[mode] then - error(("%s: cannot %s `%s'"):format( - self._name, mode == 'get' and 'read' or 'write', - element._name or ''), 5) - end - element = element[mode] - end - - -- Invoke attribute access function. - return element(instance, ...) + -- If element is a table, assume that this table contains 'get' and 'set' methods. Dispatch to them, and error out if they are missing. + if type(element) == 'table' then + local mode = select('#', ...) == 0 and 'get' or 'set' + if not element[mode] then + error(("%s: cannot %s `%s'"):format( + self._name, mode == 'get' and 'read' or 'write', + element._name or ''), 5) + end + element = element[mode] + end + + -- Invoke attribute access function. + return element(instance, ...) end -- Pretty prints type name function component.mt:__tostring() - return self._name + return self._name end --- Creates new component and sets up common parts according to given --- info. +-- Creates new component and sets up common parts according to given info. function component.create(info, mt, name) - local gtype - if core.gi.isinfo(info) then - gtype = info.gtype - name = info.name - else - gtype = info and core.gtype(info) - end - - -- Fill in meta of the compound. - local component = { _name = name } - if gtype then - -- Bind component in repo, make the relation using GType. - component._gtype = gtype - core.index[gtype] = component - end - return setmetatable(component, mt) + local gtype + if core.gi.isinfo(info) then + gtype = info.gtype + name = info.name + else + gtype = info and core.gtype(info) + end + + -- Fill in meta of the compound. + local component = { _name = name } + if gtype then + -- Bind component in repo, make the relation using GType. + component._gtype = gtype + core.index[gtype] = component + end + return setmetatable(component, mt) end return component diff --git a/LuaGObject/core.lua b/LuaGObject/core.lua index 608566be..823ef8f6 100644 --- a/LuaGObject/core.lua +++ b/LuaGObject/core.lua @@ -1,22 +1,13 @@ ------------------------------------------------------------------------------- --- -- LuaGObject Lua-side core module selector --- -- Copyright (c) 2010, 2011, 2015 Pavel Holejsovsky --- Licensed under the MIT license: --- http://www.opensource.org/licenses/mit-license.php --- ------------------------------------------------------------------------------- +-- Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php --- This module decides what kind of core routines should be loaded. --- Currently only one implementation exists, standard-Lua C-side --- implementation, LuaJIT-FFI-based one is planned. +-- This module decides what kind of core routines should be loaded. Currently only one implementation exists, standard-Lua C-side implementation, LuaJIT-FFI-based one is planned. local core = require 'LuaGObject.lua_gobject_core' --- Helper methods for converting between CamelCase and uscore_delim --- names. +-- Helper methods for converting between CamelCase and uscore_delim names. function core.uncamel(name) - return core.downcase(name:gsub('([%l%d])([%u])', '%1_%2')) + return core.downcase(name:gsub('([%l%d])([%u])', '%1_%2')) end return core diff --git a/LuaGObject/enum.lua b/LuaGObject/enum.lua index 9582cdf2..e65ad3e9 100644 --- a/LuaGObject/enum.lua +++ b/LuaGObject/enum.lua @@ -1,15 +1,9 @@ ------------------------------------------------------------------------------- --- --- LuaGObject support for enums and bitflags --- --- Copyright (c) 2010, 2011, 2013 Pavel Holejsovsky --- Licensed under the MIT license: --- http://www.opensource.org/licenses/mit-license.php --- ------------------------------------------------------------------------------- +-- LuaGObject support for enums and bitflags +-- Copyright (c) 2010, 2011, 2013 Pavel Holejsovsky +-- Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php local setmetatable, pairs, type, select - = setmetatable, pairs, type, select + = setmetatable, pairs, type, select local core = require 'LuaGObject.core' local gi = core.gi local component = require 'LuaGObject.component' @@ -17,102 +11,98 @@ local component = require 'LuaGObject.component' local band, bor = core.band, core.bor local enum = { - enum_mt = component.mt:clone('enum', { '_method' }), - bitflags_mt = component.mt:clone('flags', { '_method' }), + enum_mt = component.mt:clone('enum', { '_method' }), + bitflags_mt = component.mt:clone('flags', { '_method' }), } function enum.load(info, meta) - local enum_type = component.create(info, meta) - enum_type.error_domain = info.error_domain - if info.methods then - enum_type._method = component.get_category( - info.methods, core.callable.new) - else - -- Enum.methods was added only in GI1.30; for older gi, simulate - -- the access using lookup in the global namespace. - local prefix = core.downcase(info.name:gsub('%u+[^%u]+', '%1_')) - local namespace = core.repo[info.namespace] - enum_type._method = setmetatable( - {}, { __index = function(_, name) - return namespace[prefix .. name] - end }) - end + local enum_type = component.create(info, meta) + enum_type.error_domain = info.error_domain + if info.methods then + enum_type._method = component.get_category( + info.methods, core.callable.new) + else + -- Enum.methods was added only in GI1.30; for older gi, simulate the access using lookup in the global namespace. + local prefix = core.downcase(info.name:gsub('%u+[^%u]+', '%1_')) + local namespace = core.repo[info.namespace] + enum_type._method = setmetatable( + {}, { __index = function(_, name) + return namespace[prefix .. name] + end }) + end - -- Load all enum values. - local values = info.values - for i = 1, #values do - local mi = values[i] - enum_type[core.upcase(mi.name)] = mi.value - end + -- Load all enum values. + local values = info.values + for i = 1, #values do + local mi = values[i] + enum_type[core.upcase(mi.name)] = mi.value + end - -- Install metatable providing reverse lookup (i.e name(s) by - -- value). - return enum_type + -- Install metatable providing reverse lookup (i.e name(s) by value). + return enum_type end -- Enum reverse mapping, value->name. function enum.enum_mt:_element(instance, value) - if type(value) == 'number' then - for name, val in pairs(self) do - if val == value then return name end - end - return value - else - return component.mt._element(self, instance, value) - end + if type(value) == 'number' then + for name, val in pairs(self) do + if val == value then return name end + end + return value + else + return component.mt._element(self, instance, value) + end end --- Constructs enum number from specified string. Eventually, for --- error-type enums, allows creating error instance. +-- Constructs enum number from specified string. Eventually, for error-type enums, allows creating error instance. function enum.enum_mt:_new(param, ...) - if param == nil then - return 0 - elseif type(param) == 'string' then - param = self[param] - end - if self.error_domain and select('#', ...) > 0 then - return core.repo.GLib.Error(self, param, ...) - else - return param - end + if param == nil then + return 0 + elseif type(param) == 'string' then + param = self[param] + end + if self.error_domain and select('#', ...) > 0 then + return core.repo.GLib.Error(self, param, ...) + else + return param + end end --- Resolving arbitrary number to the table containing symbolic names --- of contained bits. +-- Resolving arbitrary number to the table containing symbolic names of contained bits. function enum.bitflags_mt:_element(instance, value) - if type(value) == 'number' then - local result, remainder = {}, value - for name, flag in pairs(self) do - if type(flag) == 'number' and name:sub(1, 1) ~= '_' and - band(value, flag) == flag then - result[name] = true - remainder = remainder - flag - end - end - if remainder > 0 then result[1] = remainder end - return result - else - return component.mt._element(self, instance, value) - end + if type(value) == 'number' then + local result, remainder = {}, value + for name, flag in pairs(self) do + if type(flag) == 'number' and name:sub(1, 1) ~= '_' and + band(value, flag) == flag then + result[name] = true + remainder = remainder - flag + end + end + if remainder > 0 then result[1] = remainder end + return result + else + return component.mt._element(self, instance, value) + end end -- 'Constructs' number from specified flags (or accepts just number). function enum.bitflags_mt:_new(param) - if param == nil then - return 0 - elseif type(param) == 'string' then - return self[param] - elseif type(param) == 'number' then - return param - else - local num = 0 - for key, value in pairs(param) do - if type(key) == 'string' then value = key end - if type(value) == 'string' then value = self[value] end - num = bor(num, value) - end - return num - end + if param == nil then + return 0 + elseif type(param) == 'string' then + return self[param] + elseif type(param) == 'number' then + return param + else + local num = 0 + for key, value in pairs(param) do + if type(key) == 'string' then value = key end + if type(value) == 'string' then value = self[value] end + num = bor(num, value) + end + return num + end end return enum diff --git a/LuaGObject/ffi.lua b/LuaGObject/ffi.lua index 0695b0be..62ecffb3 100644 --- a/LuaGObject/ffi.lua +++ b/LuaGObject/ffi.lua @@ -1,15 +1,9 @@ ------------------------------------------------------------------------------- --- --- LGI Helpers for custom FFI definitions --- --- Copyright (c) 2012 Pavel Holejsovsky --- Licensed under the MIT license: --- http://www.opensource.org/licenses/mit-license.php --- ------------------------------------------------------------------------------- +-- LGI Helpers for custom FFI definitions +-- Copyright (c) 2012 Pavel Holejsovsky +-- Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php local pairs, ipairs, setmetatable, getmetatable - = pairs, ipairs, setmetatable, getmetatable + = pairs, ipairs, setmetatable, getmetatable local math = require 'math' @@ -28,156 +22,159 @@ local glib = assert(gi.require('GLib')) -- declarations, because girepository API does not allow synthesizing -- GIBaseInfo instances from the air. ffi.types = { - void = gobject.Callback.return_type, - boolean = glib.Variant.methods.get_boolean.return_type, - int8 = gobject.ParamSpecChar.fields.minimum.typeinfo, - uint8 = gobject.ParamSpecUChar.fields.minimum.typeinfo, - int16 = glib.Variant.methods.get_int16.return_type, - uint16 = glib.Variant.methods.get_uint16.return_type, - int32 = glib.Variant.methods.get_int32.return_type, - uint32 = glib.Variant.methods.get_uint32.return_type, - int64 = glib.Variant.methods.get_int64.return_type, - uint64 = glib.Variant.methods.get_uint64.return_type, + void = gobject.Callback.return_type, + boolean = glib.Variant.methods.get_boolean.return_type, + int8 = gobject.ParamSpecChar.fields.minimum.typeinfo, + uint8 = gobject.ParamSpecUChar.fields.minimum.typeinfo, + int16 = glib.Variant.methods.get_int16.return_type, + uint16 = glib.Variant.methods.get_uint16.return_type, + int32 = glib.Variant.methods.get_int32.return_type, + uint32 = glib.Variant.methods.get_uint32.return_type, + int64 = glib.Variant.methods.get_int64.return_type, + uint64 = glib.Variant.methods.get_uint64.return_type, - int = gobject.ParamSpecEnum.fields.default_value.typeinfo, - uint = gobject.ParamSpecFlags.fields.default_value.typeinfo, - long = gobject.ParamSpecLong.fields.default_value.typeinfo, - ulong = gobject.ParamSpecULong.fields.default_value.typeinfo, + int = gobject.ParamSpecEnum.fields.default_value.typeinfo, + uint = gobject.ParamSpecFlags.fields.default_value.typeinfo, + long = gobject.ParamSpecLong.fields.default_value.typeinfo, + ulong = gobject.ParamSpecULong.fields.default_value.typeinfo, - float = gobject.ParamSpecFloat.fields.default_value.typeinfo, - double = gobject.ParamSpecDouble.fields.default_value.typeinfo, + float = gobject.ParamSpecFloat.fields.default_value.typeinfo, + double = gobject.ParamSpecDouble.fields.default_value.typeinfo, - utf8 = gobject.ParamSpecString.fields.default_value.typeinfo, - filename = glib.file_get_contents.args[1].typeinfo, + utf8 = gobject.ParamSpecString.fields.default_value.typeinfo, + filename = glib.file_get_contents.args[1].typeinfo, - GType = gobject.ParamSpecGType.fields.is_a_type.typeinfo, + GType = gobject.ParamSpecGType.fields.is_a_type.typeinfo, - GStrv = glib.KeyFile.methods.get_groups.return_type, + GStrv = glib.KeyFile.methods.get_groups.return_type, - GDestroyNotify = glib.Hook.fields.destroy.typeinfo, + GDestroyNotify = glib.Hook.fields.destroy.typeinfo, - ptr = glib.CompareDataFunc.args[1].typeinfo, + ptr = glib.CompareDataFunc.args[1].typeinfo, } for name, alias in pairs { - char = 'int8', uchar = 'uint8', short = 'int16', ushort = 'uint16' + char = 'int8', uchar = 'uint8', short = 'int16', ushort = 'uint16' } do - ffi.types[name] = ffi.types[alias] + ffi.types[name] = ffi.types[alias] end -- Gets gtype from specified resolved and _get_type function name. function ffi.load_gtype(resolver, get_type_name) - local addr = resolver[get_type_name] - if not addr then return nil, ("`%s' not found"):format(get_type_name) end - local get_gtype = core.callable.new( - { name = get_type_name, addr = addr, ret = ffi.types.GType }) - return get_gtype() + local addr = resolver[get_type_name] + if not addr then return nil, ("`%s' not found"):format(get_type_name) end + local get_gtype = core.callable.new { + name = get_type_name, + addr = addr, + ret = ffi.types.GType, + } + return get_gtype() end -- Creates new enum/flags table with all values from specified gtype. function ffi.load_enum(gtype, name) - local GLib, GObject = core.repo.GLib, core.repo.GObject - local is_flags = GObject.Type.is_a(gtype, GObject.Type.FLAGS) - local enum_component = component.create( - gtype, is_flags and enum.bitflags_mt or enum.enum_mt, name) - local type_class - -- GLib >= 2.86 deprecates GObject.TypeClass.ref() in favour of .get() - if GLib.check_version(2, 86, 0) then - type_class = GObject.TypeClass.ref(gtype) - else - type_class = GObject.TypeClass.get(gtype) - end - local enum_class = core.record.cast( - type_class, is_flags and GObject.FlagsClass or GObject.EnumClass) - for i = 0, enum_class.n_values - 1 do - local val = core.record.fromarray(enum_class.values, i) - enum_component[core.upcase(val.value_nick):gsub('%-', '_')] = val.value - end - -- For GLib versions below 2.86, type_class was ref'd and needs to be unref'd - if GLib.check_version(2, 86, 0) then - type_class:unref() - end - return enum_component + local GLib, GObject = core.repo.GLib, core.repo.GObject + local is_flags = GObject.Type.is_a(gtype, GObject.Type.FLAGS) + local enum_component = component.create(gtype, + is_flags and enum.bitflags_mt or enum.enum_mt, name) + local type_class + -- GLib >= 2.86 deprecates GObject.TypeClass.ref() in favour of .get() + if GLib.check_version(2, 86, 0) then + type_class = GObject.TypeClass.ref(gtype) + else + type_class = GObject.TypeClass.get(gtype) + end + local enum_class = core.record.cast( + type_class, is_flags and GObject.FlagsClass or GObject.EnumClass) + for i = 0, enum_class.n_values - 1 do + local val = core.record.fromarray(enum_class.values, i) + enum_component[core.upcase(val.value_nick):gsub('%-', '_')] = val.value + end + -- For GLib versions below 2.86, type_class was ref'd and needs to be unref'd + if GLib.check_version(2, 86, 0) then + type_class:unref() + end + return enum_component end -- Aligns offset to specified alignment. local function align(offset, align) - return math.modf((offset + align - 1) / align) * align + return math.modf((offset + align - 1) / align) * align end -- Creates record from the table of the field definitions. function ffi.load_fields(rec, defs) - rec._field = {} - local offset = 0 - local max_align = 1 - local max_size = 0 - for _, def in ipairs(defs) do - local field = {} - - -- Get size and alignment of this field. - local size, alignment - if gi.isinfo(def[2]) then - field[2] = 0 - if def[2].tag == 'interface' then - local ii = def[2].interface - if ii.type == 'enum' or ii.type == 'flags' then - size, alignment = core.marshal.typeinfo(ii.typeinfo) - elseif ii.type == 'struct' or ii.type == 'union' then - size, alignment = core.marshal.typeinfo(ffi.types.ptr) - if not ii.is_pointer then - -- Alignment is tricky; ideally we should go through - -- the record and find alignment according to the - -- largest alignments of the fields, but now we just - -- punt and use 'ptr' as alignment. But this might - -- be incorrect in case that doubles are used on 32b - -- platform. - - -- Get size from the record descriptor. - size = core.repotype(ii)._size - end - end - else - -- Basic type. - size, alignment = core.marshal.typeinfo(def[2]) - end - else - -- Either record or enum, decide according to repotable. - local repotype = getmetatable(def[2])._type - if repotype == 'struct' or repotype == 'union' then - field[2] = 1 - size, alignment = core.marshal.typeinfo(ffi.types.ptr) - if not def.ptr then - field[2] = 2 - size = def[2]._size - end - elseif repotype == 'enum' or repotype == 'flags' then - field[2] = 3 - field[4] = def.type or ffi.types.int - size, alignment = core.marshal.typeinfo(field[4]) - end - end - - -- Adjust offset according to the alignment. - offset = align(offset, alignment) - max_align = math.max(max_align, alignment) - - -- Create and add field definition. - field[1] = offset - field[3] = def[2] - rec._field[def[1]] = field - - if getmetatable(rec)._type == 'union' then - -- Remember largest size as the size of the union. - max_size = math.max(max_size, align(size, alignment)) - else - -- Move offset after the field. - offset = offset + size - end - end - - -- Store the total size of the record. - rec._size = ((getmetatable(rec)._type == 'union') and max_size - or align(offset, max_align)) + rec._field = {} + local offset = 0 + local max_align = 1 + local max_size = 0 + for _, def in ipairs(defs) do + local field = {} + + -- Get size and alignment of this field. + local size, alignment + if gi.isinfo(def[2]) then + field[2] = 0 + if def[2].tag == 'interface' then + local ii = def[2].interface + if ii.type == 'enum' or ii.type == 'flags' then + size, alignment = core.marshal.typeinfo(ii.typeinfo) + elseif ii.type == 'struct' or ii.type == 'union' then + size, alignment = core.marshal.typeinfo(ffi.types.ptr) + if not ii.is_pointer then + -- Alignment is tricky; ideally we should go through + -- the record and find alignment according to the + -- largest alignments of the fields, but now we just + -- punt and use 'ptr' as alignment. But this might + -- be incorrect in case that doubles are used on 32b + -- platform. + + -- Get size from the record descriptor. + size = core.repotype(ii)._size + end + end + else + -- Basic type. + size, alignment = core.marshal.typeinfo(def[2]) + end + else + -- Either record or enum, decide according to repotable. + local repotype = getmetatable(def[2])._type + if repotype == 'struct' or repotype == 'union' then + field[2] = 1 + size, alignment = core.marshal.typeinfo(ffi.types.ptr) + if not def.ptr then + field[2] = 2 + size = def[2]._size + end + elseif repotype == 'enum' or repotype == 'flags' then + field[2] = 3 + field[4] = def.type or ffi.types.int + size, alignment = core.marshal.typeinfo(field[4]) + end + end + + -- Adjust offset according to the alignment. + offset = align(offset, alignment) + max_align = math.max(max_align, alignment) + + -- Create and add field definition. + field[1] = offset + field[3] = def[2] + rec._field[def[1]] = field + + if getmetatable(rec)._type == 'union' then + -- Remember largest size as the size of the union. + max_size = math.max(max_size, align(size, alignment)) + else + -- Move offset after the field. + offset = offset + size + end + end + + -- Store the total size of the record. + rec._size = ((getmetatable(rec)._type == 'union') and max_size + or align(offset, max_align)) end return ffi diff --git a/LuaGObject/gi.c b/LuaGObject/gi.c index 2ee104f8..4ef6b71b 100644 --- a/LuaGObject/gi.c +++ b/LuaGObject/gi.c @@ -1,12 +1,7 @@ -/* - * Dynamic Lua binding to GObject using dynamic gobject-introspection. - * - * Copyright (c) 2010, 2011 Pavel Holejsovsky - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - * Native Lua wrappers around GIRepository. - */ +/* Dynamic Lua binding to GObject using dynamic gobject-introspection. +Copyright(c) 2010, 2011 Pavel Holejsovsky +Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php +Native Lua wrappers around GIRepository. */ #include #include "lua_gobject.h" @@ -14,857 +9,791 @@ typedef GIBaseInfo *(* InfosItemGet)(GIBaseInfo* info, gint item); GIRepository * -lua_gobject_gi_get_repository (void) +lua_gobject_gi_get_repository(void) { - static GIRepository *repository; + static GIRepository *repository; - if (repository == NULL) + if (repository == NULL) #if GLIB_CHECK_VERSION(2, 85, 0) - repository = gi_repository_dup_default (); + repository = gi_repository_dup_default(); #else - repository = gi_repository_new (); + repository = gi_repository_new(); #endif - return repository; + return repository; } /* Creates new instance of info from given GIBaseInfo pointer. */ int -lua_gobject_gi_info_new (lua_State *L, GIBaseInfo *info) +lua_gobject_gi_info_new(lua_State *L, GIBaseInfo *info) { - if (info) - { - GIBaseInfo **ud_info; + if (info) { + GIBaseInfo **ud_info; - g_assert (GI_IS_BASE_INFO (info)); + g_assert(GI_IS_BASE_INFO(info)); - ud_info = lua_newuserdata (L, sizeof (info)); - *ud_info = info; - luaL_getmetatable (L, LUA_GOBJECT_GI_INFO); - lua_setmetatable (L, -2); - } - else - lua_pushnil (L); + ud_info = lua_newuserdata(L, sizeof(info)); + *ud_info = info; + luaL_getmetatable(L, LUA_GOBJECT_GI_INFO); + lua_setmetatable(L, -2); + } + else + lua_pushnil(L); - return 1; + return 1; } gpointer -lua_gobject_gi_load_function (lua_State *L, int typetable, const char *name) +lua_gobject_gi_load_function(lua_State *L, int typetable, const char *name) { - GIBaseInfo **info; - gpointer symbol = NULL; - - luaL_checkstack (L, 3, ""); - lua_getfield (L, typetable, name); - info = lua_gobject_udata_test (L, -1, LUA_GOBJECT_GI_INFO); - if (info && GI_IS_FUNCTION_INFO (*info)) - gi_typelib_symbol (gi_base_info_get_typelib (*info), - gi_function_info_get_symbol (GI_FUNCTION_INFO (*info)), - &symbol); - else if (lua_islightuserdata (L, -1)) - symbol = lua_touserdata (L, -1); - lua_pop (L, 1); - return symbol; + GIBaseInfo **info; + gpointer symbol = NULL; + + luaL_checkstack(L, 3, ""); + lua_getfield(L, typetable, name); + info = lua_gobject_udata_test(L, -1, LUA_GOBJECT_GI_INFO); + if (info && GI_IS_FUNCTION_INFO(*info)) + gi_typelib_symbol(gi_base_info_get_typelib(*info), + gi_function_info_get_symbol(GI_FUNCTION_INFO(*info)), + &symbol); + else if (lua_islightuserdata(L, -1)) + symbol = lua_touserdata(L, -1); + lua_pop(L, 1); + return symbol; } -/* Userdata representing single group of infos (e.g. methods on - object, fields of struct etc.). Emulates Lua table for access. */ +/* Userdata representing single group of infos(e.g. methods on object, fields of struct etc.). Emulates Lua table for access. */ typedef struct _Infos { - GIBaseInfo *info; - gint count; - InfosItemGet item_get; + GIBaseInfo *info; + gint count; + InfosItemGet item_get; } Infos; #define LUA_GOBJECT_GI_INFOS "lua_gobject.gi.infos" static int -infos_len (lua_State *L) +infos_len(lua_State *L) { - Infos* infos = luaL_checkudata (L, 1, LUA_GOBJECT_GI_INFOS); - lua_pushinteger (L, infos->count); - return 1; + Infos* infos = luaL_checkudata(L, 1, LUA_GOBJECT_GI_INFOS); + lua_pushinteger(L, infos->count); + return 1; } static int -infos_index (lua_State *L) +infos_index(lua_State *L) { - Infos* infos = luaL_checkudata (L, 1, LUA_GOBJECT_GI_INFOS); - gint n; - if (lua_type (L, 2) == LUA_TNUMBER) - { - n = lua_tointeger (L, 2) - 1; - luaL_argcheck (L, n >= 0 && n < infos->count, 2, "out of bounds"); - return lua_gobject_gi_info_new (L, infos->item_get (infos->info, n)); - } - else - { - const gchar *name = luaL_checkstring (L, 2); - for (n = 0; n < infos->count; n++) - { - GIBaseInfo *info = infos->item_get (infos->info, n); - if (strcmp (gi_base_info_get_name (info), name) == 0) - return lua_gobject_gi_info_new (L, info); - - gi_base_info_unref (info); - } + Infos* infos = luaL_checkudata(L, 1, LUA_GOBJECT_GI_INFOS); + gint n; + if (lua_type(L, 2) == LUA_TNUMBER) { + n = lua_tointeger(L, 2) - 1; + luaL_argcheck(L, n >= 0 && n < infos->count, 2, "out of bounds"); + return lua_gobject_gi_info_new(L, infos->item_get(infos->info, n)); + } else { + const gchar *name = luaL_checkstring(L, 2); + for (n = 0; n < infos->count; n++) { + GIBaseInfo *info = infos->item_get(infos->info, n); + if (strcmp(gi_base_info_get_name(info), name) == 0) + return lua_gobject_gi_info_new(L, info); + + gi_base_info_unref(info); + } - lua_pushnil (L); - return 1; - } + lua_pushnil(L); + return 1; + } } static int -infos_gc (lua_State *L) +infos_gc(lua_State *L) { - Infos *infos = luaL_checkudata (L, 1, LUA_GOBJECT_GI_INFOS); - gi_base_info_unref (infos->info); + Infos *infos = luaL_checkudata(L, 1, LUA_GOBJECT_GI_INFOS); + gi_base_info_unref(infos->info); - /* Unset the metatable / make the infos unusable */ - lua_pushnil (L); - lua_setmetatable (L, 1); - return 0; + /* Unset the metatable / make the infos unusable */ + lua_pushnil(L); + lua_setmetatable(L, 1); + return 0; } /* Creates new userdata object representing given category of infos. */ static int -infos_new (lua_State *L, GIBaseInfo *info, gint count, InfosItemGet item_get) +infos_new(lua_State *L, GIBaseInfo *info, gint count, InfosItemGet item_get) { - Infos *infos = lua_newuserdata (L, sizeof (Infos)); - luaL_getmetatable (L, LUA_GOBJECT_GI_INFOS); - lua_setmetatable (L, -2); - infos->info = gi_base_info_ref (info); - infos->count = count; - infos->item_get = item_get; - return 1; + Infos *infos = lua_newuserdata(L, sizeof(Infos)); + luaL_getmetatable(L, LUA_GOBJECT_GI_INFOS); + lua_setmetatable(L, -2); + infos->info = gi_base_info_ref(info); + infos->count = count; + infos->item_get = item_get; + return 1; } static const luaL_Reg gi_infos_reg[] = { - { "__gc", infos_gc }, - { "__len", infos_len }, - { "__index", infos_index }, - { NULL, NULL } + { "__gc", infos_gc }, + { "__len", infos_len }, + { "__index", infos_index }, + { NULL, NULL } }; static int -info_push_transfer (lua_State *L, GITransfer transfer) +info_push_transfer(lua_State *L, GITransfer transfer) { - if (0); -#define H(n1, n2) \ - else if (transfer == GI_TRANSFER_ ## n1) \ - { \ - lua_pushstring (L, #n2); \ - return 1; \ - } - H(NOTHING, none) - H(CONTAINER, container) - H(EVERYTHING, full) + if (0); +#define H(n1, n2) \ + else if (transfer == GI_TRANSFER_ ## n1) { \ + lua_pushstring(L, #n2); \ + return 1; \ + } + H(NOTHING, none) + H(CONTAINER, container) + H(EVERYTHING, full) #undef H - return 0; + return 0; } static int -info_index (lua_State *L) +info_index(lua_State *L) { - GIBaseInfo **info = luaL_checkudata (L, 1, LUA_GOBJECT_GI_INFO); - const gchar *prop = luaL_checkstring (L, 2); - -#define INFOS(n1, n2) \ - else if (strcmp (prop, #n2 "s") == 0) \ - return infos_new (L, GI_BASE_INFO (*info), \ - gi_ ## n1 ## _info_get_n_ ## n2 ## s ((gpointer)*info), \ - (InfosItemGet) gi_ ## n1 ## _info_get_ ## n2); - -#define INFOS2(n1, n2, n3) \ - else if (strcmp (prop, #n3) == 0) \ - return infos_new (L, GI_BASE_INFO (*info), \ - gi_ ## n1 ## _info_get_n_ ## n3 ((gpointer)*info), \ - (InfosItemGet) gi_ ## n1 ## _info_get_ ## n2); - - if (strcmp (prop, "type") == 0) - { -#define H(n1, n2) \ - else if (GI_IS_ ## n1 ## _INFO (*info)) \ - { \ - lua_pushstring (L, #n2); \ - return 1; \ - } - - if (0) {} - H(FUNCTION, function) - H(CALLBACK, callback) - H(STRUCT, struct) - H(FLAGS, flags) - H(ENUM, enum) - H(OBJECT, object) - H(INTERFACE, interface) - H(CONSTANT, constant) - H(UNION, union) - H(VALUE, value) - H(SIGNAL, signal) - H(VFUNC, vfunc) - H(PROPERTY, property) - H(FIELD, field) - H(ARG, arg) - H(TYPE, type) - H(UNRESOLVED, unresolved) - else g_assert_not_reached (); -#undef H - } - -#define H(n1, n2) \ - if (strcmp (prop, "is_" #n2) == 0) \ - { \ - lua_pushboolean (L, GI_IS_ ## n1 ## _INFO (*info)); \ - return 1; \ - } - H(ARG, arg) - H(CALLABLE, callable) - H(FUNCTION, function) - H(SIGNAL, signal) - H(VFUNC, vfunc) - H(CONSTANT, constant) - H(FIELD, field) - H(PROPERTY, property) - H(REGISTERED_TYPE, registered_type) - H(ENUM, enum) - H(INTERFACE, interface) - H(OBJECT, object) - H(STRUCT, struct) - H(UNION, union) - H(TYPE, type) - H(VALUE, value); -#undef H + GIBaseInfo **info = luaL_checkudata(L, 1, LUA_GOBJECT_GI_INFO); + const gchar *prop = luaL_checkstring(L, 2); + +#define INFOS(n1, n2) \ + else if (strcmp(prop, #n2 "s") == 0) \ + return infos_new(L, GI_BASE_INFO(*info), \ + gi_ ## n1 ## _info_get_n_ ## n2 ## s((gpointer)*info), \ + (InfosItemGet) gi_ ## n1 ## _info_get_ ## n2); + +#define INFOS2(n1, n2, n3) \ + else if (strcmp(prop, #n3) == 0) \ + return infos_new(L, GI_BASE_INFO(*info), \ + gi_ ## n1 ## _info_get_n_ ## n3((gpointer)*info), \ + (InfosItemGet) gi_ ## n1 ## _info_get_ ## n2); + + if (strcmp(prop, "type") == 0) { +#define H(n1, n2) \ + else if (GI_IS_ ## n1 ## _INFO(*info)) { \ + lua_pushstring(L, #n2); \ + return 1; \ + } - if (!GI_IS_TYPE_INFO (*info)) - { - if (strcmp (prop, "name") == 0) - { - lua_pushstring (L, gi_base_info_get_name (*info)); - return 1; - } - else if (strcmp (prop, "namespace") == 0) - { - lua_pushstring (L, gi_base_info_get_namespace (*info)); - return 1; - } - } - - if (strcmp (prop, "fullname") == 0) - { - lua_concat (L, lua_gobject_type_get_name (L, *info)); - return 1; - } - - if (strcmp (prop, "deprecated") == 0) - { - lua_pushboolean (L, gi_base_info_is_deprecated (*info)); - return 1; - } - else if (strcmp (prop, "container") == 0) - { - GIBaseInfo *container = gi_base_info_get_container (*info); - if (container) - gi_base_info_ref (container); - return lua_gobject_gi_info_new (L, container); - } - else if (strcmp (prop, "typeinfo") == 0) - { - GITypeInfo *ti = NULL; - if (GI_IS_ARG_INFO (*info)) - ti = gi_arg_info_get_type_info (GI_ARG_INFO (*info)); - else if (GI_IS_CONSTANT_INFO (*info)) - ti = gi_constant_info_get_type_info (GI_CONSTANT_INFO (*info)); - else if (GI_IS_PROPERTY_INFO (*info)) - ti = gi_property_info_get_type_info (GI_PROPERTY_INFO (*info)); - else if (GI_IS_FIELD_INFO (*info)) - ti = gi_field_info_get_type_info (GI_FIELD_INFO (*info)); - - if (ti) - return lua_gobject_gi_info_new (L, GI_BASE_INFO (ti)); - } - - if (GI_IS_REGISTERED_TYPE_INFO (*info)) - { - if (strcmp (prop, "gtype") == 0) - { - GType gtype = gi_registered_type_info_get_g_type (GI_REGISTERED_TYPE_INFO (*info)); - if (gtype != G_TYPE_NONE) - lua_pushlightuserdata (L, (void *) gtype); - else - lua_pushnil (L); - return 1; + if (0) {} + H(FUNCTION, function) + H(CALLBACK, callback) + H(STRUCT, struct) + H(FLAGS, flags) + H(ENUM, enum) + H(OBJECT, object) + H(INTERFACE, interface) + H(CONSTANT, constant) + H(UNION, union) + H(VALUE, value) + H(SIGNAL, signal) + H(VFUNC, vfunc) + H(PROPERTY, property) + H(FIELD, field) + H(ARG, arg) + H(TYPE, type) + H(UNRESOLVED, unresolved) + else g_assert_not_reached(); +#undef H } - else if (GI_IS_STRUCT_INFO (*info)) - { - if (strcmp (prop, "is_gtype_struct") == 0) - { - lua_pushboolean (L, gi_struct_info_is_gtype_struct (GI_STRUCT_INFO (*info))); - return 1; - } - else if (strcmp (prop, "size") == 0) - { - lua_pushinteger (L, gi_struct_info_get_size (GI_STRUCT_INFO (*info))); - return 1; - } - INFOS (struct, field) - INFOS (struct, method); + +#define H(n1, n2) \ + if (strcmp(prop, "is_" #n2) == 0) { \ + lua_pushboolean(L, GI_IS_ ## n1 ## _INFO(*info)); \ + return 1; \ } - else if (GI_IS_UNION_INFO (*info)) - { - if (strcmp (prop, "size") == 0) - { - lua_pushinteger (L, gi_union_info_get_size (GI_UNION_INFO (*info))); - return 1; - } - INFOS (union, field) - INFOS (union, method); + H(ARG, arg) + H(CALLABLE, callable) + H(FUNCTION, function) + H(SIGNAL, signal) + H(VFUNC, vfunc) + H(CONSTANT, constant) + H(FIELD, field) + H(PROPERTY, property) + H(REGISTERED_TYPE, registered_type) + H(ENUM, enum) + H(INTERFACE, interface) + H(OBJECT, object) + H(STRUCT, struct) + H(UNION, union) + H(TYPE, type) + H(VALUE, value); +#undef H + + if (!GI_IS_TYPE_INFO(*info)) { + if (strcmp(prop, "name") == 0) { + lua_pushstring(L, gi_base_info_get_name(*info)); + return 1; + } else if (strcmp(prop, "namespace") == 0) { + lua_pushstring(L, gi_base_info_get_namespace(*info)); + return 1; + } } - else if (GI_IS_INTERFACE_INFO (*info)) - { - if (strcmp (prop, "type_struct") == 0) - return - lua_gobject_gi_info_new (L, GI_BASE_INFO (gi_interface_info_get_iface_struct (GI_INTERFACE_INFO (*info)))); - INFOS (interface, prerequisite) - INFOS (interface, vfunc) - INFOS (interface, method) - INFOS (interface, constant) - INFOS2 (interface, property, properties) - INFOS (interface, signal); + + if (strcmp(prop, "fullname") == 0) { + lua_concat(L, lua_gobject_type_get_name(L, *info)); + return 1; } - else if (GI_IS_OBJECT_INFO (*info)) - { - if (strcmp (prop, "parent") == 0) - return lua_gobject_gi_info_new (L, GI_BASE_INFO (gi_object_info_get_parent (GI_OBJECT_INFO (*info)))); - else if (strcmp (prop, "type_struct") == 0) - return lua_gobject_gi_info_new (L, GI_BASE_INFO (gi_object_info_get_class_struct (GI_OBJECT_INFO (*info)))); - INFOS (object, interface) - INFOS (object, field) - INFOS (object, vfunc) - INFOS (object, method) - INFOS (object, constant) - INFOS2 (object, property, properties) - INFOS (object, signal); + + if (strcmp(prop, "deprecated") == 0) { + lua_pushboolean(L, gi_base_info_is_deprecated(*info)); + return 1; + } else if (strcmp(prop, "container") == 0) { + GIBaseInfo *container = gi_base_info_get_container(*info); + if (container) + gi_base_info_ref(container); + return lua_gobject_gi_info_new(L, container); + } else if (strcmp(prop, "typeinfo") == 0) { + GITypeInfo *ti = NULL; + if (GI_IS_ARG_INFO(*info)) + ti = gi_arg_info_get_type_info(GI_ARG_INFO(*info)); + else if (GI_IS_CONSTANT_INFO(*info)) + ti = gi_constant_info_get_type_info(GI_CONSTANT_INFO(*info)); + else if (GI_IS_PROPERTY_INFO(*info)) + ti = gi_property_info_get_type_info(GI_PROPERTY_INFO(*info)); + else if (GI_IS_FIELD_INFO(*info)) + ti = gi_field_info_get_type_info(GI_FIELD_INFO(*info)); + + if (ti) + return lua_gobject_gi_info_new(L, GI_BASE_INFO(ti)); } - } - - if (GI_IS_CALLABLE_INFO (*info)) - { - if (strcmp (prop, "return_type") == 0) - return lua_gobject_gi_info_new (L, GI_BASE_INFO (gi_callable_info_get_return_type (GI_CALLABLE_INFO (*info)))); - else if (strcmp (prop, "return_transfer") == 0) - return info_push_transfer (L, gi_callable_info_get_caller_owns (GI_CALLABLE_INFO (*info))); - INFOS (callable, arg); - - if (GI_IS_SIGNAL_INFO (*info)) - { - if (strcmp (prop, "flags") == 0) - { - GSignalFlags flags = gi_signal_info_get_flags (GI_SIGNAL_INFO (*info)); - lua_newtable (L); -#define H(n1, n2) \ - if ((flags & G_SIGNAL_ ## n1) != 0) \ - { \ - lua_pushboolean (L, 1); \ - lua_setfield (L, -2, #n2); \ + + if (GI_IS_REGISTERED_TYPE_INFO(*info)) { + if (strcmp(prop, "gtype") == 0) { + GType gtype = gi_registered_type_info_get_g_type( + GI_REGISTERED_TYPE_INFO(*info)); + if (gtype != G_TYPE_NONE) + lua_pushlightuserdata(L,(void *) gtype); + else + lua_pushnil(L); + return 1; + } else if (GI_IS_STRUCT_INFO(*info)) { + if (strcmp(prop, "is_gtype_struct") == 0) { + lua_pushboolean(L, + gi_struct_info_is_gtype_struct(GI_STRUCT_INFO(*info))); + return 1; + } else if (strcmp(prop, "size") == 0) { + lua_pushinteger(L, + gi_struct_info_get_size(GI_STRUCT_INFO(*info))); + return 1; + } + INFOS(struct, field) + INFOS(struct, method); + } else if (GI_IS_UNION_INFO(*info)) { + if (strcmp(prop, "size") == 0) { + lua_pushinteger(L, + gi_union_info_get_size(GI_UNION_INFO(*info))); + return 1; + } + INFOS(union, field) + INFOS(union, method); + } else if (GI_IS_INTERFACE_INFO(*info)) { + if (strcmp(prop, "type_struct") == 0) + return lua_gobject_gi_info_new(L, + GI_BASE_INFO(gi_interface_info_get_iface_struct( + GI_INTERFACE_INFO(*info)))); + INFOS(interface, prerequisite) + INFOS(interface, vfunc) + INFOS(interface, method) + INFOS(interface, constant) + INFOS2(interface, property, properties) + INFOS(interface, signal); + } else if (GI_IS_OBJECT_INFO(*info)) { + if (strcmp(prop, "parent") == 0) + return lua_gobject_gi_info_new(L, GI_BASE_INFO( + gi_object_info_get_parent(GI_OBJECT_INFO(*info)))); + else if (strcmp(prop, "type_struct") == 0) + return lua_gobject_gi_info_new(L, GI_BASE_INFO( + gi_object_info_get_class_struct( + GI_OBJECT_INFO(*info)))); + INFOS(object, interface) + INFOS(object, field) + INFOS(object, vfunc) + INFOS(object, method) + INFOS(object, constant) + INFOS2(object, property, properties) + INFOS(object, signal); } - H(RUN_FIRST, run_first) - H(RUN_LAST, run_last) - H(RUN_CLEANUP, run_cleanup) - H(NO_RECURSE, no_recurse) - H(DETAILED, detailed) - H(ACTION, action) - H(NO_HOOKS, no_hooks); -#undef H - return 1; - } } - if (GI_IS_FUNCTION_INFO (*info)) - { - if (strcmp (prop, "flags") == 0) - { - GIFunctionInfoFlags flags = gi_function_info_get_flags (GI_FUNCTION_INFO (*info)); - lua_newtable (L); - if (0); -#define H(n1, n2) \ - else if ((flags & GI_FUNCTION_ ## n1) != 0) \ - { \ - lua_pushboolean (L, 1); \ - lua_setfield (L, -2, #n2); \ + if (GI_IS_CALLABLE_INFO(*info)) { + if (strcmp(prop, "return_type") == 0) + return lua_gobject_gi_info_new(L, GI_BASE_INFO( + gi_callable_info_get_return_type( + GI_CALLABLE_INFO(*info)))); + else if (strcmp(prop, "return_transfer") == 0) + return info_push_transfer(L, gi_callable_info_get_caller_owns( + GI_CALLABLE_INFO(*info))); + INFOS(callable, arg); + + if (GI_IS_SIGNAL_INFO(*info)) { + if (strcmp(prop, "flags") == 0) { + GSignalFlags flags = gi_signal_info_get_flags( + GI_SIGNAL_INFO(*info)); + lua_newtable(L); +#define H(n1, n2) \ + if ((flags & G_SIGNAL_ ## n1) != 0) { \ + lua_pushboolean(L, 1); \ + lua_setfield(L, -2, #n2); \ + } + H(RUN_FIRST, run_first) + H(RUN_LAST, run_last) + H(RUN_CLEANUP, run_cleanup) + H(NO_RECURSE, no_recurse) + H(DETAILED, detailed) + H(ACTION, action) + H(NO_HOOKS, no_hooks); +#undef H + return 1; + } } - H(IS_METHOD, is_method) - H(IS_CONSTRUCTOR, is_constructor) - H(IS_GETTER, is_getter) - H(IS_SETTER, is_setter) - H(WRAPS_VFUNC, wraps_vfunc) + + if (GI_IS_FUNCTION_INFO(*info)) { + if (strcmp(prop, "flags") == 0) { + GIFunctionInfoFlags flags = gi_function_info_get_flags( + GI_FUNCTION_INFO(*info)); + lua_newtable(L); + if (0); +#define H(n1, n2) \ + else if ((flags & GI_FUNCTION_ ## n1) != 0) { \ + lua_pushboolean(L, 1); \ + lua_setfield(L, -2, #n2); \ + } + H(IS_METHOD, is_method) + H(IS_CONSTRUCTOR, is_constructor) + H(IS_GETTER, is_getter) + H(IS_SETTER, is_setter) + H(WRAPS_VFUNC, wraps_vfunc) #undef H - return 1; - } - } - } - - if (GI_IS_ENUM_INFO (*info) || GI_IS_FLAGS_INFO (*info)) - { - if (strcmp (prop, "storage") == 0) - { - GITypeTag tag = gi_enum_info_get_storage_type (GI_ENUM_INFO (*info)); - lua_pushstring (L, gi_type_tag_to_string (tag)); - return 1; + return 1; + } + } } -#if GLIB_CHECK_VERSION (2, 30, 0) - INFOS (enum, method) + + if (GI_IS_ENUM_INFO(*info) || GI_IS_FLAGS_INFO(*info)) { + if (strcmp(prop, "storage") == 0) { + GITypeTag tag = gi_enum_info_get_storage_type( + GI_ENUM_INFO(*info)); + lua_pushstring(L, gi_type_tag_to_string(tag)); + return 1; + } +#if GLIB_CHECK_VERSION(2, 30, 0) + INFOS(enum, method) #endif - INFOS (enum, value) - else if (strcmp (prop, "error_domain") == 0) - { - const gchar *domain = gi_enum_info_get_error_domain (GI_ENUM_INFO (*info)); - if (domain != NULL) - lua_pushinteger (L, g_quark_from_string (domain)); - else - lua_pushnil (L); - - return 1; - } - } - - if (GI_IS_VALUE_INFO (*info)) - { - if (strcmp (prop, "value") == 0) - { - lua_pushinteger (L, gi_value_info_get_value (GI_VALUE_INFO (*info))); - return 1; - } - } - - if (GI_IS_ARG_INFO (*info)) - { - if (strcmp (prop, "direction") == 0) - { - GIDirection dir = gi_arg_info_get_direction (GI_ARG_INFO (*info)); - if (dir == GI_DIRECTION_OUT) - lua_pushstring (L, gi_arg_info_is_caller_allocates (GI_ARG_INFO (*info)) - ? "out-caller-alloc" : "out"); - else - lua_pushstring (L, dir == GI_DIRECTION_IN ? "in" : "inout"); - return 1; - } - if (strcmp (prop, "transfer") == 0) - return info_push_transfer (L, - gi_arg_info_get_ownership_transfer (GI_ARG_INFO (*info))); - if (strcmp (prop, "optional") == 0) - { - lua_pushboolean (L, gi_arg_info_is_optional (GI_ARG_INFO (*info)) - || gi_arg_info_may_be_null (GI_ARG_INFO (*info))); - return 1; - } - } - - if (GI_IS_PROPERTY_INFO (*info)) - { - if (strcmp (prop, "flags") == 0) - { - lua_pushinteger (L, gi_property_info_get_flags (GI_PROPERTY_INFO (*info))); - return 1; - } - else if (strcmp (prop, "transfer") == 0) - return - info_push_transfer (L, - gi_property_info_get_ownership_transfer (GI_PROPERTY_INFO (*info))); - } - - if (GI_IS_FIELD_INFO (*info)) - { - if (strcmp (prop, "flags") == 0) - { - GIFieldInfoFlags flags = gi_field_info_get_flags (GI_FIELD_INFO (*info)); - lua_newtable (L); - if (0); -#define H(n1, n2) \ - else if ((flags & GI_FIELD_ ## n1) != 0) \ - { \ - lua_pushboolean (L, 1); \ - lua_setfield (L, -2, #n2); \ + INFOS(enum, value) + else if (strcmp(prop, "error_domain") == 0) { + const gchar *domain = gi_enum_info_get_error_domain( + GI_ENUM_INFO(*info)); + if (domain != NULL) + lua_pushinteger(L, g_quark_from_string(domain)); + else + lua_pushnil(L); + + return 1; } - H(IS_READABLE, is_readable) - H(IS_WRITABLE, is_writable) -#undef H - return 1; - } - else if (strcmp (prop, "size") == 0) - { - lua_pushinteger (L, gi_field_info_get_size (GI_FIELD_INFO (*info))); - return 1; } - else if (strcmp (prop, "offset") == 0) - { - lua_pushinteger (L, gi_field_info_get_offset (GI_FIELD_INFO (*info))); - return 1; - } - } - - if (GI_IS_TYPE_INFO (*info)) - { - GITypeTag tag = gi_type_info_get_tag (GI_TYPE_INFO (*info)); - if (strcmp (prop, "tag") == 0) - { - lua_pushstring (L, gi_type_tag_to_string (tag)); - return 1; - } - else if (strcmp (prop, "is_basic") == 0) - { - lua_pushboolean (L, GI_TYPE_TAG_IS_BASIC (tag)); - return 1; + + if (GI_IS_VALUE_INFO(*info)) { + if (strcmp(prop, "value") == 0) { + lua_pushinteger(L, gi_value_info_get_value(GI_VALUE_INFO(*info))); + return 1; + } } - else if (strcmp (prop, "params") == 0) - { - if (tag == GI_TYPE_TAG_ARRAY || tag == GI_TYPE_TAG_GLIST || - tag == GI_TYPE_TAG_GSLIST || tag == GI_TYPE_TAG_GHASH) - { - lua_newtable (L); - lua_gobject_gi_info_new (L, GI_BASE_INFO (gi_type_info_get_param_type (GI_TYPE_INFO (*info), 0))); - lua_rawseti (L, -2, 1); - if (tag == GI_TYPE_TAG_GHASH) - { - lua_gobject_gi_info_new (L, GI_BASE_INFO (gi_type_info_get_param_type (GI_TYPE_INFO (*info), 1))); - lua_rawseti (L, -2, 2); + + if (GI_IS_ARG_INFO(*info)) { + if (strcmp(prop, "direction") == 0) { + GIDirection dir = gi_arg_info_get_direction(GI_ARG_INFO(*info)); + if (dir == GI_DIRECTION_OUT) + lua_pushstring(L, + gi_arg_info_is_caller_allocates(GI_ARG_INFO(*info)) + ? "out-caller-alloc" : "out"); + else + lua_pushstring(L, dir == GI_DIRECTION_IN ? "in" : "inout"); + return 1; + } + if (strcmp(prop, "transfer") == 0) + return info_push_transfer(L, + gi_arg_info_get_ownership_transfer(GI_ARG_INFO(*info))); + if (strcmp(prop, "optional") == 0) { + lua_pushboolean(L, gi_arg_info_is_optional(GI_ARG_INFO(*info)) + || gi_arg_info_may_be_null(GI_ARG_INFO(*info))); + return 1; } - return 1; - } } - else if (strcmp (prop, "interface") == 0 && tag == GI_TYPE_TAG_INTERFACE) - { - lua_gobject_gi_info_new (L, gi_type_info_get_interface (GI_TYPE_INFO (*info))); - return 1; + + if (GI_IS_PROPERTY_INFO(*info)) { + if (strcmp(prop, "flags") == 0) { + lua_pushinteger(L, + gi_property_info_get_flags(GI_PROPERTY_INFO(*info))); + return 1; + } + else if (strcmp(prop, "transfer") == 0) + return info_push_transfer(L, + gi_property_info_get_ownership_transfer( + GI_PROPERTY_INFO(*info))); } - else if (strcmp (prop, "array_type") == 0 && tag == GI_TYPE_TAG_ARRAY) - { - switch (gi_type_info_get_array_type (GI_TYPE_INFO (*info))) - { -#define H(n1, n2) \ - case GI_ARRAY_TYPE_ ## n1: \ - lua_pushstring (L, #n2); \ - return 1; - H(C, c) - H(ARRAY, array) - H(PTR_ARRAY, ptr_array) - H(BYTE_ARRAY, byte_array) + if (GI_IS_FIELD_INFO(*info)) { + if (strcmp(prop, "flags") == 0) { + GIFieldInfoFlags flags = gi_field_info_get_flags(GI_FIELD_INFO(*info)); + lua_newtable(L); + if (0); +#define H(n1, n2) \ + else if ((flags & GI_FIELD_ ## n1) != 0) { \ + lua_pushboolean(L, 1); \ + lua_setfield(L, -2, #n2); \ + } + H(IS_READABLE, is_readable) + H(IS_WRITABLE, is_writable) #undef H - default: - g_assert_not_reached (); - } - } - else if (strcmp (prop, "is_zero_terminated") == 0 - && tag == GI_TYPE_TAG_ARRAY) - { - lua_pushboolean (L, gi_type_info_is_zero_terminated (GI_TYPE_INFO (*info))); - return 1; - } - else if (strcmp (prop, "array_length") == 0) - { - guint len; - if (gi_type_info_get_array_length_index (GI_TYPE_INFO (*info), &len)) - { - lua_pushinteger (L, len); - return 1; - } - } - else if (strcmp (prop, "fixed_size") == 0) - { - gsize size; - if (gi_type_info_get_array_fixed_size (GI_TYPE_INFO (*info), &size)) - { - lua_pushinteger (L, size); - return 1; - } + return 1; + } else if (strcmp(prop, "size") == 0) { + lua_pushinteger(L, gi_field_info_get_size(GI_FIELD_INFO(*info))); + return 1; + } else if (strcmp(prop, "offset") == 0) { + lua_pushinteger(L, gi_field_info_get_offset(GI_FIELD_INFO(*info))); + return 1; + } } - else if (strcmp (prop, "is_pointer") == 0) - { - lua_pushboolean (L, gi_type_info_is_pointer (GI_TYPE_INFO (*info))); - return 1; + + if (GI_IS_TYPE_INFO(*info)) { + GITypeTag tag = gi_type_info_get_tag(GI_TYPE_INFO(*info)); + if (strcmp(prop, "tag") == 0) { + lua_pushstring(L, gi_type_tag_to_string(tag)); + return 1; + } else if (strcmp(prop, "is_basic") == 0) { + lua_pushboolean(L, GI_TYPE_TAG_IS_BASIC(tag)); + return 1; + } else if (strcmp(prop, "params") == 0) { + if (tag == GI_TYPE_TAG_ARRAY || tag == GI_TYPE_TAG_GLIST + || tag == GI_TYPE_TAG_GSLIST + || tag == GI_TYPE_TAG_GHASH) { + lua_newtable(L); + lua_gobject_gi_info_new(L, + GI_BASE_INFO(gi_type_info_get_param_type( + GI_TYPE_INFO(*info), 0))); + lua_rawseti(L, -2, 1); + if (tag == GI_TYPE_TAG_GHASH) { + lua_gobject_gi_info_new(L, GI_BASE_INFO( + gi_type_info_get_param_type( + GI_TYPE_INFO(*info), 1))); + lua_rawseti(L, -2, 2); + } + return 1; + } + } else if (strcmp(prop, "interface") == 0 + && tag == GI_TYPE_TAG_INTERFACE) { + lua_gobject_gi_info_new(L, gi_type_info_get_interface( + GI_TYPE_INFO(*info))); + return 1; + } else if (strcmp(prop, "array_type") == 0 && tag == GI_TYPE_TAG_ARRAY) { + switch(gi_type_info_get_array_type(GI_TYPE_INFO(*info))) { +#define H(n1, n2) \ + case GI_ARRAY_TYPE_ ## n1: \ + lua_pushstring(L, #n2); \ + return 1; + + H(C, c) + H(ARRAY, array) + H(PTR_ARRAY, ptr_array) + H(BYTE_ARRAY, byte_array) +#undef H + default: + g_assert_not_reached(); + } + } else if (strcmp(prop, "is_zero_terminated") == 0 + && tag == GI_TYPE_TAG_ARRAY) { + lua_pushboolean(L, gi_type_info_is_zero_terminated( + GI_TYPE_INFO(*info))); + return 1; + } else if (strcmp(prop, "array_length") == 0) { + guint len; + if (gi_type_info_get_array_length_index(GI_TYPE_INFO(*info), &len)) { + lua_pushinteger(L, len); + return 1; + } + } else if (strcmp(prop, "fixed_size") == 0) { + gsize size; + if (gi_type_info_get_array_fixed_size(GI_TYPE_INFO(*info), &size)) { + lua_pushinteger(L, size); + return 1; + } + } else if (strcmp(prop, "is_pointer") == 0) { + lua_pushboolean(L, gi_type_info_is_pointer(GI_TYPE_INFO(*info))); + return 1; + } } - } - lua_pushnil (L); - return 1; + lua_pushnil(L); + return 1; #undef INFOS #undef INFOS2 } static int -info_eq (lua_State *L) +info_eq(lua_State *L) { - GIBaseInfo **i1 = luaL_checkudata (L, 1, LUA_GOBJECT_GI_INFO); - GIBaseInfo **i2 = luaL_checkudata (L, 2, LUA_GOBJECT_GI_INFO); - lua_pushboolean (L, gi_base_info_equal (*i1, *i2)); - return 1; + GIBaseInfo **i1 = luaL_checkudata(L, 1, LUA_GOBJECT_GI_INFO); + GIBaseInfo **i2 = luaL_checkudata(L, 2, LUA_GOBJECT_GI_INFO); + lua_pushboolean(L, gi_base_info_equal(*i1, *i2)); + return 1; } static int -info_gc (lua_State *L) +info_gc(lua_State *L) { - GIBaseInfo **info = luaL_checkudata (L, 1, LUA_GOBJECT_GI_INFO); - gi_base_info_unref (*info); - return 0; + GIBaseInfo **info = luaL_checkudata(L, 1, LUA_GOBJECT_GI_INFO); + gi_base_info_unref(*info); + return 0; } static const luaL_Reg gi_info_reg[] = { - { "__gc", info_gc }, - { "__index", info_index }, - { "__eq", info_eq }, - { NULL, NULL } + { "__gc", info_gc }, + { "__index", info_index }, + { "__eq", info_eq }, + { NULL, NULL } }; /* Userdata representing symbol resolver of the namespace. */ #define LUA_GOBJECT_GI_RESOLVER "lua_gobject.gi.resolver" static int -resolver_index (lua_State *L) +resolver_index(lua_State *L) { - gpointer address; - GITypelib **typelib = luaL_checkudata (L, 1, LUA_GOBJECT_GI_RESOLVER); - if (gi_typelib_symbol (*typelib, luaL_checkstring (L, 2), &address)) - { - lua_pushlightuserdata (L, address); - return 1; - } - - return 0; + gpointer address; + GITypelib **typelib = luaL_checkudata(L, 1, LUA_GOBJECT_GI_RESOLVER); + if (gi_typelib_symbol(*typelib, luaL_checkstring(L, 2), &address)) { + lua_pushlightuserdata(L, address); + return 1; + } + + return 0; } static const luaL_Reg gi_resolver_reg[] = { - { "__index", resolver_index }, - { NULL, NULL } + { "__index", resolver_index }, + { NULL, NULL } }; /* Userdata representing namespace in girepository. */ #define LUA_GOBJECT_GI_NAMESPACE "lua_gobject.gi.namespace" static int -namespace_len (lua_State *L) +namespace_len(lua_State *L) { - const gchar *ns = luaL_checkudata (L, 1, LUA_GOBJECT_GI_NAMESPACE); - lua_pushinteger (L, gi_repository_get_n_infos (lua_gobject_gi_get_repository (), ns)); - return 1; + const gchar *ns = luaL_checkudata(L, 1, LUA_GOBJECT_GI_NAMESPACE); + lua_pushinteger(L, gi_repository_get_n_infos( + lua_gobject_gi_get_repository(), ns)); + return 1; } static int -namespace_index (lua_State *L) +namespace_index(lua_State *L) { - const gchar *ns = luaL_checkudata (L, 1, LUA_GOBJECT_GI_NAMESPACE); - const gchar *prop; - if (lua_type (L, 2) == LUA_TNUMBER) - { - GIBaseInfo *info = gi_repository_get_info (lua_gobject_gi_get_repository (), ns, - lua_tointeger (L, 2) - 1); - return lua_gobject_gi_info_new (L, info); - } - prop = luaL_checkstring (L, 2); - if (strcmp (prop, "dependencies") == 0) - { - gchar **deps = gi_repository_get_dependencies (lua_gobject_gi_get_repository (), ns, NULL); - if (deps == NULL) - lua_pushnil (L); - else - { - int index; - gchar **dep; - lua_newtable (L); - for (index = 1, dep = deps; *dep; dep++, index++) - { - const gchar *sep = strchr (*dep, '-'); - lua_pushlstring (L, *dep, sep - *dep); - lua_pushstring (L, sep + 1); - lua_settable (L, -3); - } - g_strfreev (deps); + const gchar *ns = luaL_checkudata(L, 1, LUA_GOBJECT_GI_NAMESPACE); + const gchar *prop; + if (lua_type(L, 2) == LUA_TNUMBER) { + GIBaseInfo *info = gi_repository_get_info( + lua_gobject_gi_get_repository(), ns, lua_tointeger(L, 2) - 1); + return lua_gobject_gi_info_new(L, info); } + prop = luaL_checkstring(L, 2); + if (strcmp(prop, "dependencies") == 0) { + gchar **deps = gi_repository_get_dependencies( + lua_gobject_gi_get_repository(), ns, NULL); + if (deps == NULL) + lua_pushnil(L); + else { + int index; + gchar **dep; + lua_newtable(L); + for (index = 1, dep = deps; *dep; dep++, index++) { + const gchar *sep = strchr(*dep, '-'); + lua_pushlstring(L, *dep, sep - *dep); + lua_pushstring(L, sep + 1); + lua_settable(L, -3); + } + g_strfreev(deps); + } - return 1; - } - else if (strcmp (prop, "version") == 0) - { - lua_pushstring (L, gi_repository_get_version (lua_gobject_gi_get_repository (), ns)); - return 1; - } - else if (strcmp (prop, "name") == 0) - { - lua_pushstring (L, ns); - return 1; - } - else if (strcmp (prop, "resolve") == 0) - { - GITypelib **udata = lua_newuserdata (L, sizeof (GITypelib *)); - luaL_getmetatable (L, LUA_GOBJECT_GI_RESOLVER); - lua_setmetatable (L, -2); - *udata = gi_repository_require (lua_gobject_gi_get_repository (), ns, NULL, 0, NULL); - return 1; - } - else - /* Try to lookup the symbol. */ - return lua_gobject_gi_info_new (L, gi_repository_find_by_name (lua_gobject_gi_get_repository (), ns, prop)); + return 1; + } else if (strcmp(prop, "version") == 0) { + lua_pushstring(L, gi_repository_get_version( + lua_gobject_gi_get_repository(), ns)); + return 1; + } else if (strcmp(prop, "name") == 0) { + lua_pushstring(L, ns); + return 1; + } else if (strcmp(prop, "resolve") == 0) { + GITypelib **udata = lua_newuserdata(L, sizeof(GITypelib *)); + luaL_getmetatable(L, LUA_GOBJECT_GI_RESOLVER); + lua_setmetatable(L, -2); + *udata = gi_repository_require(lua_gobject_gi_get_repository(), + ns, NULL, 0, NULL); + return 1; + } + else + /* Try to lookup the symbol. */ + return lua_gobject_gi_info_new(L, + gi_repository_find_by_name( + lua_gobject_gi_get_repository(), ns, prop)); } static int -namespace_new (lua_State *L, const gchar *namespace) +namespace_new(lua_State *L, const gchar *namespace) { - gchar *ns = lua_newuserdata (L, strlen (namespace) + 1); - luaL_getmetatable (L, LUA_GOBJECT_GI_NAMESPACE); - lua_setmetatable (L, -2); - strcpy (ns, namespace); - return 1; + gchar *ns = lua_newuserdata(L, strlen(namespace) + 1); + luaL_getmetatable(L, LUA_GOBJECT_GI_NAMESPACE); + lua_setmetatable(L, -2); + strcpy(ns, namespace); + return 1; } static const luaL_Reg gi_namespace_reg[] = { - { "__index", namespace_index }, - { "__len", namespace_len }, - { NULL, NULL } + { "__index", namespace_index }, + { "__len", namespace_len }, + { NULL, NULL } }; /* Lua API: core.gi.require(namespace[, version[, typelib_dir]]) */ static int -gi_require (lua_State *L) +gi_require(lua_State *L) { - GError *err = NULL; - const gchar *namespace = luaL_checkstring (L, 1); - const gchar *version = luaL_optstring (L, 2, NULL); - const gchar *typelib_dir = luaL_optstring (L, 3, NULL); - GITypelib *typelib; - - if (typelib_dir == NULL) - typelib = gi_repository_require (lua_gobject_gi_get_repository (), namespace, version, 0, &err); - else - typelib = gi_repository_require_private (lua_gobject_gi_get_repository (), typelib_dir, namespace, - version, 0, &err); - if (!typelib) - { - lua_pushboolean (L, 0); - lua_pushstring (L, err->message); - lua_pushinteger (L, err->code); - g_error_free (err); - return 3; - } - - return namespace_new (L, namespace); + GError *err = NULL; + const gchar *namespace = luaL_checkstring(L, 1); + const gchar *version = luaL_optstring(L, 2, NULL); + const gchar *typelib_dir = luaL_optstring(L, 3, NULL); + GITypelib *typelib; + + if (typelib_dir == NULL) + typelib = gi_repository_require(lua_gobject_gi_get_repository(), + namespace, version, 0, &err); + else + typelib = gi_repository_require_private(lua_gobject_gi_get_repository(), + typelib_dir, namespace, version, 0, &err); + if (!typelib) { + lua_pushboolean(L, 0); + lua_pushstring(L, err->message); + lua_pushinteger(L, err->code); + g_error_free(err); + return 3; + } + + return namespace_new(L, namespace); } /* Lua API: boolean = core.gi.isinfo(info) */ static int -gi_isinfo (lua_State *L) +gi_isinfo(lua_State *L) { - if (lua_getmetatable (L, 1)) - { - luaL_getmetatable (L, LUA_GOBJECT_GI_INFO); - lua_pushboolean (L, lua_rawequal (L, -1, -2)); - } - else - lua_pushboolean (L, 0); - return 1; + if (lua_getmetatable(L, 1)) { + luaL_getmetatable(L, LUA_GOBJECT_GI_INFO); + lua_pushboolean(L, lua_rawequal(L, -1, -2)); + } + else + lua_pushboolean(L, 0); + return 1; } static int -gi_index (lua_State *L) +gi_index(lua_State *L) { - if (lua_type (L, 2) == LUA_TLIGHTUSERDATA) - { - GType gtype = (GType) lua_touserdata (L, 2); - GIBaseInfo *info = (gtype != G_TYPE_INVALID) - ? gi_repository_find_by_gtype (lua_gobject_gi_get_repository (), gtype) : NULL; - return lua_gobject_gi_info_new (L, info); - } - else if (lua_type (L, 2) == LUA_TNUMBER) - { - GQuark domain = (GQuark) lua_tointeger (L, 2); - GIBaseInfo *info = GI_BASE_INFO (gi_repository_find_by_error_domain (lua_gobject_gi_get_repository (), domain)); - return lua_gobject_gi_info_new (L, info); - } - else - { - const gchar *ns = luaL_checkstring (L, 2); - if (gi_repository_is_registered (lua_gobject_gi_get_repository (), ns, NULL)) - return namespace_new (L, ns); - } - - return 0; + if (lua_type(L, 2) == LUA_TLIGHTUSERDATA) { + GType gtype = (GType) lua_touserdata(L, 2); + GIBaseInfo *info = (gtype != G_TYPE_INVALID) + ? gi_repository_find_by_gtype(lua_gobject_gi_get_repository(), gtype) + : NULL; + return lua_gobject_gi_info_new(L, info); + } else if (lua_type(L, 2) == LUA_TNUMBER) { + GQuark domain = (GQuark) lua_tointeger(L, 2); + GIBaseInfo *info = GI_BASE_INFO(gi_repository_find_by_error_domain( + lua_gobject_gi_get_repository(), domain)); + return lua_gobject_gi_info_new(L, info); + } else { + const gchar *ns = luaL_checkstring(L, 2); + if (gi_repository_is_registered(lua_gobject_gi_get_repository(), ns, NULL)) + return namespace_new(L, ns); + } + + return 0; } -typedef struct _Reg -{ - const gchar *name; - const luaL_Reg* reg; +typedef struct _Reg { + const gchar *name; + const luaL_Reg* reg; } Reg; static const Reg gi_reg[] = { - { LUA_GOBJECT_GI_INFOS, gi_infos_reg }, - { LUA_GOBJECT_GI_INFO, gi_info_reg }, - { LUA_GOBJECT_GI_NAMESPACE, gi_namespace_reg }, - { LUA_GOBJECT_GI_RESOLVER, gi_resolver_reg }, - { NULL, NULL } + { LUA_GOBJECT_GI_INFOS, gi_infos_reg }, + { LUA_GOBJECT_GI_INFO, gi_info_reg }, + { LUA_GOBJECT_GI_NAMESPACE, gi_namespace_reg }, + { LUA_GOBJECT_GI_RESOLVER, gi_resolver_reg }, + { NULL, NULL } }; static const luaL_Reg gi_api_reg[] = { - { "require", gi_require }, - { "isinfo", gi_isinfo }, - { NULL, NULL } + { "require", gi_require }, + { "isinfo", gi_isinfo }, + { NULL, NULL } }; void -lua_gobject_gi_init (lua_State *L) +lua_gobject_gi_init(lua_State *L) { - const Reg *reg; - - /* Register metatables for userdata objects. */ - for (reg = gi_reg; reg->name; reg++) - { - luaL_newmetatable (L, reg->name); - luaL_register (L, NULL, reg->reg); - lua_pop (L, 1); - } - - /* Register global API. */ - lua_newtable (L); - luaL_register (L, NULL, gi_api_reg); - lua_newtable (L); - lua_pushcfunction (L, gi_index); - lua_setfield (L, -2, "__index"); - lua_setmetatable (L, -2); - lua_setfield (L, -2, "gi"); + const Reg *reg; + + /* Register metatables for userdata objects. */ + for (reg = gi_reg; reg->name; reg++) { + luaL_newmetatable(L, reg->name); + luaL_register(L, NULL, reg->reg); + lua_pop(L, 1); + } + + /* Register global API. */ + lua_newtable(L); + luaL_register(L, NULL, gi_api_reg); + lua_newtable(L); + lua_pushcfunction(L, gi_index); + lua_setfield(L, -2, "__index"); + lua_setmetatable(L, -2); + lua_setfield(L, -2, "gi"); } #if !GLIB_CHECK_VERSION(2, 30, 0) -/* Workaround for broken gi_struct_info_get_size() for GValue, see - https://bugzilla.gnome.org/show_bug.cgi?id=657040 */ +/* Workaround for broken gi_struct_info_get_size() for GValue, see https://bugzilla.gnome.org/show_bug.cgi?id=657040 */ static GIStructInfo *parameter_info = NULL; static GIFieldInfo *parameter_value_info = NULL; #undef gi_struct_info_get_size gsize -lua_gobject_struct_info_get_size (GIStructInfo *info) +lua_gobject_struct_info_get_size(GIStructInfo *info) { - if (parameter_info == NULL) - parameter_info = gi_repository_find_by_name (lua_gobject_gi_get_repository (), "GObject", "Parameter"); - if (g_registered_type_info_get_g_type (info) == G_TYPE_VALUE) - return sizeof (GValue); - else if (parameter_info && gi_base_info_equal (info, parameter_info)) - return sizeof (GParameter); - return gi_struct_info_get_size (info); + if (parameter_info == NULL) + parameter_info = gi_repository_find_by_name( + lua_gobject_gi_get_repository(), "GObject", "Parameter"); + if (g_registered_type_info_get_g_type(info) == G_TYPE_VALUE) + return sizeof(GValue); + else if (parameter_info && gi_base_info_equal(info, parameter_info)) + return sizeof(GParameter); + return gi_struct_info_get_size(info); } #undef gi_field_info_get_offset gint -lua_gobject_field_info_get_offset (GIFieldInfo *info) +lua_gobject_field_info_get_offset(GIFieldInfo *info) { - if (parameter_value_info == NULL) - { - if (parameter_info == NULL) - parameter_info = gi_repository_find_by_name (lua_gobject_gi_get_repository (), - "GObject", "Parameter"); - parameter_value_info = gi_struct_info_get_field (parameter_info, 1); - } - if (parameter_value_info && gi_base_info_equal (info, parameter_value_info)) - return G_STRUCT_OFFSET (GParameter, value); - return gi_field_info_get_offset (info); + if (parameter_value_info == NULL) { + if (parameter_info == NULL) + parameter_info = gi_repository_find_by_name( + lua_gobject_gi_get_repository(), + "GObject", + "Parameter"); + parameter_value_info = gi_struct_info_get_field(parameter_info, 1); + } + if (parameter_value_info && gi_base_info_equal(info, parameter_value_info)) + return G_STRUCT_OFFSET(GParameter, value); + return gi_field_info_get_offset(info); } #endif diff --git a/LuaGObject/init.lua b/LuaGObject/init.lua index addb7e4c..06f2798e 100644 --- a/LuaGObject/init.lua +++ b/LuaGObject/init.lua @@ -1,17 +1,11 @@ ------------------------------------------------------------------------------- --- --- LGI Lua-side core. --- --- Copyright (c) 2010, 2011 Pavel Holejsovsky --- Licensed under the MIT license: --- http://www.opensource.org/licenses/mit-license.php --- ------------------------------------------------------------------------------- +-- LGI Lua-side core. +-- Copyright (c) 2010, 2011 Pavel Holejsovsky +-- Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php local assert, require, pcall, setmetatable, pairs, type, error, tostring, -_VERSION, jit - = assert, require, pcall, setmetatable, pairs, type, error, tostring, -_VERSION, rawget(_G, 'jit') + _VERSION, jit + = assert, require, pcall, setmetatable, pairs, type, error, tostring, + _VERSION, rawget(_G, 'jit') local package = require 'package' @@ -19,29 +13,29 @@ local package = require 'package' local core = require 'LuaGObject.core' -- Create LuaGObject table, containing the module. -local LuaGObject = { _NAME = 'LuaGObject', _VERSION = require 'LuaGObject.version' } +local LuaGObject = { + _NAME = 'LuaGObject', + _VERSION = require 'LuaGObject.version', +} -- Forward selected core methods into external interface. for _, name in pairs { 'yield', 'lock', 'enter', 'leave' } do - LuaGObject[name] = core[name] + LuaGObject[name] = core[name] end --- If global package 'bytes' does not exist (i.e. not provided --- externally), use our internal (although incomplete) implementation. +-- If global package 'bytes' does not exist (i.e. not provided externally), use our internal (although incomplete) implementation. local ok, bytes = pcall(require, 'bytes') if not ok or not bytes then - package.loaded.bytes = core.bytes + package.loaded.bytes = core.bytes end --- Prepare logging support. 'log' is module-exported table, containing all --- functionality related to logging wrapped around GLib g_log facility. +-- Prepare logging support. 'log' is module-exported table, containing all functionality related to logging wrapped around GLib g_log facility. LuaGObject.log = require 'LuaGObject.log' -- For the rest of bootstrap, prepare logging to LuaGObject domain. local log = LuaGObject.log.domain('LuaGObject') --- Repository, table with all loaded namespaces. Its metatable takes care of --- loading on-demand. Created by C-side bootstrap. +-- Repository, table with all loaded namespaces. Its metatable takes care of loading on-demand. Created by C-side bootstrap. local repo = core.repo local namespace = require 'LuaGObject.namespace' @@ -50,31 +44,32 @@ LuaGObject.require = namespace.require -- Install 'LuaGObject.package' method. LuaGObject.package = require('LuaGObject.package').ensure --- Add assert override, which accepts not only text message but any --- kind of error object. +-- Add assert override, which accepts not only text message but any kind of error object. function LuaGObject.assert(cond, ...) - if cond then return cond, ... end - local err = ... - if _VERSION == 'Lua 5.1' and not jit then - -- Lua 5.1 does not support displaying message of non-string - -- errors on the commandline interpreter, so better stringize - -- the error message right now. - err = tostring(err) - end - error(err, 2) + if cond then return cond, ... end + local err = ... + if _VERSION == 'Lua 5.1' and not jit then + -- Lua 5.1 does not support displaying message of non-string + -- errors on the commandline interpreter, so better stringize + -- the error message right now. + err = tostring(err) + end + error(err, 2) end -- Install metatable into repo table, so that on-demand loading works. -setmetatable(repo, { __index = function(_, name) - return LuaGObject.require(name) - end }) +setmetatable(repo, { + __index = function(_, name) + return LuaGObject.require(name) + end, +}) -- Create lazy-loading components for base gobject entities. assert(core.gi.require ('GLib', '2.0')) assert(core.gi.require ('GObject', '2.0')) repo.GObject._precondition = {} for _, name in pairs { 'Type', 'Value', 'Closure', 'Object' } do - repo.GObject._precondition[name] = 'GObject-' .. name + repo.GObject._precondition[name] = 'GObject-' .. name end repo.GObject._precondition.InitiallyUnowned = 'GObject-Object' @@ -88,9 +83,8 @@ repo.GLib._precondition.MarkupParseContext = 'GLib-Markup' repo.GLib._precondition.Source = 'GLib-Source' repo.GLib._precondition.SourceFuncs = 'GLib-Source' for _, name in pairs { 'Variant', 'VariantType', 'VariantBuilder' } do - repo.GLib._precondition[name] = 'GLib-Variant' + repo.GLib._precondition[name] = 'GLib-Variant' end --- Access to module proxies the whole repo, so that LuaGObject.'namespace' --- notation works. +-- Access to module proxies the whole repo, so that LuaGObject.'namespace' notation works. return setmetatable(LuaGObject, { __index = repo }) diff --git a/LuaGObject/log.lua b/LuaGObject/log.lua index 2d5cf021..e9b7edbc 100644 --- a/LuaGObject/log.lua +++ b/LuaGObject/log.lua @@ -1,12 +1,6 @@ ------------------------------------------------------------------------------- --- --- LGI support for GLib-based logging. --- --- Copyright (c) 2011 Pavel Holejsovsky --- Licensed under the MIT license: --- http://www.opensource.org/licenses/mit-license.php --- ------------------------------------------------------------------------------- +-- LGI support for GLib-based logging. +-- Copyright (c) 2011 Pavel Holejsovsky +-- Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php local pcall, ipairs = pcall, ipairs local string = require 'string' @@ -17,22 +11,21 @@ local log = {} -- Creates table containing methods 'message', 'warning', 'critical', 'error', -- 'debug' methods which log to specified domain. function log.domain(name) - local domain = log[name] or {} - for _, level in ipairs { 'message', 'warning', 'critical', - 'error', 'debug' } do - if not domain[level] then - domain[level] = - function(format, ...) - local ok, msg = pcall(string.format, format, ...) - if not ok then - msg = ("BAD FMT: `%s', `%s'"):format(format, msg) - end - core.log(name, core.upcase(level), msg) - end - end - end - log[name] = domain - return domain + local domain = log[name] or {} + for _, level in ipairs { 'message', 'warning', 'critical', 'error', 'debug' } do + if not domain[level] then + domain[level] = + function(format, ...) + local ok, msg = pcall(string.format, format, ...) + if not ok then + msg = ("BAD FMT: `%s', `%s'"):format(format, msg) + end + core.log(name, core.upcase(level), msg) + end + end + end + log[name] = domain + return domain end return log diff --git a/LuaGObject/lua_gobject.h b/LuaGObject/lua_gobject.h index cdd16064..3da27f30 100644 --- a/LuaGObject/lua_gobject.h +++ b/LuaGObject/lua_gobject.h @@ -1,10 +1,6 @@ -/* - * Dynamic Lua binding to GObject using dynamic gobject-introspection. - * - * Author: Pavel Holejsovsky (pavel.holejsovsky@gmail.com) - * - * License: MIT. - */ +/* Dynamic Lua binding to GObject using dynamic gobject-introspection. +Author: Pavel Holejsovsky (pavel.holejsovsky@gmail.com) +License: MIT. */ #define G_LOG_DOMAIN "LuaGObject" @@ -55,25 +51,19 @@ typedef unsigned long lua_gobject_Unsigned; /* Makes sure that Lua stack offset is absolute one, not relative. */ #define lua_gobject_makeabs(L, x) do { if (x < 0) x += lua_gettop (L) + 1; } while (0) -/* Puts parts of the name to the stack, to be concatenated by lua_concat. - Returns number of pushed elements. */ +/* Puts parts of the name to the stack, to be concatenated by lua_concat. Returns number of pushed elements. */ int lua_gobject_type_get_name (lua_State *L, GIBaseInfo *info); -/* Stores repo type table associated with specified gtype (or BaseInfo - if gtype is invalid). to the stack, or nil if no such table can be - found in the repo. */ +/* Stores repo type table associated with specified gtype (or BaseInfo if gtype is invalid). to the stack, or nil if no such table can be found in the repo. */ void lua_gobject_type_get_repotype (lua_State *L, GType gtype, GIBaseInfo *info); -/* Gets GType from Lua index narg. Accepts number and when it is - other type, invokes Lua helper to convert. */ +/* Gets GType from Lua index narg. Accepts number and when it is other type, invokes Lua helper to convert. */ GType lua_gobject_type_get_gtype (lua_State *L, int narg); -/* Allocates guard, a pointer-size userdata with associated destroy - handler. Returns pointer to user_data stored inside guard. */ +/* Allocates guard, a pointer-size userdata with associated destroy handler. Returns pointer to user_data stored inside guard. */ gpointer *lua_gobject_guard_create (lua_State *L, GDestroyNotify destroy); -/* Creates cache table (optionally with given table __mode), stores it - into registry to specified userdata address. */ +/* Creates cache table (optionally with given table __mode), stores it into registry to specified userdata address. */ void lua_gobject_cache_create (lua_State *L, gpointer key, const char *mode); @@ -85,13 +75,11 @@ void lua_gobject_callable_init (lua_State *L); void lua_gobject_gi_init (lua_State *L); void lua_gobject_buffer_init (lua_State *L); -/* Checks whether given argument is of specified udata - similar to - luaL_testudata, which is missing in Lua 5.1 */ +/* Checks whether given argument is of specified udata - similar to luaL_testudata, which is missing in Lua 5.1 */ void * lua_gobject_udata_test (lua_State *L, int narg, const char *name); -/* Metatable name of userdata for 'bytes' extension; see - http://permalink.gmane.org/gmane.comp.lang.lua.general/79288 */ +/* Metatable name of userdata for 'bytes' extension; see http://permalink.gmane.org/gmane.comp.lang.lua.general/79288 */ #define LUA_GOBJECT_BYTES_BUFFER "bytes.bytearray" /* Metatable name of userdata - gi wrapped 'GIBaseInfo*' */ @@ -100,126 +88,92 @@ lua_gobject_udata_test (lua_State *L, int narg, const char *name); /* Creates new instance of info from given GIBaseInfo pointer. */ int lua_gobject_gi_info_new (lua_State *L, GIBaseInfo *info); -/* Assumes that 'typetable' can hold field 'name' which contains - wrapped LUA_GOBJECT_GI_INFO of function. Returns address of this function, - NULL if table does not contain such field. */ +/* Assumes that 'typetable' can hold field 'name' which contains wrapped LUA_GOBJECT_GI_INFO of function. Returns address of this function, NULL if table does not contain such field. */ gpointer lua_gobject_gi_load_function(lua_State *L, int typetable, const char *name); -/* Retrieve synchronization state, which can be used for entering and - leaving the state using lua_gobject_state_enter() and lua_gobject_state_leave(). */ +/* Retrieve synchronization state, which can be used for entering and leaving the state using lua_gobject_state_enter() and lua_gobject_state_leave(). */ gpointer lua_gobject_state_get_lock (lua_State *L); /* Enters/leaves Lua state. */ void lua_gobject_state_enter (gpointer left_state); void lua_gobject_state_leave (gpointer state_lock); -/* Special value for 'parent' argument of marshal_2c/lua. When parent - is set to this value, marshalling takes place always into pointer - on the C side. This isuseful when marshalling value from/to lists, - arrays and hashtables. */ +/* Special value for 'parent' argument of marshal_2c/lua. When parent is set to this value, marshalling takes place always into pointer on the C side. This isuseful when marshalling value from/to lists, arrays and hashtables. */ #define LUA_GOBJECT_PARENT_FORCE_POINTER G_MAXINT -/* Another special value for 'parent' argument, meaning that the value - should be handled as return value, according to ffi_call retval - requirements. */ +/* Another special value for 'parent' argument, meaning that the value should be handled as return value, according to ffi_call retval requirements. */ #define LUA_GOBJECT_PARENT_IS_RETVAL (G_MAXINT - 1) -/* Yet another special value for 'parent' argument, meaning that the - value already contains address of caller-allocated space into which - the result should be marshalled. */ +/* Yet another special value for 'parent' argument, meaning that the value already contains address of caller-allocated space into which the result should be marshalled. */ #define LUA_GOBJECT_PARENT_CALLER_ALLOC (G_MAXINT - 2) -/* Marshalls single value from Lua to GLib/C. Returns number of temporary - entries pushed to Lua stack, which should be popped before function call - returns. */ +/* Marshalls single value from Lua to GLib/C. Returns number of temporary entries pushed to Lua stack, which should be popped before function call returns. */ int lua_gobject_marshal_2c (lua_State *L, GITypeInfo *ti, GIArgInfo *ai, - GITransfer xfer, gpointer target, int narg, - int parent, GICallableInfo *ci, void **args); + GITransfer xfer, gpointer target, int narg, + int parent, GICallableInfo *ci, void **args); -/* If given parameter is out:caller-allocates, tries to perform - special 2c marshalling. If not needed, returns FALSE, otherwise - stores single value with value prepared to be returned to C. */ +/* If given parameter is out:caller-allocates, tries to perform special 2c marshalling. If not needed, returns FALSE, otherwise stores single value with value prepared to be returned to C. */ gboolean lua_gobject_marshal_2c_caller_alloc (lua_State *L, GITypeInfo *ti, - GIArgument *target, int pos); + GIArgument *target, int pos); -/* Marshalls single value from GLib/C to Lua. If parent is non-0, it - is stack index of parent structure/array in which this C value - resides. */ +/* Marshalls single value from GLib/C to Lua. If parent is non-0, it is stack index of parent structure/array in which this C value resides. */ void lua_gobject_marshal_2lua (lua_State *L, GITypeInfo *ti, GIArgInfo *ai, - GIDirection dir, GITransfer xfer, - gpointer source, int parent, - GICallableInfo *ci, void *args); + GIDirection dir, GITransfer xfer, + gpointer source, int parent, + GICallableInfo *ci, void *args); -/* Marshalls field to/from given memory (struct, union or - object). Returns number of results pushed to the stack (0 or 1). */ +/* Marshalls field to/from given memory (struct, union or object). Returns number of results pushed to the stack (0 or 1). */ int lua_gobject_marshal_field (lua_State *L, gpointer object, gboolean getmode, - int parent_arg, int field_arg, int val_arg); + int parent_arg, int field_arg, int val_arg); /* Implementation of object/record _access invocation. */ int lua_gobject_marshal_access (lua_State *L, gboolean getmode, int compound_arg, int element_arg, int val_arg); -/* Parses given GICallableInfo, creates new userdata for it and stores - it to the stack. */ +/* Parses given GICallableInfo, creates new userdata for it and stores it to the stack. */ int lua_gobject_callable_create (lua_State *L, GICallableInfo *ci, gpointer addr); /* Parses callable from table-driven info description. */ int lua_gobject_callable_parse (lua_State *L, int info, gpointer addr); -/* Creates container block for allocated closures. Returns address of - the block, suitable as user_data parameter. */ +/* Creates container block for allocated closures. Returns address of the block, suitable as user_data parameter. */ gpointer lua_gobject_closure_allocate (lua_State *L, int count); -/* Allocates n-th closure in the closure block for specified Lua - function (or callable table or userdata). Assumes Callable to be - created on the stack, pops it. Returns executable address for the - closure. */ +/* Allocates n-th closure in the closure block for specified Lua function (or callable table or userdata). Assumes Callable to be created on the stack, pops it. Returns executable address for the closure. */ gpointer lua_gobject_closure_create (lua_State* L, gpointer user_data, int target, gboolean autodestroy); /* GDestroyNotify-compatible callback for destroying closure. */ void lua_gobject_closure_destroy (gpointer user_data); -/* Allocates and creates new record instance. Assumes that repotype table - is on the stack, replaces it with newly created proxy. */ +/* Allocates and creates new record instance. Assumes that repotype table is on the stack, replaces it with newly created proxy. */ gpointer lua_gobject_record_new (lua_State *L, int count, gboolean alloc); -/* Creates Lua-side part of given record. Assumes that repotype table - is on the stack, replaces it with newly created proxy. If parent - not zero, it is stack index of record parent (i.e. record of which - the arg record is part of). */ +/* Creates Lua-side part of given record. Assumes that repotype table is on the stack, replaces it with newly created proxy. If parent not zero, it is stack index of record parent (i.e. record of which the arg record is part of). */ void lua_gobject_record_2lua (lua_State *L, gpointer addr, gboolean own, int parent); -/* Gets pointer to C-structure from given Lua-side object, or copies - record to specified address. Expects repo typetable of expected - argument pushed on the top of the stack, removes it. */ +/* Gets pointer to C-structure from given Lua-side object, or copies record to specified address. Expects repo typetable of expected argument pushed on the top of the stack, removes it. */ void lua_gobject_record_2c (lua_State *L, gint narg, gpointer target, gboolean by_value, gboolean own, gboolean optional, gboolean nothrow); -/* Creates Lua-side part (proxy) of given object. If the object is not - owned (own == FALSE), an ownership is automatically acquired. Returns - number of elements pushed to the stack, i.e. always 1. */ +/* Creates Lua-side part (proxy) of given object. If the object is not owned (own == FALSE), an ownership is automatically acquired. Returns number of elements pushed to the stack, i.e. always 1. */ int lua_gobject_object_2lua (lua_State *L, gpointer obj, gboolean own, gboolean no_sink); -/* Gets pointer to C-side object represented by given Lua proxy. If - gtype is not G_TYPE_INVALID, the real type is checked to conform to - requested type. */ +/* Gets pointer to C-side object represented by given Lua proxy. If gtype is not G_TYPE_INVALID, the real type is checked to conform to requested type. */ gpointer lua_gobject_object_2c (lua_State *L, int narg, GType gtype, gboolean optional, gboolean nothrow, gboolean transfer); #if !GLIB_CHECK_VERSION(2, 30, 0) -/* Workaround for broken g_struct_info_get_size() for GValue, see - https://bugzilla.gnome.org/show_bug.cgi?id=657040 */ +/* Workaround for broken g_struct_info_get_size() for GValue, see https://bugzilla.gnome.org/show_bug.cgi?id=657040 */ gsize lua_gobject_struct_info_get_size (GIStructInfo *info); #define g_struct_info_get_size lua_gobject_struct_info_get_size int lua_gobject_field_info_get_offset (GIFieldInfo *info); #define g_field_info_get_offset lua_gobject_field_info_get_offset #endif -/* Workaround method for broken g_object_info_get_*_function_pointer() - in GI 1.32.0. (see https://bugzilla.gnome.org/show_bug.cgi?id=673282) */ +/* Workaround method for broken g_object_info_get_*_function_pointer() in GI 1.32.0. (see https://bugzilla.gnome.org/show_bug.cgi?id=673282) */ gpointer lua_gobject_object_get_function_ptr (GIObjectInfo *info, - const gchar *(*getter)(GIObjectInfo *)); + const gchar *(*getter)(GIObjectInfo *)); GIRepository *lua_gobject_gi_get_repository (void); diff --git a/LuaGObject/marshal.c b/LuaGObject/marshal.c index e6f4aad4..e6eb194c 100644 --- a/LuaGObject/marshal.c +++ b/LuaGObject/marshal.c @@ -1,12 +1,7 @@ -/* - * Dynamic Lua binding to GObject using dynamic gobject-introspection. - * - * Copyright (c) 2010-2013 Pavel Holejsovsky - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - * Implements marshalling, i.e. transferring values between Lua and GLib/C. - */ +/* Dynamic Lua binding to GObject using dynamic gobject-introspection. +Copyright(c) 2010-2013 Pavel Holejsovsky +Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php +Implements marshalling, i.e. transferring values between Lua and GLib/C. */ #include #include @@ -19,1943 +14,1747 @@ #define lua_gobject_memdup g_memdup #endif -/* Checks whether given argument contains number which fits given - constraints. If yes, returns it, otherwise throws Lua error. */ +/* Checks whether given argument contains number which fits given constraints. If yes, returns it, otherwise throws Lua error. */ #if LUA_VERSION_NUM < 503 static lua_Number -check_integer (lua_State *L, int narg, lua_Number val_min, lua_Number val_max) +check_integer(lua_State *L, int narg, lua_Number val_min, lua_Number val_max) { - lua_Number val = luaL_checknumber (L, narg); - if (val < val_min || val > val_max) - { - lua_pushfstring (L, "%f is out of <%f, %f>", val, val_min, val_max); - luaL_argerror (L, narg, lua_tostring (L, -1)); - } - return val; + lua_Number val = luaL_checknumber(L, narg); + if (val < val_min || val > val_max) { + lua_pushfstring(L, "%f is out of <%f, %f>", val, val_min, val_max); + luaL_argerror(L, narg, lua_tostring(L, -1)); + } + return val; } #else static lua_Integer -check_integer (lua_State *L, int narg, lua_Integer val_min, lua_Integer val_max) +check_integer(lua_State *L, int narg, lua_Integer val_min, lua_Integer val_max) { - lua_Integer val = luaL_checkint (L, narg); - if (val < val_min || val > val_max) - { - lua_pushfstring (L, "%I is out of <%I, %I>", val, val_min, val_max); - luaL_argerror (L, narg, lua_tostring (L, -1)); - } - return val; + lua_Integer val = luaL_checkint(L, narg); + if (val < val_min || val > val_max) { + lua_pushfstring(L, "%I is out of <%I, %I>", val, val_min, val_max); + luaL_argerror(L, narg, lua_tostring(L, -1)); + } + return val; } #endif typedef union { - GIArgument arg; - ffi_arg u; - ffi_sarg s; + GIArgument arg; + ffi_arg u; + ffi_sarg s; } ReturnUnion; -/* Marshals integral types to C. If requested, makes sure that the - value is actually marshalled into val->v_pointer no matter what the - input type is. */ +/* Marshals integral types to C. If requested, makes sure that the value is actually marshalled into val->v_pointer no matter what the input type is. */ static void -marshal_2c_int (lua_State *L, GITypeTag tag, GIArgument *val, int narg, - gboolean optional, int parent) +marshal_2c_int(lua_State *L, GITypeTag tag, GIArgument *val, int narg, + gboolean optional, int parent) { - (void) optional; - switch (tag) - { + (void) optional; + switch (tag) + { #define HANDLE_INT(nameup, namelow, ptrconv, pct, val_min, val_max, ut) \ - case GI_TYPE_TAG_ ## nameup: \ - val->v_ ## namelow = check_integer (L, narg, val_min, val_max); \ - if (parent == LUA_GOBJECT_PARENT_FORCE_POINTER) \ - val->v_pointer = \ - G ## ptrconv ## _TO_POINTER ((pct) val->v_ ## namelow); \ - else if (sizeof (g ## namelow) <= sizeof (long) \ - && parent == LUA_GOBJECT_PARENT_IS_RETVAL) \ - { \ - ReturnUnion *ru = (ReturnUnion *) val; \ - ru->ut = ru->arg.v_ ## namelow; \ - } \ - break - -#define HANDLE_INT_NOPTR(nameup, namelow, val_min, val_max, ut) \ - case GI_TYPE_TAG_ ## nameup: \ - val->v_ ## namelow = check_integer (L, narg, val_min, val_max); \ - g_assert (parent != LUA_GOBJECT_PARENT_FORCE_POINTER); \ - if (sizeof (g ## namelow) <= sizeof (long) \ - && parent == LUA_GOBJECT_PARENT_IS_RETVAL) \ - { \ - ReturnUnion *ru = (ReturnUnion *) val; \ - ru->ut = ru->arg.v_ ## namelow; \ - } \ - break - - HANDLE_INT(INT8, int8, INT, gint, G_MININT8, G_MAXINT8, s); - HANDLE_INT(UINT8, uint8, UINT, guint, 0, G_MAXUINT8, u); - HANDLE_INT(INT16, int16, INT, gint, G_MININT16, G_MAXINT16, s); - HANDLE_INT(UINT16, uint16, UINT, guint, 0, G_MAXUINT16, u); - HANDLE_INT(INT32, int32, INT, gint, G_MININT32, G_MAXINT32, s); - HANDLE_INT(UINT32, uint32, UINT, guint, 0, G_MAXUINT32, u); - HANDLE_INT(UNICHAR, uint32, UINT, guint, 0, G_MAXUINT32, u); + case GI_TYPE_TAG_ ## nameup: \ + val->v_ ## namelow = check_integer(L, narg, val_min, val_max); \ + if (parent == LUA_GOBJECT_PARENT_FORCE_POINTER) \ + val->v_pointer = \ + G ## ptrconv ## _TO_POINTER((pct) val->v_ ## namelow); \ + else if (sizeof(g ## namelow) <= sizeof(long) \ + && parent == LUA_GOBJECT_PARENT_IS_RETVAL) { \ + ReturnUnion *ru = (ReturnUnion *) val; \ + ru->ut = ru->arg.v_ ## namelow; \ + } \ + break + +#define HANDLE_INT_NOPTR(nameup, namelow, val_min, val_max, ut) \ + case GI_TYPE_TAG_ ## nameup: \ + val->v_ ## namelow = check_integer(L, narg, val_min, val_max); \ + g_assert(parent != LUA_GOBJECT_PARENT_FORCE_POINTER); \ + if (sizeof(g ## namelow) <= sizeof(long) \ + && parent == LUA_GOBJECT_PARENT_IS_RETVAL) { \ + ReturnUnion *ru = (ReturnUnion *) val; \ + ru->ut = ru->arg.v_ ## namelow; \ + } \ + break + + HANDLE_INT(INT8, int8, INT, gint, G_MININT8, G_MAXINT8, s); + HANDLE_INT(UINT8, uint8, UINT, guint, 0, G_MAXUINT8, u); + HANDLE_INT(INT16, int16, INT, gint, G_MININT16, G_MAXINT16, s); + HANDLE_INT(UINT16, uint16, UINT, guint, 0, G_MAXUINT16, u); + HANDLE_INT(INT32, int32, INT, gint, G_MININT32, G_MAXINT32, s); + HANDLE_INT(UINT32, uint32, UINT, guint, 0, G_MAXUINT32, u); + HANDLE_INT(UNICHAR, uint32, UINT, guint, 0, G_MAXUINT32, u); #if LUA_VERSION_NUM >= 503 - HANDLE_INT_NOPTR(INT64, int64, LUA_MININTEGER, LUA_MAXINTEGER, s); - HANDLE_INT_NOPTR(UINT64, uint64, 0, LUA_MAXINTEGER, u); + HANDLE_INT_NOPTR(INT64, int64, LUA_MININTEGER, LUA_MAXINTEGER, s); + HANDLE_INT_NOPTR(UINT64, uint64, 0, LUA_MAXINTEGER, u); #else - HANDLE_INT_NOPTR(INT64, int64, ((lua_Number) -0x7f00000000000000LL) - 1, - 0x7fffffffffffffffLL, s); - HANDLE_INT_NOPTR(UINT64, uint64, 0, 0xffffffffffffffffULL, u); + HANDLE_INT_NOPTR(INT64, int64,((lua_Number) -0x7f00000000000000LL) - 1, + 0x7fffffffffffffffLL, s); + HANDLE_INT_NOPTR(UINT64, uint64, 0, 0xffffffffffffffffULL, u); #endif #undef HANDLE_INT #undef HANDLE_INT_NOPTR - case GI_TYPE_TAG_GTYPE: - { + case GI_TYPE_TAG_GTYPE: + { #if GLIB_SIZEOF_SIZE_T == 4 - val->v_uint32 = + val->v_uint32 = #else - val->v_uint64 = + val->v_uint64 = #endif - lua_gobject_type_get_gtype (L, narg); - break; - } + lua_gobject_type_get_gtype(L, narg); + break; + } - default: - g_assert_not_reached (); - } + default: + g_assert_not_reached(); + } } /* Marshals integral types from C to Lua. */ static void -marshal_2lua_int (lua_State *L, GITypeTag tag, GIArgument *val, - int parent) +marshal_2lua_int(lua_State *L, GITypeTag tag, GIArgument *val, + int parent) { - switch (tag) - { -#define HANDLE_INT(nameupper, namelower, ptrconv, ut) \ - case GI_TYPE_TAG_ ## nameupper: \ - if (sizeof (g ## namelower) <= sizeof (long) \ - && parent == LUA_GOBJECT_PARENT_IS_RETVAL) \ - { \ - ReturnUnion *ru = (ReturnUnion *) val; \ - ru->arg.v_ ## namelower = (g ## namelower) ru->ut; \ - } \ - lua_pushinteger (L, parent == LUA_GOBJECT_PARENT_FORCE_POINTER \ - ? GPOINTER_TO_ ## ptrconv (val->v_pointer) \ - : val->v_ ## namelower); \ - break; + switch (tag) { +#define HANDLE_INT(nameupper, namelower, ptrconv, ut) \ + case GI_TYPE_TAG_ ## nameupper: \ + if (sizeof(g ## namelower) <= sizeof(long) \ + && parent == LUA_GOBJECT_PARENT_IS_RETVAL) { \ + ReturnUnion *ru = (ReturnUnion *) val; \ + ru->arg.v_ ## namelower = (g ## namelower) ru->ut; \ + } \ + lua_pushinteger(L, parent == LUA_GOBJECT_PARENT_FORCE_POINTER \ + ? GPOINTER_TO_ ## ptrconv(val->v_pointer) \ + : val->v_ ## namelower); \ + break; - HANDLE_INT(INT8, int8, INT, s); - HANDLE_INT(UINT8, uint8, UINT, u); - HANDLE_INT(INT16, int16, INT, s); - HANDLE_INT(UINT16, uint16, UINT, u); - HANDLE_INT(INT32, int32, INT, s); - HANDLE_INT(UINT32, uint32, UINT, u); - HANDLE_INT(UNICHAR, uint32, UINT, u); - HANDLE_INT(INT64, int64, INT, s); - HANDLE_INT(UINT64, uint64, UINT, u); + HANDLE_INT(INT8, int8, INT, s); + HANDLE_INT(UINT8, uint8, UINT, u); + HANDLE_INT(INT16, int16, INT, s); + HANDLE_INT(UINT16, uint16, UINT, u); + HANDLE_INT(INT32, int32, INT, s); + HANDLE_INT(UINT32, uint32, UINT, u); + HANDLE_INT(UNICHAR, uint32, UINT, u); + HANDLE_INT(INT64, int64, INT, s); + HANDLE_INT(UINT64, uint64, UINT, u); #undef HANDLE_INT - case GI_TYPE_TAG_GTYPE: - lua_pushstring (L, g_type_name ( + case GI_TYPE_TAG_GTYPE: + lua_pushstring(L, g_type_name( #if GLIB_SIZEOF_SIZE_T == 4 - val->v_uint32 + val->v_uint32 #else - val->v_uint64 + val->v_uint64 #endif - )); - break; + )); + break; - default: - g_assert_not_reached (); - } + default: + g_assert_not_reached(); + } } /* Gets or sets the length of the array. */ static void -array_get_or_set_length (GITypeInfo *ti, gssize *get_length, gssize set_length, - GIBaseInfo *ci, void *args) +array_get_or_set_length(GITypeInfo *ti, gssize *get_length, gssize set_length, + GIBaseInfo *ci, void *args) { - guint param; - - if (gi_type_info_get_array_length_index (ti, ¶m) && ci != NULL) - { - GIArgument *val; - GITypeInfo *eti; - - if (GI_IS_FUNCTION_INFO (ci) || GI_IS_CALLBACK_INFO (ci)) - { - GIArgInfo *ai; - - if (param >= gi_callable_info_get_n_args (GI_CALLABLE_INFO (ci))) - return; - ai = gi_callable_info_get_arg (GI_CALLABLE_INFO (ci), param); - eti = gi_arg_info_get_type_info (ai); - if (gi_arg_info_get_direction (ai) == GI_DIRECTION_IN) - /* For input parameters, value is directly pointed to by args - table element. */ - val = (GIArgument *) ((void **) args)[param]; - else - /* For output arguments, args table element points to pointer - to value. */ - val = *(GIArgument **) ((void **) args)[param]; - gi_base_info_unref (ai); - } - else if (GI_IS_STRUCT_INFO (ci) || GI_IS_UNION_INFO (ci)) - { - GIFieldInfo *fi; - - if (param >= gi_struct_info_get_n_fields (GI_STRUCT_INFO (ci))) - return; - fi = gi_struct_info_get_field (GI_STRUCT_INFO (ci), param); - eti = gi_field_info_get_type_info (fi); - val = (GIArgument *) ((char *) args + gi_field_info_get_offset (fi)); - gi_base_info_unref (fi); - } - else - return; - - switch (gi_type_info_get_tag (eti)) - { -#define HANDLE_ELT(tag, field) \ - case GI_TYPE_TAG_ ## tag: \ - if (get_length != NULL) \ - *get_length = val->v_ ## field; \ - else \ - val->v_ ## field = set_length; \ - break - - HANDLE_ELT(INT8, int8); - HANDLE_ELT(UINT8, uint8); - HANDLE_ELT(INT16, int16); - HANDLE_ELT(UINT16, uint16); - HANDLE_ELT(INT32, int32); - HANDLE_ELT(UINT32, uint32); - HANDLE_ELT(INT64, int64); - HANDLE_ELT(UINT64, uint64); + guint param; + + if (gi_type_info_get_array_length_index(ti, ¶m) && ci != NULL) { + GIArgument *val; + GITypeInfo *eti; + + if (GI_IS_FUNCTION_INFO(ci) || GI_IS_CALLBACK_INFO(ci)) { + GIArgInfo *ai; + + if (param >= gi_callable_info_get_n_args(GI_CALLABLE_INFO(ci))) + return; + ai = gi_callable_info_get_arg(GI_CALLABLE_INFO(ci), param); + eti = gi_arg_info_get_type_info(ai); + if (gi_arg_info_get_direction(ai) == GI_DIRECTION_IN) + /* For input parameters, value is directly pointed to by args table element. */ + val = (GIArgument *)((void **) args)[param]; + else + /* For output arguments, args table element points to pointer to value. */ + val = *(GIArgument **)((void **) args)[param]; + gi_base_info_unref(ai); + } + else if (GI_IS_STRUCT_INFO(ci) || GI_IS_UNION_INFO(ci)) { + GIFieldInfo *fi; + + if (param >= gi_struct_info_get_n_fields(GI_STRUCT_INFO(ci))) + return; + fi = gi_struct_info_get_field(GI_STRUCT_INFO(ci), param); + eti = gi_field_info_get_type_info(fi); + val = (GIArgument *)((char *) args + gi_field_info_get_offset(fi)); + gi_base_info_unref(fi); + } + else + return; + + switch (gi_type_info_get_tag(eti)) { +#define HANDLE_ELT(tag, field) \ + case GI_TYPE_TAG_ ## tag: \ + if (get_length != NULL) \ + *get_length = val->v_ ## field; \ + else \ + val->v_ ## field = set_length; \ + break + + HANDLE_ELT(INT8, int8); + HANDLE_ELT(UINT8, uint8); + HANDLE_ELT(INT16, int16); + HANDLE_ELT(UINT16, uint16); + HANDLE_ELT(INT32, int32); + HANDLE_ELT(UINT32, uint32); + HANDLE_ELT(INT64, int64); + HANDLE_ELT(UINT64, uint64); #undef HANDLE_ELT - default: - g_assert_not_reached (); - } + default: + g_assert_not_reached(); + } - gi_base_info_unref (eti); - } + gi_base_info_unref(eti); + } } -/* Retrieves pointer to GIArgument in given array, given that array - contains elements of type ti. */ +/* Retrieves pointer to GIArgument in given array, given that array contains elements of type ti. */ static gssize -array_get_elt_size (GITypeInfo *ti, gboolean force_ptr) +array_get_elt_size(GITypeInfo *ti, gboolean force_ptr) { - gssize size = sizeof (gpointer); - if (!gi_type_info_is_pointer (ti) && !force_ptr) - { - switch (gi_type_info_get_tag (ti)) - { -#define HANDLE_ELT(nameupper, nametype) \ - case GI_TYPE_TAG_ ## nameupper: \ - return sizeof (nametype); - - HANDLE_ELT(BOOLEAN, gboolean); - HANDLE_ELT(INT8, gint8); - HANDLE_ELT(UINT8, guint8); - HANDLE_ELT(INT16, gint16); - HANDLE_ELT(UINT16, guint16); - HANDLE_ELT(INT32, gint32); - HANDLE_ELT(UINT32, guint32); - HANDLE_ELT(UNICHAR, guint32); - HANDLE_ELT(INT64, gint64); - HANDLE_ELT(UINT64, guint64); - HANDLE_ELT(FLOAT, gfloat); - HANDLE_ELT(DOUBLE, gdouble); - HANDLE_ELT(GTYPE, GType); + gssize size = sizeof(gpointer); + if (!gi_type_info_is_pointer(ti) && !force_ptr) { + switch (gi_type_info_get_tag(ti)) { +#define HANDLE_ELT(nameupper, nametype) \ + case GI_TYPE_TAG_ ## nameupper: \ + return sizeof(nametype); + + HANDLE_ELT(BOOLEAN, gboolean); + HANDLE_ELT(INT8, gint8); + HANDLE_ELT(UINT8, guint8); + HANDLE_ELT(INT16, gint16); + HANDLE_ELT(UINT16, guint16); + HANDLE_ELT(INT32, gint32); + HANDLE_ELT(UINT32, guint32); + HANDLE_ELT(UNICHAR, guint32); + HANDLE_ELT(INT64, gint64); + HANDLE_ELT(UINT64, guint64); + HANDLE_ELT(FLOAT, gfloat); + HANDLE_ELT(DOUBLE, gdouble); + HANDLE_ELT(GTYPE, GType); #undef HANDLE_ELT - case GI_TYPE_TAG_INTERFACE: - { - GIBaseInfo *info = gi_type_info_get_interface (ti); - if (GI_IS_STRUCT_INFO (info)) - size = gi_struct_info_get_size (GI_STRUCT_INFO (info)); - else if (GI_IS_UNION_INFO (info)) - size = gi_union_info_get_size (GI_UNION_INFO (info)); - gi_base_info_unref (info); - break; - } + case GI_TYPE_TAG_INTERFACE: + { + GIBaseInfo *info = gi_type_info_get_interface(ti); + if (GI_IS_STRUCT_INFO(info)) + size = gi_struct_info_get_size(GI_STRUCT_INFO(info)); + else if (GI_IS_UNION_INFO(info)) + size = gi_union_info_get_size(GI_UNION_INFO(info)); + gi_base_info_unref(info); + break; + } - default: - break; + default: + break; + } } - } - return size; + return size; } static void -array_detach (GArray *array) +array_detach(GArray *array) { - g_array_free (array, FALSE); + g_array_free(array, FALSE); } static void -ptr_array_detach (GPtrArray *array) +ptr_array_detach(GPtrArray *array) { - g_ptr_array_free (array, FALSE); + g_ptr_array_free(array, FALSE); } static void -byte_array_detach (GByteArray *array) +byte_array_detach(GByteArray *array) { - g_byte_array_free (array, FALSE); + g_byte_array_free(array, FALSE); } /* Marshalls array from Lua to C. Returns number of temporary elements - pushed to the stack. */ + pushed to the stack. */ static int -marshal_2c_array (lua_State *L, GITypeInfo *ti, GIArrayType atype, - gpointer *out_array, gssize *out_size, int narg, - gboolean optional, GITransfer transfer) +marshal_2c_array(lua_State *L, GITypeInfo *ti, GIArrayType atype, + gpointer *out_array, gssize *out_size, int narg, + gboolean optional, GITransfer transfer) { - GITypeInfo* eti; - gssize objlen, esize; - gint index, vals = 0, to_pop, eti_guard; - GITransfer exfer = (transfer == GI_TRANSFER_EVERYTHING - ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING); - gboolean zero_terminated; - GArray *array = NULL; - int parent = 0; - - /* Represent nil as NULL array. */ - if (optional && lua_isnoneornil (L, narg)) - { - *out_size = 0; - *out_array = NULL; - } - else - { - /* Get element type info, create guard for it. */ - eti = gi_type_info_get_param_type (ti, 0); - lua_gobject_gi_info_new (L, GI_BASE_INFO (eti)); - eti_guard = lua_gettop (L); - esize = array_get_elt_size (eti, atype == GI_ARRAY_TYPE_PTR_ARRAY); - - /* Check the type. If this is C-array of byte-sized elements, we - can try special-case and accept strings or buffers. */ - *out_array = NULL; - if (lua_type (L, narg) != LUA_TTABLE && esize == 1 - && atype == GI_ARRAY_TYPE_C) - { - size_t size = 0; - *out_array = lua_gobject_udata_test (L, narg, LUA_GOBJECT_BYTES_BUFFER); - if (*out_array) - size = lua_objlen (L, narg); - else - *out_array = (gpointer *) lua_tolstring (L, narg, &size); + GITypeInfo* eti; + gssize objlen, esize; + gint index, vals = 0, to_pop, eti_guard; + GITransfer exfer = (transfer == GI_TRANSFER_EVERYTHING + ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING); + gboolean zero_terminated; + GArray *array = NULL; + int parent = 0; + + /* Represent nil as NULL array. */ + if (optional && lua_isnoneornil(L, narg)) { + *out_size = 0; + *out_array = NULL; + } else { + /* Get element type info, create guard for it. */ + eti = gi_type_info_get_param_type(ti, 0); + lua_gobject_gi_info_new(L, GI_BASE_INFO(eti)); + eti_guard = lua_gettop(L); + esize = array_get_elt_size(eti, atype == GI_ARRAY_TYPE_PTR_ARRAY); + + /* Check the type. If this is C-array of byte-sized elements, we can try special-case and accept strings or buffers. */ + *out_array = NULL; + if (lua_type(L, narg) != LUA_TTABLE && esize == 1 + && atype == GI_ARRAY_TYPE_C) { + size_t size = 0; + *out_array = lua_gobject_udata_test(L, narg, + LUA_GOBJECT_BYTES_BUFFER); + if (*out_array) + size = lua_objlen(L, narg); + else + *out_array = (gpointer *) lua_tolstring(L, narg, &size); + + if (transfer != GI_TRANSFER_NOTHING) + *out_array = lua_gobject_memdup(*out_array, size); + + *out_size = size; + } - if (transfer != GI_TRANSFER_NOTHING) - *out_array = lua_gobject_memdup (*out_array, size); + if (!*out_array) { + /* Otherwise, we allow only tables. */ + luaL_checktype(L, narg, LUA_TTABLE); + + /* Find out how long array should we allocate. */ + zero_terminated = gi_type_info_is_zero_terminated(ti); + objlen = lua_objlen(L, narg); + if (atype != GI_ARRAY_TYPE_C + || !gi_type_info_get_array_fixed_size(ti,(gsize *)out_size)) + *out_size = objlen; + else if (*out_size < objlen) + objlen = *out_size; + + /* Allocate the array and wrap it into the userdata guard, if needed. */ + if (*out_size > 0 || zero_terminated) { + guint total_size = *out_size +(zero_terminated ? 1 : 0); + switch (atype) { + case GI_ARRAY_TYPE_C: + case GI_ARRAY_TYPE_ARRAY: + array = g_array_sized_new(zero_terminated, TRUE, esize, + *out_size); + g_array_set_size(array, *out_size); + *lua_gobject_guard_create(L,(GDestroyNotify) + (transfer == GI_TRANSFER_EVERYTHING + ? array_detach : g_array_unref)) = array; + break; + + case GI_ARRAY_TYPE_PTR_ARRAY: + parent = LUA_GOBJECT_PARENT_FORCE_POINTER; + array = (GArray *) g_ptr_array_sized_new(total_size); + g_ptr_array_set_size((GPtrArray *) array, total_size); + *lua_gobject_guard_create(L,(GDestroyNotify) + (transfer == GI_TRANSFER_EVERYTHING + ? ptr_array_detach + : g_ptr_array_unref)) = array; + break; + + case GI_ARRAY_TYPE_BYTE_ARRAY: + array = (GArray *) g_byte_array_sized_new(total_size); + g_byte_array_set_size((GByteArray *) array, *out_size); + *lua_gobject_guard_create(L,(GDestroyNotify) + (transfer == GI_TRANSFER_EVERYTHING + ? byte_array_detach + : g_byte_array_unref)) = array; + break; + } + vals = 1; + } - *out_size = size; - } + /* Iterate through Lua array and fill GArray accordingly. */ + for (index = 0; index < objlen; index++) { + lua_pushinteger(L, index + 1); + lua_gettable(L, narg); - if (!*out_array) - { - /* Otherwise, we allow only tables. */ - luaL_checktype (L, narg, LUA_TTABLE); - - /* Find out how long array should we allocate. */ - zero_terminated = gi_type_info_is_zero_terminated (ti); - objlen = lua_objlen (L, narg); - if (atype != GI_ARRAY_TYPE_C || !gi_type_info_get_array_fixed_size (ti, (gsize *)out_size)) - *out_size = objlen; - else if (*out_size < objlen) - objlen = *out_size; - - /* Allocate the array and wrap it into the userdata guard, - if needed. */ - if (*out_size > 0 || zero_terminated) - { - guint total_size = *out_size + (zero_terminated ? 1 : 0); - switch (atype) - { - case GI_ARRAY_TYPE_C: - case GI_ARRAY_TYPE_ARRAY: - array = g_array_sized_new (zero_terminated, TRUE, esize, - *out_size); - g_array_set_size (array, *out_size); - *lua_gobject_guard_create (L, (GDestroyNotify) - (transfer == GI_TRANSFER_EVERYTHING - ? array_detach : g_array_unref)) = array; - break; - - case GI_ARRAY_TYPE_PTR_ARRAY: - parent = LUA_GOBJECT_PARENT_FORCE_POINTER; - array = (GArray *) g_ptr_array_sized_new (total_size); - g_ptr_array_set_size ((GPtrArray *) array, total_size); - *lua_gobject_guard_create (L, (GDestroyNotify) - (transfer == GI_TRANSFER_EVERYTHING - ? ptr_array_detach : - g_ptr_array_unref)) = array; - break; - - case GI_ARRAY_TYPE_BYTE_ARRAY: - array = (GArray *) g_byte_array_sized_new (total_size); - g_byte_array_set_size ((GByteArray *) array, *out_size); - *lua_gobject_guard_create (L, (GDestroyNotify) - (transfer == GI_TRANSFER_EVERYTHING - ? byte_array_detach : - g_byte_array_unref)) = array; - break; + /* Marshal element retrieved from the table into target array. */ + to_pop = lua_gobject_marshal_2c(L, eti, NULL, exfer, + array->data + index * esize, -1, + parent, NULL, NULL); + + /* Remove temporary element from the stack. */ + lua_remove(L, - to_pop - 1); + + /* Remember that some more temp elements could be pushed. */ + vals += to_pop; + } + + /* Return either GArray or direct pointer to the data, according to the array type. */ + if (array == NULL) + *out_array = NULL; + else + switch (atype) { + case GI_ARRAY_TYPE_C: + *out_array = (void *) array->data; + break; + + case GI_ARRAY_TYPE_ARRAY: + case GI_ARRAY_TYPE_PTR_ARRAY: + case GI_ARRAY_TYPE_BYTE_ARRAY: + *out_array = (void *) array; + break; + } } - vals = 1; - } - - /* Iterate through Lua array and fill GArray accordingly. */ - for (index = 0; index < objlen; index++) - { - lua_pushinteger (L, index + 1); - lua_gettable (L, narg); - - /* Marshal element retrieved from the table into target - array. */ - to_pop = lua_gobject_marshal_2c (L, eti, NULL, exfer, - array->data + index * esize, -1, - parent, NULL, NULL); - - /* Remove temporary element from the stack. */ - lua_remove (L, - to_pop - 1); - - /* Remember that some more temp elements could be - pushed. */ - vals += to_pop; - } - - /* Return either GArray or direct pointer to the data, - according to the array type. */ - if (array == NULL) - *out_array = NULL; - else - switch (atype) - { - case GI_ARRAY_TYPE_C: - *out_array = (void *) array->data; - break; - case GI_ARRAY_TYPE_ARRAY: - case GI_ARRAY_TYPE_PTR_ARRAY: - case GI_ARRAY_TYPE_BYTE_ARRAY: - *out_array = (void *) array; - break; - } + lua_remove(L, eti_guard); } - lua_remove (L, eti_guard); - } - - return vals; + return vals; } static void -marshal_2lua_array (lua_State *L, GITypeInfo *ti, GIDirection dir, - GIArrayType atype, GITransfer transfer, - gpointer array, gssize size, int parent) +marshal_2lua_array(lua_State *L, GITypeInfo *ti, GIDirection dir, + GIArrayType atype, GITransfer transfer, + gpointer array, gssize size, int parent) { - GITypeInfo *eti; - gssize len = 0, esize; - gint index, eti_guard; - char *data = NULL; - - /* Avoid propagating return value marshaling flag to array elements. */ - if (parent == LUA_GOBJECT_PARENT_IS_RETVAL) - parent = 0; - - /* First of all, find out the length of the array. */ - if (atype == GI_ARRAY_TYPE_ARRAY) - { - if (array) - { - len = ((GArray *) array)->len; - data = ((GArray *) array)->data; - } - } - else if (atype == GI_ARRAY_TYPE_BYTE_ARRAY) - { - if (array) - { - len = ((GByteArray *) array)->len; - data = (char *) ((GByteArray *) array)->data; - } - } - else if (atype == GI_ARRAY_TYPE_PTR_ARRAY) - { - if (array) - { - len = ((GPtrArray *) array)->len; - data = (char *) ((GPtrArray *) array)->pdata; - parent = LUA_GOBJECT_PARENT_FORCE_POINTER; - } - } - else - { - data = array; - if (gi_type_info_is_zero_terminated (ti)) - len = -1; - else - { - if (!gi_type_info_get_array_fixed_size (ti, (gsize *)&len)) - /* Length of the array is dynamic, get it from other - argument. If the size isn't known ahead of time (it's -1), - and it isn't zero-terminated, assume 1. */ - len = size < 0 ? 1 : size; - } - } - - /* Get array element type info, wrap it in the guard so that we - don't leak it. */ - eti = gi_type_info_get_param_type (ti, 0); - lua_gobject_gi_info_new (L, GI_BASE_INFO (eti)); - eti_guard = lua_gettop (L); - esize = array_get_elt_size (eti, atype == GI_ARRAY_TYPE_PTR_ARRAY); - - /* Note that we ignore is_pointer check for uint8 type. Although it - is not exactly correct, we probably would not handle uint8* - correctly anyway, this is strange type to use, and moreover this - is workaround for g-ir-scanner bug which might mark elements of - uint8 arrays as gconstpointer, thus setting is_pointer=true on - it. See https://github.com/lgi-devs/lgi/issues/57 */ - if (gi_type_info_get_tag (eti) == GI_TYPE_TAG_UINT8) - { - /* UINT8 arrays are marshalled as Lua strings. */ - if (len < 0) - len = data ? strlen(data) : 0; - if (data != NULL || len != 0) - lua_pushlstring (L, data, len); - else - lua_pushnil (L); - } - else - { - if (array == NULL) - { - /* NULL array is represented by empty table for C arrays, nil - for other types. */ - if (atype == GI_ARRAY_TYPE_C) - lua_newtable (L); - else - lua_pushnil (L); - - lua_remove (L, eti_guard); - return; + GITypeInfo *eti; + gssize len = 0, esize; + gint index, eti_guard; + char *data = NULL; + + /* Avoid propagating return value marshaling flag to array elements. */ + if (parent == LUA_GOBJECT_PARENT_IS_RETVAL) + parent = 0; + + /* First of all, find out the length of the array. */ + if (atype == GI_ARRAY_TYPE_ARRAY) { + if (array) { + len = ((GArray *) array)->len; + data = ((GArray *) array)->data; + } + } else if (atype == GI_ARRAY_TYPE_BYTE_ARRAY) { + if (array) { + len = ((GByteArray *) array)->len; + data = (char *)((GByteArray *) array)->data; + } + } else if (atype == GI_ARRAY_TYPE_PTR_ARRAY) { + if (array) { + len = ((GPtrArray *) array)->len; + data = (char *)((GPtrArray *) array)->pdata; + parent = LUA_GOBJECT_PARENT_FORCE_POINTER; + } + } else { + data = array; + if (gi_type_info_is_zero_terminated(ti)) + len = -1; + else { + if (!gi_type_info_get_array_fixed_size(ti,(gsize *)&len)) + /* Length of the array is dynamic, get it from other argument. If the size isn't known ahead of time(it's -1), and it isn't zero-terminated, assume 1. */ + len = size < 0 ? 1 : size; + } } - /* Create Lua table which will hold the array. */ - lua_createtable (L, len > 0 ? len : 0, 0); + /* Get array element type info, wrap it in the guard so that we don't leak it. */ + eti = gi_type_info_get_param_type(ti, 0); + lua_gobject_gi_info_new(L, GI_BASE_INFO(eti)); + eti_guard = lua_gettop(L); + esize = array_get_elt_size(eti, atype == GI_ARRAY_TYPE_PTR_ARRAY); + + /* Note that we ignore is_pointer check for uint8 type. Although it is not exactly correct, we probably would not handle uint8* correctly anyway, this is strange type to use, and moreover this is workaround for g-ir-scanner bug which might mark elements of uint8 arrays as gconstpointer, thus setting is_pointer=true on it. See https://github.com/lgi-devs/lgi/issues/57 */ + if (gi_type_info_get_tag(eti) == GI_TYPE_TAG_UINT8) { + /* UINT8 arrays are marshalled as Lua strings. */ + if (len < 0) + len = data ? strlen(data) : 0; + if (data != NULL || len != 0) + lua_pushlstring(L, data, len); + else + lua_pushnil(L); + } else { + if (array == NULL) { + /* NULL array is represented by empty table for C arrays, nil for other types. */ + if (atype == GI_ARRAY_TYPE_C) + lua_newtable(L); + else + lua_pushnil(L); + + lua_remove(L, eti_guard); + return; + } - /* Iterate through array elements. */ - for (index = 0; len < 0 || index < len; index++) - { - /* Get value from specified index. */ - GIArgument *eval = (GIArgument *) (data + index * esize); - - /* If the array is zero-terminated, terminate now and don't - include NULL entry. */ - if (len < 0 && eval->v_pointer == NULL) - break; - - /* Store value into the table. */ - lua_gobject_marshal_2lua (L, eti, NULL, dir, - (transfer == GI_TRANSFER_EVERYTHING) ? - GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING, - eval, parent, NULL, NULL); - lua_rawseti (L, -2, index + 1); + /* Create Lua table which will hold the array. */ + lua_createtable(L, len > 0 ? len : 0, 0); + + /* Iterate through array elements. */ + for (index = 0; len < 0 || index < len; index++) { + /* Get value from specified index. */ + GIArgument *eval = (GIArgument *)(data + index * esize); + + /* If the array is zero-terminated, terminate now and don't include NULL entry. */ + if (len < 0 && eval->v_pointer == NULL) + break; + + /* Store value into the table. */ + lua_gobject_marshal_2lua(L, eti, NULL, dir, + (transfer == GI_TRANSFER_EVERYTHING) + ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING, + eval, parent, NULL, NULL); + lua_rawseti(L, -2, index + 1); + } + } + + /* If needed, free the original array. */ + if (transfer != GI_TRANSFER_NOTHING) { + if (atype == GI_ARRAY_TYPE_ARRAY) + g_array_free(array, TRUE); + else if (atype == GI_ARRAY_TYPE_BYTE_ARRAY) + g_byte_array_free(array, TRUE); + else if (atype == GI_ARRAY_TYPE_PTR_ARRAY) + g_ptr_array_free(array, TRUE); + else + g_free(array); } - } - - /* If needed, free the original array. */ - if (transfer != GI_TRANSFER_NOTHING) - { - if (atype == GI_ARRAY_TYPE_ARRAY) - g_array_free (array, TRUE); - else if (atype == GI_ARRAY_TYPE_BYTE_ARRAY) - g_byte_array_free (array, TRUE); - else if (atype == GI_ARRAY_TYPE_PTR_ARRAY) - g_ptr_array_free (array, TRUE); - else - g_free (array); - } - - lua_remove (L, eti_guard); + + lua_remove(L, eti_guard); } -/* Marshalls GSList or GList from Lua to C. Returns number of - temporary elements pushed to the stack. */ +/* Marshalls GSList or GList from Lua to C. Returns number of temporary elements pushed to the stack. */ static int -marshal_2c_list (lua_State *L, GITypeInfo *ti, GITypeTag list_tag, - gpointer *list, int narg, GITransfer transfer) +marshal_2c_list(lua_State *L, GITypeInfo *ti, GITypeTag list_tag, + gpointer *list, int narg, GITransfer transfer) { - GITypeInfo *eti; - GITransfer exfer = (transfer == GI_TRANSFER_EVERYTHING - ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING); - gint index, vals = 0, to_pop, eti_guard; - GSList **guard = NULL; - - /* Allow empty list to be expressed also as 'nil', because in C, - there is no difference between NULL and empty list. */ - if (lua_isnoneornil (L, narg)) - index = 0; - else - { - luaL_checktype (L, narg, LUA_TTABLE); - index = lua_objlen (L, narg); - } - - /* Get list element type info, create guard for it so that we don't - leak it. */ - eti = gi_type_info_get_param_type (ti, 0); - lua_gobject_gi_info_new (L, GI_BASE_INFO (eti)); - eti_guard = lua_gettop (L); - - /* Go from back and prepend to the list, which is cheaper than - appending. */ - guard = (GSList **) lua_gobject_guard_create (L, list_tag == GI_TYPE_TAG_GSLIST - ? (GDestroyNotify) g_slist_free - : (GDestroyNotify) g_list_free); - while (index > 0) - { - /* Retrieve index-th element from the source table and marshall - it as pointer to arg. */ - GIArgument eval; - lua_pushinteger (L, index--); - lua_gettable (L, narg); - to_pop = lua_gobject_marshal_2c (L, eti, NULL, exfer, &eval, -1, - LUA_GOBJECT_PARENT_FORCE_POINTER, NULL, NULL); - - /* Prepend new list element and reassign the guard. */ - if (list_tag == GI_TYPE_TAG_GSLIST) - *guard = g_slist_prepend (*guard, eval.v_pointer); - else - *guard = (GSList *) g_list_prepend ((GList *) *guard, eval.v_pointer); - - lua_remove (L, - to_pop - 1); - vals += to_pop; - } - - /* Marshalled value is kept inside the guard. */ - *list = *guard; - lua_remove (L, eti_guard); - return vals; + GITypeInfo *eti; + GITransfer exfer = (transfer == GI_TRANSFER_EVERYTHING + ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING); + gint index, vals = 0, to_pop, eti_guard; + GSList **guard = NULL; + + /* Allow empty list to be expressed also as 'nil', because in C, there is no difference between NULL and empty list. */ + if (lua_isnoneornil(L, narg)) + index = 0; + else { + luaL_checktype(L, narg, LUA_TTABLE); + index = lua_objlen(L, narg); + } + + /* Get list element type info, create guard for it so that we don't leak it. */ + eti = gi_type_info_get_param_type(ti, 0); + lua_gobject_gi_info_new(L, GI_BASE_INFO(eti)); + eti_guard = lua_gettop(L); + + /* Go from back and prepend to the list, which is cheaper than appending. */ + guard = (GSList **) lua_gobject_guard_create(L, + list_tag == GI_TYPE_TAG_GSLIST + ? (GDestroyNotify) g_slist_free + : (GDestroyNotify) g_list_free); + while (index > 0) { + /* Retrieve index-th element from the source table and marshall it as pointer to arg. */ + GIArgument eval; + lua_pushinteger(L, index--); + lua_gettable(L, narg); + to_pop = lua_gobject_marshal_2c(L, eti, NULL, exfer, &eval, -1, + LUA_GOBJECT_PARENT_FORCE_POINTER, NULL, NULL); + + /* Prepend new list element and reassign the guard. */ + if (list_tag == GI_TYPE_TAG_GSLIST) + *guard = g_slist_prepend(*guard, eval.v_pointer); + else + *guard = (GSList *) g_list_prepend((GList *) *guard, eval.v_pointer); + + lua_remove(L, - to_pop - 1); + vals += to_pop; + } + + /* Marshalled value is kept inside the guard. */ + *list = *guard; + lua_remove(L, eti_guard); + return vals; } static int -marshal_2lua_list (lua_State *L, GITypeInfo *ti, GIDirection dir, - GITypeTag list_tag, GITransfer xfer, gpointer list) +marshal_2lua_list(lua_State *L, GITypeInfo *ti, GIDirection dir, + GITypeTag list_tag, GITransfer xfer, gpointer list) { - GSList *i; - GITypeInfo *eti; - gint index, eti_guard; - - /* Get element type info, guard it so that we don't leak it. */ - eti = gi_type_info_get_param_type (ti, 0); - lua_gobject_gi_info_new (L, GI_BASE_INFO (eti)); - eti_guard = lua_gettop (L); - - /* Create table to which we will deserialize the list. */ - lua_newtable (L); - - /* Go through the list and push elements into the table. */ - for (i = list, index = 0; i != NULL; i = g_slist_next (i)) - { - /* Get access to list item. */ - GIArgument *eval = (GIArgument *) &i->data; - - /* Store it into the table. */ - lua_gobject_marshal_2lua (L, eti, NULL, dir, (xfer == GI_TRANSFER_EVERYTHING) ? - GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING, - eval, LUA_GOBJECT_PARENT_FORCE_POINTER, NULL, NULL); - lua_rawseti(L, -2, ++index); - } - - /* Free the list, if we got its ownership. */ - if (xfer != GI_TRANSFER_NOTHING) - { - if (list_tag == GI_TYPE_TAG_GSLIST) - g_slist_free (list); - else - g_list_free (list); - } - - lua_remove (L, eti_guard); - return 1; + GSList *i; + GITypeInfo *eti; + gint index, eti_guard; + + /* Get element type info, guard it so that we don't leak it. */ + eti = gi_type_info_get_param_type(ti, 0); + lua_gobject_gi_info_new(L, GI_BASE_INFO(eti)); + eti_guard = lua_gettop(L); + + /* Create table to which we will deserialize the list. */ + lua_newtable(L); + + /* Go through the list and push elements into the table. */ + for (i = list, index = 0; i != NULL; i = g_slist_next(i)) { + /* Get access to list item. */ + GIArgument *eval = (GIArgument *) &i->data; + + /* Store it into the table. */ + lua_gobject_marshal_2lua(L, eti, NULL, dir, + (xfer == GI_TRANSFER_EVERYTHING) + ? GI_TRANSFER_EVERYTHING + : GI_TRANSFER_NOTHING, + eval, LUA_GOBJECT_PARENT_FORCE_POINTER, NULL, NULL); + lua_rawseti(L, -2, ++index); + } + + /* Free the list, if we got its ownership. */ + if (xfer != GI_TRANSFER_NOTHING) { + if (list_tag == GI_TYPE_TAG_GSLIST) + g_slist_free(list); + else + g_list_free(list); + } + + lua_remove(L, eti_guard); + return 1; } -/* Marshalls hashtable from Lua to C. Returns number of temporary - elements pushed to the stack. */ +/* Marshalls hashtable from Lua to C. Returns number of temporary elements pushed to the stack. */ static int -marshal_2c_hash (lua_State *L, GITypeInfo *ti, GHashTable **table, int narg, - gboolean optional, GITransfer transfer) +marshal_2c_hash(lua_State *L, GITypeInfo *ti, GHashTable **table, int narg, + gboolean optional, GITransfer transfer) { - GITypeInfo *eti[2]; - GITransfer exfer = (transfer == GI_TRANSFER_EVERYTHING - ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING); - gint i, vals = 0, guard; - GHashTable **guarded_table; - GHashFunc hash_func; - GEqualFunc equal_func; - - /* Represent nil as NULL table. */ - if (optional && lua_isnoneornil (L, narg)) - *table = NULL; - else - { - /* Check the type; we allow tables only. */ - luaL_checktype (L, narg, LUA_TTABLE); - - /* Get element type infos, create guard for it. */ - guard = lua_gettop (L) + 1; - for (i = 0; i < 2; i++) - { - eti[i] = gi_type_info_get_param_type (ti, i); - lua_gobject_gi_info_new (L, GI_BASE_INFO (eti[i])); - } - - /* Create the hashtable and guard it so that it is destroyed in - case something goes wrong during marshalling. */ - guarded_table = (GHashTable **) - lua_gobject_guard_create (L, (GDestroyNotify) g_hash_table_destroy); - vals++; + GITypeInfo *eti[2]; + GITransfer exfer = + (transfer == GI_TRANSFER_EVERYTHING + ? GI_TRANSFER_EVERYTHING : GI_TRANSFER_NOTHING); + gint i, vals = 0, guard; + GHashTable **guarded_table; + GHashFunc hash_func; + GEqualFunc equal_func; + + /* Represent nil as NULL table. */ + if (optional && lua_isnoneornil(L, narg)) + *table = NULL; + else { + /* Check the type; we allow tables only. */ + luaL_checktype(L, narg, LUA_TTABLE); + + /* Get element type infos, create guard for it. */ + guard = lua_gettop(L) + 1; + for (i = 0; i < 2; i++) { + eti[i] = gi_type_info_get_param_type(ti, i); + lua_gobject_gi_info_new(L, GI_BASE_INFO(eti[i])); + } - /* Find out which hash_func and equal_func should be used, - according to the type of the key. */ - switch (gi_type_info_get_tag (eti[0])) - { - case GI_TYPE_TAG_UTF8: - case GI_TYPE_TAG_FILENAME: - hash_func = g_str_hash; - equal_func = g_str_equal; - break; - case GI_TYPE_TAG_INT64: - case GI_TYPE_TAG_UINT64: - hash_func = g_int64_hash; - equal_func = g_int64_equal; - break; - case GI_TYPE_TAG_FLOAT: - case GI_TYPE_TAG_DOUBLE: - return luaL_error (L, "hashtable with float or double is not " - "supported"); - default: - /* For everything else, use direct hash of stored pointer. */ - hash_func = NULL; - equal_func = NULL; - } - *guarded_table = *table = g_hash_table_new (hash_func, equal_func); + /* Create the hashtable and guard it so that it is destroyed in case something goes wrong during marshalling. */ + guarded_table = (GHashTable **) lua_gobject_guard_create(L,(GDestroyNotify) g_hash_table_destroy); + vals++; + + /* Find out which hash_func and equal_func should be used, according to the type of the key. */ + switch (gi_type_info_get_tag(eti[0])) { + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + hash_func = g_str_hash; + equal_func = g_str_equal; + break; + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + hash_func = g_int64_hash; + equal_func = g_int64_equal; + break; + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + return luaL_error(L, "hashtable with float or double is not " "supported"); + default: + /* For everything else, use direct hash of stored pointer. */ + hash_func = NULL; + equal_func = NULL; + } + *guarded_table = *table = g_hash_table_new(hash_func, equal_func); + + /* Iterate through Lua table and fill hashtable. */ + lua_pushnil(L); + while (lua_next(L, narg)) { + GIArgument eval[2]; + int key_pos = lua_gettop(L) - 1; + + /* Marshal key and value from the table. */ + for (i = 0; i < 2; i++) + vals += lua_gobject_marshal_2c(L, eti[i], NULL, exfer, &eval[i], + key_pos + i, LUA_GOBJECT_PARENT_FORCE_POINTER, + NULL, NULL); + + /* Insert newly marshalled pointers into the table. */ + g_hash_table_insert(*table, eval[0].v_pointer, eval[1].v_pointer); + + /* The great stack suffle; remove value completely and leave key on the top of the stack. Complicated by the fact that both are burried under key_pop + val_pop elements created by marshalling. */ + lua_remove(L, key_pos + 1); + lua_pushvalue(L, key_pos); + lua_remove(L, key_pos); + } - /* Iterate through Lua table and fill hashtable. */ - lua_pushnil (L); - while (lua_next (L, narg)) - { - GIArgument eval[2]; - int key_pos = lua_gettop (L) - 1; - - /* Marshal key and value from the table. */ - for (i = 0; i < 2; i++) - vals += lua_gobject_marshal_2c (L, eti[i], NULL, exfer, &eval[i], - key_pos + i, LUA_GOBJECT_PARENT_FORCE_POINTER, - NULL, NULL); - - /* Insert newly marshalled pointers into the table. */ - g_hash_table_insert (*table, eval[0].v_pointer, eval[1].v_pointer); - - /* The great stack suffle; remove value completely and leave - key on the top of the stack. Complicated by the fact - that both are burried under key_pop + val_pop elements - created by marshalling. */ - lua_remove (L, key_pos + 1); - lua_pushvalue (L, key_pos); - lua_remove (L, key_pos); + /* Remove guards for element types. */ + lua_remove(L, guard); + lua_remove(L, guard); } - /* Remove guards for element types. */ - lua_remove (L, guard); - lua_remove (L, guard); - } - - return vals; + return vals; } static void -marshal_2lua_hash (lua_State *L, GITypeInfo *ti, GIDirection dir, - GITransfer xfer, GHashTable *hash_table) +marshal_2lua_hash(lua_State *L, GITypeInfo *ti, GIDirection dir, + GITransfer xfer, GHashTable *hash_table) { - GHashTableIter iter; - GITypeInfo *eti[2]; - gint i, guard; - GIArgument eval[2]; - - /* Check for 'NULL' table, represent it simply as nil. */ - if (hash_table == NULL) - lua_pushnil (L); - else - { - /* Get key and value type infos, guard them so that we don't - leak it. */ - guard = lua_gettop (L) + 1; - for (i = 0; i < 2; i++) - { - eti[i] = gi_type_info_get_param_type (ti, i); - lua_gobject_gi_info_new (L, GI_BASE_INFO (eti[i])); - } + GHashTableIter iter; + GITypeInfo *eti[2]; + gint i, guard; + GIArgument eval[2]; + + /* Check for 'NULL' table, represent it simply as nil. */ + if (hash_table == NULL) + lua_pushnil(L); + else { + /* Get key and value type infos, guard them so that we don't leak it. */ + guard = lua_gettop(L) + 1; + for (i = 0; i < 2; i++) { + eti[i] = gi_type_info_get_param_type(ti, i); + lua_gobject_gi_info_new(L, GI_BASE_INFO(eti[i])); + } - /* Create table to which we will deserialize the hashtable. */ - lua_newtable (L); + /* Create table to which we will deserialize the hashtable. */ + lua_newtable(L); + + /* Go through the hashtable and push elements into the table. */ + g_hash_table_iter_init(&iter, hash_table); + while (g_hash_table_iter_next(&iter, &eval[0].v_pointer, &eval[1].v_pointer)) { + /* Marshal key and value to the stack. */ + for (i = 0; i < 2; i++) + lua_gobject_marshal_2lua(L, eti[i], NULL, dir, + GI_TRANSFER_NOTHING, &eval[i], + LUA_GOBJECT_PARENT_FORCE_POINTER, + NULL, NULL); + + /* Store these two elements to the table. */ + lua_settable(L, -3); + } - /* Go through the hashtable and push elements into the table. */ - g_hash_table_iter_init (&iter, hash_table); - while (g_hash_table_iter_next (&iter, &eval[0].v_pointer, - &eval[1].v_pointer)) - { - /* Marshal key and value to the stack. */ - for (i = 0; i < 2; i++) - lua_gobject_marshal_2lua (L, eti[i], NULL, dir, GI_TRANSFER_NOTHING, - &eval[i], LUA_GOBJECT_PARENT_FORCE_POINTER, NULL, NULL); + /* Free the table, if requested. */ + if (xfer != GI_TRANSFER_NOTHING) + g_hash_table_unref(hash_table); - /* Store these two elements to the table. */ - lua_settable (L, -3); + lua_remove(L, guard); + lua_remove(L, guard); } - - /* Free the table, if requested. */ - if (xfer != GI_TRANSFER_NOTHING) - g_hash_table_unref (hash_table); - - lua_remove (L, guard); - lua_remove (L, guard); - } } static void -marshal_2lua_error (lua_State *L, GITransfer xfer, GError *err) +marshal_2lua_error(lua_State *L, GITransfer xfer, GError *err) { - if (err == NULL) - lua_pushnil (L); - else - { - /* Wrap error instance with GLib.Error record. */ - lua_gobject_type_get_repotype (L, G_TYPE_ERROR, NULL); - lua_gobject_record_2lua (L, err, xfer != GI_TRANSFER_NOTHING, 0); - } + if (err == NULL) + lua_pushnil(L); + else { + /* Wrap error instance with GLib.Error record. */ + lua_gobject_type_get_repotype(L, G_TYPE_ERROR, NULL); + lua_gobject_record_2lua(L, err, xfer != GI_TRANSFER_NOTHING, 0); + } } /* Marshalls given callable from Lua to C. */ static int -marshal_2c_callable (lua_State *L, GICallableInfo *ci, GIArgInfo *ai, - gpointer *callback, int narg, gboolean optional, - GICallableInfo *argci, void **args) +marshal_2c_callable(lua_State *L, GICallableInfo *ci, GIArgInfo *ai, + gpointer *callback, int narg, gboolean optional, + GICallableInfo *argci, void **args) { - int nret = 0; - GIScopeType scope; - gpointer user_data = NULL; - gint nargs = 0; - - if (argci != NULL) - nargs = gi_callable_info_get_n_args (argci); - - /* Check 'nil' in optional case. In this case, return NULL as - callback. */ - if (lua_isnoneornil (L, narg)) - { - if (optional) - { - *callback = NULL; - - /* Also set associated destroy handler to NULL, because some - callees tend to call it when left as garbage even when - main callback is NULL (gtk_menu_popup_for_device() - case). */ - if (ai != NULL) - { - guint arg; - if (gi_arg_info_get_destroy_index (ai, &arg) && arg < (guint)nargs) - ((GIArgument *) args[arg])->v_pointer = NULL; - } - return 0; + int nret = 0; + GIScopeType scope; + gpointer user_data = NULL; + gint nargs = 0; + + if (argci != NULL) + nargs = gi_callable_info_get_n_args(argci); + + /* Check 'nil' in optional case. In this case, return NULL as callback. */ + if (lua_isnoneornil(L, narg)) { + if (optional) { + *callback = NULL; + + /* Also set associated destroy handler to NULL, because some callees tend to call it when left as garbage even when main callback is NULL(gtk_menu_popup_for_device() case). */ + if (ai != NULL) { + guint arg; + if (gi_arg_info_get_destroy_index(ai, &arg) && arg <(guint)nargs) + ((GIArgument *) args[arg])->v_pointer = NULL; + } + return 0; + } else + return luaL_argerror(L, narg, "nil is not allowed"); } - else - return luaL_argerror (L, narg, "nil is not allowed"); - } - - /* Check lightuserdata case; simply use that data if provided. */ - if (lua_islightuserdata (L, narg)) - { - *callback = lua_touserdata (L, narg); - return 0; - } - - if (argci != NULL) - { - guint arg; - - /* user_data block is already preallocated from function call. */ - g_assert (args != NULL); - if (gi_arg_info_get_closure_index (ai, &arg) && arg < (guint)nargs) - { - user_data = ((GIArgument *) args[arg])->v_pointer; - if (gi_arg_info_get_destroy_index (ai, &arg) && arg < (guint)nargs) - ((GIArgument *) args[arg])->v_pointer = lua_gobject_closure_destroy; + + /* Check lightuserdata case; simply use that data if provided. */ + if (lua_islightuserdata(L, narg)) { + *callback = lua_touserdata(L, narg); + return 0; } - } - - scope = gi_arg_info_get_scope (ai); - if (user_data == NULL) - { - /* Closure without user_data block. Create new data block, - setup destruction according to scope. */ - user_data = lua_gobject_closure_allocate (L, 1); - if (scope == GI_SCOPE_TYPE_CALL) - { - *lua_gobject_guard_create (L, lua_gobject_closure_destroy) = user_data; - nret++; + + if (argci != NULL) { + guint arg; + + /* user_data block is already preallocated from function call. */ + g_assert(args != NULL); + if (gi_arg_info_get_closure_index(ai, &arg) && arg <(guint)nargs) { + user_data = ((GIArgument *) args[arg])->v_pointer; + if (gi_arg_info_get_destroy_index(ai, &arg) && arg <(guint)nargs) + ((GIArgument *) args[arg])->v_pointer = + lua_gobject_closure_destroy; + } } - else - g_assert (scope == GI_SCOPE_TYPE_ASYNC); - } - - /* Create the closure. */ - lua_gobject_callable_create (L, ci, NULL); - *callback = lua_gobject_closure_create (L, user_data, narg, - scope == GI_SCOPE_TYPE_ASYNC); - return nret; + + scope = gi_arg_info_get_scope(ai); + if (user_data == NULL) { + /* Closure without user_data block. Create new data block, setup destruction according to scope. */ + user_data = lua_gobject_closure_allocate(L, 1); + if (scope == GI_SCOPE_TYPE_CALL) { + *lua_gobject_guard_create(L, lua_gobject_closure_destroy) = user_data; + nret++; + } else + g_assert(scope == GI_SCOPE_TYPE_ASYNC); + } + + /* Create the closure. */ + lua_gobject_callable_create(L, ci, NULL); + *callback = lua_gobject_closure_create(L, user_data, narg, + scope == GI_SCOPE_TYPE_ASYNC); + return nret; } /* Marshalls single value from Lua to GLib/C. */ int -lua_gobject_marshal_2c (lua_State *L, GITypeInfo *ti, GIArgInfo *ai, +lua_gobject_marshal_2c(lua_State *L, GITypeInfo *ti, GIArgInfo *ai, GITransfer transfer, gpointer target, int narg, int parent, GICallableInfo *ci, void **args) { - int nret = 0; - gboolean optional = (parent == LUA_GOBJECT_PARENT_CALLER_ALLOC) || - (ai == NULL || (gi_arg_info_is_optional (ai) || - gi_arg_info_may_be_null (ai))); - GITypeTag tag = gi_type_info_get_tag (ti); - GIArgument *arg = target; - - /* Convert narg stack position to absolute one, because during - marshalling some temporary items might be pushed to the stack, - which would disrupt relative stack addressing of the value. */ - lua_gobject_makeabs(L, narg); - - switch (tag) - { - case GI_TYPE_TAG_BOOLEAN: - { - gboolean result; - result = lua_toboolean (L, narg) ? TRUE : FALSE; - if (parent == LUA_GOBJECT_PARENT_FORCE_POINTER) - arg->v_pointer = GINT_TO_POINTER (result); - else if (parent == LUA_GOBJECT_PARENT_IS_RETVAL) - { - ReturnUnion *ru = (ReturnUnion *) arg; - ru->s = result; - } - else - arg->v_boolean = result; - break; - } - - case GI_TYPE_TAG_FLOAT: - case GI_TYPE_TAG_DOUBLE: - { - /* Retrieve number from given position. */ - lua_Number num = (optional && lua_isnoneornil (L, narg)) - ? 0 : luaL_checknumber (L, narg); - - /* Marshalling float/double into pointer target is not possible. */ - g_return_val_if_fail (parent != LUA_GOBJECT_PARENT_FORCE_POINTER, 0); - - /* Store read value into chosen target. */ - if (tag == GI_TYPE_TAG_FLOAT) - arg->v_float = (float) num; - else - arg->v_double = (double) num; - break; - } - - case GI_TYPE_TAG_UTF8: - case GI_TYPE_TAG_FILENAME: - { - gchar *str = NULL; - int type = lua_type (L, narg); - if (type == LUA_TLIGHTUSERDATA) - str = lua_touserdata (L, narg); - else if (!optional || (type != LUA_TNIL && type != LUA_TNONE)) + int nret = 0; + gboolean optional = (parent == LUA_GOBJECT_PARENT_CALLER_ALLOC) || + (ai == NULL || (gi_arg_info_is_optional(ai) || gi_arg_info_may_be_null(ai))); + GITypeTag tag = gi_type_info_get_tag(ti); + GIArgument *arg = target; + + /* Convert narg stack position to absolute one, because during + marshalling some temporary items might be pushed to the stack, + which would disrupt relative stack addressing of the value. */ + lua_gobject_makeabs(L, narg); + + switch (tag) { - if (type == LUA_TUSERDATA) - str = (gchar *) lua_gobject_udata_test (L, narg, LUA_GOBJECT_BYTES_BUFFER); - if (str == NULL) - str = (gchar *) luaL_checkstring (L, narg); + case GI_TYPE_TAG_BOOLEAN: + { + gboolean result; + result = lua_toboolean(L, narg) ? TRUE : FALSE; + if (parent == LUA_GOBJECT_PARENT_FORCE_POINTER) + arg->v_pointer = GINT_TO_POINTER(result); + else if (parent == LUA_GOBJECT_PARENT_IS_RETVAL) { + ReturnUnion *ru = (ReturnUnion *) arg; + ru->s = result; + } + else + arg->v_boolean = result; + break; } - if (tag == GI_TYPE_TAG_FILENAME) - { - /* Convert from UTF-8 to filename encoding. */ - if (str) - { - str = g_filename_from_utf8 (str, -1, NULL, NULL, NULL); - if (transfer != GI_TRANSFER_EVERYTHING) - { - /* Create temporary object on the stack which will - destroy the allocated temporary filename. */ - *lua_gobject_guard_create (L, g_free) = (gpointer) str; - nret = 1; - } - } - } - else if (transfer == GI_TRANSFER_EVERYTHING) - str = g_strdup (str); - if (parent == LUA_GOBJECT_PARENT_FORCE_POINTER) - arg->v_pointer = str; - else - arg->v_string = str; - } - break; - - case GI_TYPE_TAG_INTERFACE: - { - GIBaseInfo *info = gi_type_info_get_interface (ti); - int info_guard; - lua_gobject_gi_info_new (L, info); - info_guard = lua_gettop (L); - - if (GI_IS_ENUM_INFO (info) || GI_IS_FLAGS_INFO (info)) - { - /* If the argument is not numeric, convert to number - first. Use enum/flags 'constructor' to do this. */ - if (lua_type (L, narg) != LUA_TNUMBER) - { - lua_gobject_type_get_repotype (L, G_TYPE_INVALID, info); - lua_pushvalue (L, narg); - lua_call (L, 1, 1); - narg = -1; - } - - /* Directly store underlying value. */ - marshal_2c_int (L, gi_enum_info_get_storage_type (GI_ENUM_INFO (info)), arg, narg, - optional, parent); - - /* Remove the temporary value, to keep stack balanced. */ - if (narg == -1) - lua_pop (L, 1); - } - else if (GI_IS_STRUCT_INFO (info) || GI_IS_UNION_INFO (info)) - { - /* Ideally the gi_type_info_is_pointer() should be - sufficient here, but there is some - gobject-introspection quirk that some struct - arguments might not be marked as pointers - (e.g. g_variant_equals(), which has ctype of - gconstpointer, and thus logic in girparser.c which - sets is_pointer attribute fails). Workaround it by - checking also argument type - structs as C function - arguments are always passed as pointers. */ - gboolean by_value = - parent != LUA_GOBJECT_PARENT_FORCE_POINTER && - ((!gi_type_info_is_pointer (ti) && ai == NULL) || - parent == LUA_GOBJECT_PARENT_CALLER_ALLOC); - - lua_gobject_type_get_repotype (L, G_TYPE_INVALID, info); - lua_gobject_record_2c (L, narg, target, by_value, - transfer != GI_TRANSFER_NOTHING, optional, FALSE); - } - else if (GI_IS_OBJECT_INFO (info) || GI_IS_INTERFACE_INFO (info)) - { - arg->v_pointer = - lua_gobject_object_2c (L, narg, - gi_registered_type_info_get_g_type (GI_REGISTERED_TYPE_INFO (info)), - optional, FALSE, - transfer != GI_TRANSFER_NOTHING); - } - else if (GI_IS_CALLBACK_INFO (info)) - { - nret = marshal_2c_callable (L, GI_CALLABLE_INFO (info), ai, &arg->v_pointer, narg, - optional, ci, args); - } - else - { - g_assert_not_reached (); - } - - lua_remove (L, info_guard); - } - break; - - case GI_TYPE_TAG_ARRAY: - { - gssize size; - GIArrayType atype = gi_type_info_get_array_type (ti); - nret = marshal_2c_array (L, ti, atype, &arg->v_pointer, &size, - narg, optional, transfer); - - /* Fill in array length argument, if it is specified. */ - if (atype == GI_ARRAY_TYPE_C) - array_get_or_set_length (ti, NULL, size, GI_BASE_INFO (ci), args); - break; - } + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + { + /* Retrieve number from given position. */ + lua_Number num = (optional && lua_isnoneornil(L, narg)) + ? 0 : luaL_checknumber(L, narg); + + /* Marshalling float/double into pointer target is not possible. */ + g_return_val_if_fail(parent != LUA_GOBJECT_PARENT_FORCE_POINTER, + 0); + + /* Store read value into chosen target. */ + if (tag == GI_TYPE_TAG_FLOAT) + arg->v_float = (float) num; + else + arg->v_double = (double) num; + break; + } - case GI_TYPE_TAG_GLIST: - case GI_TYPE_TAG_GSLIST: - nret = marshal_2c_list (L, ti, tag, &arg->v_pointer, narg, transfer); - break; + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + { + gchar *str = NULL; + int type = lua_type(L, narg); + if (type == LUA_TLIGHTUSERDATA) + str = lua_touserdata(L, narg); + else if (!optional ||(type != LUA_TNIL && type != LUA_TNONE)) + { + if (type == LUA_TUSERDATA) + str = (gchar *) lua_gobject_udata_test(L, narg, + LUA_GOBJECT_BYTES_BUFFER); + if (str == NULL) + str = (gchar *) luaL_checkstring(L, narg); + } - case GI_TYPE_TAG_GHASH: - nret = marshal_2c_hash (L, ti, (GHashTable **) &arg->v_pointer, narg, - optional, transfer); - break; + if (tag == GI_TYPE_TAG_FILENAME) { + /* Convert from UTF-8 to filename encoding. */ + if (str) { + str = g_filename_from_utf8(str, -1, NULL, NULL, NULL); + if (transfer != GI_TRANSFER_EVERYTHING) { + /* Create temporary object on the stack which will + destroy the allocated temporary filename. */ + *lua_gobject_guard_create(L, g_free) = (gpointer) str; + nret = 1; + } + } + } + else if (transfer == GI_TRANSFER_EVERYTHING) + str = g_strdup(str); + if (parent == LUA_GOBJECT_PARENT_FORCE_POINTER) + arg->v_pointer = str; + else + arg->v_string = str; + } + break; - case GI_TYPE_TAG_VOID: - if (gi_type_info_is_pointer (ti)) + case GI_TYPE_TAG_INTERFACE: { - /* Check and marshal according to real Lua type. */ - if (lua_isnoneornil (L, narg)) - /* nil -> NULL. */ - arg->v_pointer = NULL; - if (lua_type (L, narg) == LUA_TSTRING) - /* Use string directly. */ - arg->v_pointer = (gpointer) lua_tostring (L, narg); - else - { - int type = lua_type (L, narg); - if (type == LUA_TLIGHTUSERDATA) - /* Generic pointer. */ - arg->v_pointer = lua_touserdata (L, narg); - else - { - /* Check memory buffer. */ - arg->v_pointer = lua_gobject_udata_test (L, narg, LUA_GOBJECT_BYTES_BUFFER); - if (!arg->v_pointer) - { - /* Check object. */ - arg->v_pointer = lua_gobject_object_2c (L, narg, G_TYPE_INVALID, - FALSE, TRUE, FALSE); - if (!arg->v_pointer) - { - /* Check any kind of record. */ - lua_pushnil (L); - lua_gobject_record_2c (L, narg, &arg->v_pointer, FALSE, - FALSE, FALSE, TRUE); + GIBaseInfo *info = gi_type_info_get_interface(ti); + int info_guard; + lua_gobject_gi_info_new(L, info); + info_guard = lua_gettop(L); + + if (GI_IS_ENUM_INFO(info) || GI_IS_FLAGS_INFO(info)) { + /* If the argument is not numeric, convert to number + first. Use enum/flags 'constructor' to do this. */ + if (lua_type(L, narg) != LUA_TNUMBER) { + lua_gobject_type_get_repotype(L, G_TYPE_INVALID, info); + lua_pushvalue(L, narg); + lua_call(L, 1, 1); + narg = -1; } - } + + /* Directly store underlying value. */ + marshal_2c_int(L, + gi_enum_info_get_storage_type(GI_ENUM_INFO(info)), + arg, narg, optional, parent); + + /* Remove the temporary value, to keep stack balanced. */ + if (narg == -1) + lua_pop(L, 1); + } else if (GI_IS_STRUCT_INFO(info) || GI_IS_UNION_INFO(info)) { + /* Ideally the gi_type_info_is_pointer() should be sufficient here, but there is some gobject-introspection quirk that some struct arguments might not be marked as pointers (e.g. g_variant_equals(), which has ctype of gconstpointer, and thus logic in girparser.c which sets is_pointer attribute fails). Workaround it by checking also argument type - structs as C function arguments are always passed as pointers. */ + gboolean by_value = + parent != LUA_GOBJECT_PARENT_FORCE_POINTER && + ((!gi_type_info_is_pointer(ti) && ai == NULL) || + parent == LUA_GOBJECT_PARENT_CALLER_ALLOC); + + lua_gobject_type_get_repotype(L, G_TYPE_INVALID, info); + lua_gobject_record_2c(L, narg, target, by_value, + transfer != GI_TRANSFER_NOTHING, optional, FALSE); + } else if (GI_IS_OBJECT_INFO(info) || GI_IS_INTERFACE_INFO(info)) { + arg->v_pointer = + lua_gobject_object_2c(L, narg, + gi_registered_type_info_get_g_type( + GI_REGISTERED_TYPE_INFO(info)), + optional, FALSE, + transfer != GI_TRANSFER_NOTHING); + } else if (GI_IS_CALLBACK_INFO(info)) { + nret = marshal_2c_callable(L, GI_CALLABLE_INFO(info), ai, + &arg->v_pointer, narg, optional, ci, args); + } else { + g_assert_not_reached(); } - } + + lua_remove(L, info_guard); } - break; + break; + + case GI_TYPE_TAG_ARRAY: + { + gssize size; + GIArrayType atype = gi_type_info_get_array_type(ti); + nret = marshal_2c_array(L, ti, atype, &arg->v_pointer, &size, + narg, optional, transfer); + + /* Fill in array length argument, if it is specified. */ + if (atype == GI_ARRAY_TYPE_C) + array_get_or_set_length(ti, NULL, size, GI_BASE_INFO(ci), args); + break; + } + + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + nret = marshal_2c_list(L, ti, tag, &arg->v_pointer, narg, transfer); + break; - default: - marshal_2c_int (L, tag, arg, narg, optional, parent); - } + case GI_TYPE_TAG_GHASH: + nret = marshal_2c_hash(L, ti,(GHashTable **) &arg->v_pointer, narg, + optional, transfer); + break; + + case GI_TYPE_TAG_VOID: + if (gi_type_info_is_pointer(ti)) { + /* Check and marshal according to real Lua type. */ + if (lua_isnoneornil(L, narg)) + /* nil -> NULL. */ + arg->v_pointer = NULL; + if (lua_type(L, narg) == LUA_TSTRING) + /* Use string directly. */ + arg->v_pointer = (gpointer) lua_tostring(L, narg); + else { + int type = lua_type(L, narg); + if (type == LUA_TLIGHTUSERDATA) + /* Generic pointer. */ + arg->v_pointer = lua_touserdata(L, narg); + else { + /* Check memory buffer. */ + arg->v_pointer = lua_gobject_udata_test(L, narg, + LUA_GOBJECT_BYTES_BUFFER); + if (!arg->v_pointer) { + /* Check object. */ + arg->v_pointer = lua_gobject_object_2c(L, narg, + G_TYPE_INVALID, FALSE, TRUE, FALSE); + if (!arg->v_pointer) { + /* Check any kind of record. */ + lua_pushnil(L); + lua_gobject_record_2c(L, narg, &arg->v_pointer, + FALSE, FALSE, FALSE, TRUE); + } + } + } + } + } + break; + + default: + marshal_2c_int(L, tag, arg, narg, optional, parent); + } - return nret; + return nret; } gboolean -lua_gobject_marshal_2c_caller_alloc (lua_State *L, GITypeInfo *ti, GIArgument *val, - int pos) +lua_gobject_marshal_2c_caller_alloc(lua_State *L, GITypeInfo *ti, GIArgument *val, + int pos) { - gboolean handled = FALSE; - switch (gi_type_info_get_tag (ti)) - { - case GI_TYPE_TAG_INTERFACE: - { - GIBaseInfo *ii = gi_type_info_get_interface (ti); - if (GI_IS_STRUCT_INFO (ii) || GI_IS_UNION_INFO (ii)) - { - if (pos == 0) - { - lua_gobject_type_get_repotype (L, G_TYPE_INVALID, ii); - val->v_pointer = lua_gobject_record_new (L, 1, FALSE); - } - handled = TRUE; - } - - gi_base_info_unref (ii); - break; - } - - case GI_TYPE_TAG_ARRAY: - { - if (gi_type_info_get_array_type (ti) == GI_ARRAY_TYPE_C) - { - gpointer *array_guard; - if (pos == 0) - { - gssize elt_size; - gsize size; - - /* Currently only fixed-size arrays are supported. */ - elt_size = - array_get_elt_size (gi_type_info_get_param_type (ti, 0), FALSE); - if (!gi_type_info_get_array_fixed_size (ti, &size)) - g_assert_not_reached (); - g_assert (size > 0); - - /* Allocate underlying array. It is temporary, - existing only for the duration of the call. */ - array_guard = - lua_gobject_guard_create (L, (GDestroyNotify) g_array_unref); - *array_guard = g_array_sized_new (FALSE, FALSE, elt_size, size); - g_array_set_size (*array_guard, size); - } - else - { - /* Convert the allocated array into Lua table with - contents. We have to do it in-place. */ - - /* Make sure that pos is absolute, so that stack - shuffling below does not change the element it - points to. */ - if (pos < 0) - pos += lua_gettop (L) + 1; - - /* Get GArray from the guard and unmarshal it as a - full GArray into Lua. */ - array_guard = lua_touserdata (L, pos); - marshal_2lua_array (L, ti, GI_DIRECTION_OUT, - GI_ARRAY_TYPE_ARRAY, - GI_TRANSFER_EVERYTHING, *array_guard, - -1, pos); - - /* Deactivate old guard, everything was marshalled - into the newly created and marshalled table. */ - *array_guard = NULL; - - /* Switch old value with the new data. */ - lua_replace (L, pos); - } - handled = TRUE; - } + gboolean handled = FALSE; + switch (gi_type_info_get_tag(ti)) { + case GI_TYPE_TAG_INTERFACE: + { + GIBaseInfo *ii = gi_type_info_get_interface(ti); + if (GI_IS_STRUCT_INFO(ii) || GI_IS_UNION_INFO(ii)) { + if (pos == 0) { + lua_gobject_type_get_repotype(L, G_TYPE_INVALID, ii); + val->v_pointer = lua_gobject_record_new(L, 1, FALSE); + } + handled = TRUE; + } - break; - } + gi_base_info_unref(ii); + break; + } - default: - break; - } + case GI_TYPE_TAG_ARRAY: + { + if (gi_type_info_get_array_type(ti) == GI_ARRAY_TYPE_C) { + gpointer *array_guard; + if (pos == 0) { + gssize elt_size; + gsize size; + + /* Currently only fixed-size arrays are supported. */ + elt_size = + array_get_elt_size(gi_type_info_get_param_type(ti, 0), FALSE); + if (!gi_type_info_get_array_fixed_size(ti, &size)) + g_assert_not_reached(); + g_assert(size > 0); + + /* Allocate underlying array. It is temporary, existing only for the duration of the call. */ + array_guard = + lua_gobject_guard_create(L,(GDestroyNotify) g_array_unref); + *array_guard = g_array_sized_new(FALSE, FALSE, elt_size, size); + g_array_set_size(*array_guard, size); + } else { + /* Convert the allocated array into Lua table with contents. We have to do it in-place. */ + + /* Make sure that pos is absolute, so that stack shuffling below does not change the element it points to. */ + if (pos < 0) + pos += lua_gettop(L) + 1; + + /* Get GArray from the guard and unmarshal it as a full GArray into Lua. */ + array_guard = lua_touserdata(L, pos); + marshal_2lua_array(L, ti, GI_DIRECTION_OUT, + GI_ARRAY_TYPE_ARRAY, + GI_TRANSFER_EVERYTHING, *array_guard, + -1, pos); + + /* Deactivate old guard, everything was marshalled into the newly created and marshalled table. */ + *array_guard = NULL; + + /* Switch old value with the new data. */ + lua_replace(L, pos); + } + handled = TRUE; + } + + break; + } - return handled; + default: + break; + } + + return handled; } -/* Marshalls single value from GLib/C to Lua. Returns 1 if something - was pushed to the stack. */ +/* Marshalls single value from GLib/C to Lua. Returns 1 if something was pushed to the stack. */ void -lua_gobject_marshal_2lua (lua_State *L, GITypeInfo *ti, GIArgInfo *ai, GIDirection dir, - GITransfer transfer, gpointer source, int parent, - GICallableInfo *ci, void *args) +lua_gobject_marshal_2lua(lua_State *L, GITypeInfo *ti, GIArgInfo *ai, GIDirection dir, + GITransfer transfer, gpointer source, int parent, + GICallableInfo *ci, void *args) { - gboolean own = (transfer != GI_TRANSFER_NOTHING); - GITypeTag tag = gi_type_info_get_tag (ti); - GIArgument *arg = source; - - /* Make sure that parent is absolute index so that it is fixed even - when we add/remove from the stack. */ - lua_gobject_makeabs (L, parent); - - switch (tag) - { - case GI_TYPE_TAG_VOID: - if (gi_type_info_is_pointer (ti)) - /* Marshal pointer to simple lightuserdata. */ - lua_pushlightuserdata (L, arg->v_pointer); - else - lua_pushnil (L); - break; - - case GI_TYPE_TAG_BOOLEAN: - if (parent == LUA_GOBJECT_PARENT_IS_RETVAL) + gboolean own = (transfer != GI_TRANSFER_NOTHING); + GITypeTag tag = gi_type_info_get_tag(ti); + GIArgument *arg = source; + + /* Make sure that parent is absolute index so that it is fixed even + when we add/remove from the stack. */ + lua_gobject_makeabs(L, parent); + + switch (tag) { - ReturnUnion *ru = (ReturnUnion *) arg; - ru->arg.v_boolean = ru->s; - } - lua_pushboolean (L, arg->v_boolean); - break; - - case GI_TYPE_TAG_FLOAT: - case GI_TYPE_TAG_DOUBLE: - g_return_if_fail (parent != LUA_GOBJECT_PARENT_FORCE_POINTER); - lua_pushnumber (L, (tag == GI_TYPE_TAG_FLOAT) - ? arg->v_float : arg->v_double); - break; - - case GI_TYPE_TAG_UTF8: - case GI_TYPE_TAG_FILENAME: - { - gchar *str = (parent == LUA_GOBJECT_PARENT_FORCE_POINTER) - ? arg->v_pointer : arg->v_string; - if (tag == GI_TYPE_TAG_FILENAME && str != NULL) - { - gchar *utf8 = g_filename_to_utf8 (str, -1, NULL, NULL, NULL); - lua_pushstring (L, utf8); - g_free (utf8); - } - else - lua_pushstring (L, str); - if (transfer == GI_TRANSFER_EVERYTHING) - g_free (str); + case GI_TYPE_TAG_VOID: + if (gi_type_info_is_pointer(ti)) + /* Marshal pointer to simple lightuserdata. */ + lua_pushlightuserdata(L, arg->v_pointer); + else + lua_pushnil(L); break; - } - - case GI_TYPE_TAG_INTERFACE: - { - GIBaseInfo *info = gi_type_info_get_interface (ti); - int info_guard; - lua_gobject_gi_info_new (L, info); - info_guard = lua_gettop (L); - if (GI_IS_ENUM_INFO (info) || GI_IS_FLAGS_INFO (info)) - { - /* Prepare repotable of enum/flags on the stack. */ - lua_gobject_type_get_repotype (L, G_TYPE_INVALID, info); - - /* Unmarshal the numeric value. */ - marshal_2lua_int (L, gi_enum_info_get_storage_type (GI_ENUM_INFO (info)), - arg, parent); - - /* Get symbolic value from the table. */ - lua_gettable (L, -2); - - /* Remove the table from the stack. */ - lua_remove (L, -2); - } - else if (GI_IS_STRUCT_INFO (info) || GI_IS_UNION_INFO (info)) - { - gboolean by_ref = parent == LUA_GOBJECT_PARENT_FORCE_POINTER || - gi_type_info_is_pointer (ti); - if (parent < LUA_GOBJECT_PARENT_CALLER_ALLOC && by_ref) - parent = 0; - lua_gobject_type_get_repotype (L, G_TYPE_INVALID, info); - lua_gobject_record_2lua (L, by_ref ? arg->v_pointer : source, - own, parent); - } - else if (GI_IS_OBJECT_INFO (info) || GI_IS_INTERFACE_INFO (info)) - { - /* Avoid sinking for input arguments, because it wreaks - havoc to input arguments of vfunc callbacks during - InitiallyUnowned construction phase. */ - lua_gobject_object_2lua (L, arg->v_pointer, own, dir == GI_DIRECTION_IN); - } - else if (GI_IS_CALLBACK_INFO (info)) - { - if (arg->v_pointer == NULL) - lua_pushnil (L); - else - { - lua_gobject_callable_create (L, GI_CALLABLE_INFO (info), arg->v_pointer); - if (ai != NULL && args != NULL) - { - guint closure; - if (gi_arg_info_get_closure_index (ai, &closure)) - { - /* Store context associated with the callback - to the callback object. */ - GIArgument *arg = ((void **) args)[closure]; - lua_pushlightuserdata (L, arg->v_pointer); - lua_setfield (L, -2, "user_data"); - } - } - } - } - else - { - g_assert_not_reached (); - } - - lua_remove (L, info_guard); - } - break; - - case GI_TYPE_TAG_ARRAY: - { - GIArrayType atype = gi_type_info_get_array_type (ti); - gssize size = -1; - gpointer ptr = gi_type_info_is_pointer (ti) ? arg->v_pointer : arg; - array_get_or_set_length (ti, &size, 0, GI_BASE_INFO (ci), args); - marshal_2lua_array (L, ti, dir, atype, transfer, ptr, size, parent); - } - break; - - case GI_TYPE_TAG_GSLIST: - case GI_TYPE_TAG_GLIST: - marshal_2lua_list (L, ti, dir, tag, transfer, arg->v_pointer); - break; - - case GI_TYPE_TAG_GHASH: - marshal_2lua_hash (L, ti, dir, transfer, arg->v_pointer); - break; - - case GI_TYPE_TAG_ERROR: - marshal_2lua_error (L, transfer, arg->v_pointer); - break; - - default: - marshal_2lua_int (L, tag, arg, parent); - } -} -int -lua_gobject_marshal_field (lua_State *L, gpointer object, gboolean getmode, - int parent_arg, int field_arg, int val_arg) -{ - GITypeInfo *ti; - int to_remove, nret; - GIBaseInfo *pi = NULL; - gpointer field_addr; - - /* Check the type of the field information. */ - if (lua_gobject_udata_test (L, field_arg, LUA_GOBJECT_GI_INFO)) - { - GIFieldInfoFlags flags; - GIFieldInfo **fi = lua_touserdata (L, field_arg); - pi = gi_base_info_get_container (GI_BASE_INFO (*fi)); - - /* Check, whether field is readable/writable. */ - flags = gi_field_info_get_flags (*fi); - if ((flags & (getmode ? GI_FIELD_IS_READABLE - : GI_FIELD_IS_WRITABLE)) == 0) + case GI_TYPE_TAG_BOOLEAN: + if (parent == LUA_GOBJECT_PARENT_IS_RETVAL) { + ReturnUnion *ru = (ReturnUnion *) arg; + ru->arg.v_boolean = ru->s; + } + lua_pushboolean(L, arg->v_boolean); + break; + + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + g_return_if_fail(parent != LUA_GOBJECT_PARENT_FORCE_POINTER); + lua_pushnumber(L,(tag == GI_TYPE_TAG_FLOAT) + ? arg->v_float : arg->v_double); + break; + + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: { - /* Check, whether parent did not disable access checks - completely. */ - lua_getfield (L, -1, "_allow"); - if (!lua_toboolean (L, -1)) - { - /* Prepare proper error message. */ - lua_concat (L, - lua_gobject_type_get_name (L, - gi_base_info_get_container (GI_BASE_INFO (*fi)))); - return luaL_error (L, "%s: field `%s' is not %s", - lua_tostring (L, -1), - gi_base_info_get_name (GI_BASE_INFO (*fi)), - getmode ? "readable" : "writable"); - } - lua_pop (L, 1); + gchar *str = (parent == LUA_GOBJECT_PARENT_FORCE_POINTER) + ? arg->v_pointer : arg->v_string; + if (tag == GI_TYPE_TAG_FILENAME && str != NULL) { + gchar *utf8 = g_filename_to_utf8(str, -1, NULL, NULL, NULL); + lua_pushstring(L, utf8); + g_free(utf8); + } + else + lua_pushstring(L, str); + if (transfer == GI_TRANSFER_EVERYTHING) + g_free(str); + break; } - /* Map GIArgument to proper memory location, get typeinfo of the - field and perform actual marshalling. */ - field_addr = (char *) object + gi_field_info_get_offset (*fi); - ti = gi_field_info_get_type_info (*fi); - lua_gobject_gi_info_new (L, GI_BASE_INFO (ti)); - to_remove = lua_gettop (L); - } - else - { - /* Consult field table, get kind of field and offset. */ - int kind; - lua_gobject_makeabs (L, field_arg); - luaL_checktype (L, field_arg, LUA_TTABLE); - lua_rawgeti (L, field_arg, 1); - field_addr = (char *) object + lua_tointeger (L, -1); - lua_rawgeti (L, field_arg, 2); - kind = lua_tointeger (L, -1); - lua_pop (L, 2); - - /* Load type information from the table and decide how to handle - it according to 'kind' */ - lua_rawgeti (L, field_arg, 3); - switch (kind) + case GI_TYPE_TAG_INTERFACE: { - case 0: - /* field[3] contains typeinfo, load it and fall through. */ - ti = *(GITypeInfo **) luaL_checkudata (L, -1, LUA_GOBJECT_GI_INFO); - to_remove = lua_gettop (L); - break; - - case 1: - case 2: - { - GIArgument *arg = (GIArgument *) field_addr; - if (getmode) - { - if (kind == 1) - { - field_addr = arg->v_pointer; - parent_arg = 0; - } - lua_gobject_record_2lua (L, field_addr, FALSE, parent_arg); - return 1; - } - else - { - g_assert (kind == 1); - lua_gobject_record_2c (L, val_arg, arg->v_pointer, - FALSE, TRUE, FALSE, FALSE); - return 0; - } - break; - } - - case 3: - { - /* Get the typeinfo for marshalling the numeric enum value. */ - lua_rawgeti (L, field_arg, 4); - ti = *(GITypeInfo **) luaL_checkudata (L, -1, LUA_GOBJECT_GI_INFO); - if (getmode) - { - /* Use typeinfo to unmarshal numeric value. */ - lua_gobject_marshal_2lua (L, ti, NULL, GI_DIRECTION_OUT, - GI_TRANSFER_NOTHING, field_addr, 0, - NULL, NULL); - - /* Replace numeric field with symbolic value. */ - lua_gettable (L, -3); - lua_replace (L, -3); - lua_pop (L, 1); - return 1; - } - else - { - /* Convert enum symbol to numeric value. */ - if (lua_type (L, val_arg != LUA_TNUMBER)) - { - lua_pushvalue (L, -1); - lua_pushvalue (L, val_arg); - lua_call (L, 1, 1); - lua_replace (L, val_arg); - } - - /* Use typeinfo to marshal the numeric value. */ - lua_gobject_marshal_2c (L, ti, NULL, GI_TRANSFER_NOTHING, field_addr, - val_arg, 0, NULL, NULL); - lua_pop (L, 2); - return 0; - } - } + GIBaseInfo *info = gi_type_info_get_interface(ti); + int info_guard; + lua_gobject_gi_info_new(L, info); + info_guard = lua_gettop(L); + if (GI_IS_ENUM_INFO(info) || GI_IS_FLAGS_INFO(info)) { + /* Prepare repotable of enum/flags on the stack. */ + lua_gobject_type_get_repotype(L, G_TYPE_INVALID, info); + + /* Unmarshal the numeric value. */ + marshal_2lua_int(L, + gi_enum_info_get_storage_type(GI_ENUM_INFO(info)), + arg, parent); + + /* Get symbolic value from the table. */ + lua_gettable(L, -2); + + /* Remove the table from the stack. */ + lua_remove(L, -2); + } else if (GI_IS_STRUCT_INFO(info) || GI_IS_UNION_INFO(info)) { + gboolean by_ref = parent == + LUA_GOBJECT_PARENT_FORCE_POINTER || + gi_type_info_is_pointer(ti); + if (parent < LUA_GOBJECT_PARENT_CALLER_ALLOC && by_ref) + parent = 0; + lua_gobject_type_get_repotype(L, G_TYPE_INVALID, info); + lua_gobject_record_2lua(L, by_ref ? arg->v_pointer : source, + own, parent); + } else if (GI_IS_OBJECT_INFO(info) || GI_IS_INTERFACE_INFO(info)) { + /* Avoid sinking for input arguments, because it wreaks + havoc to input arguments of vfunc callbacks during + InitiallyUnowned construction phase. */ + lua_gobject_object_2lua(L, arg->v_pointer, own, dir == GI_DIRECTION_IN); + } else if (GI_IS_CALLBACK_INFO(info)) { + if (arg->v_pointer == NULL) + lua_pushnil(L); + else { + lua_gobject_callable_create(L, GI_CALLABLE_INFO(info), arg->v_pointer); + if (ai != NULL && args != NULL) { + guint closure; + if (gi_arg_info_get_closure_index(ai, &closure)) { + /* Store context associated with the callback + to the callback object. */ + GIArgument *arg = ((void **) args)[closure]; + lua_pushlightuserdata(L, arg->v_pointer); + lua_setfield(L, -2, "user_data"); + } + } + } + } else { + g_assert_not_reached(); + } + + lua_remove(L, info_guard); + } + break; + + case GI_TYPE_TAG_ARRAY: + { + GIArrayType atype = gi_type_info_get_array_type(ti); + gssize size = -1; + gpointer ptr = gi_type_info_is_pointer(ti) ? arg->v_pointer : arg; + array_get_or_set_length(ti, &size, 0, GI_BASE_INFO(ci), args); + marshal_2lua_array(L, ti, dir, atype, transfer, ptr, size, parent); + break; + } + + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GLIST: + marshal_2lua_list(L, ti, dir, tag, transfer, arg->v_pointer); + break; + + case GI_TYPE_TAG_GHASH: + marshal_2lua_hash(L, ti, dir, transfer, arg->v_pointer); + break; + + case GI_TYPE_TAG_ERROR: + marshal_2lua_error(L, transfer, arg->v_pointer); + break; default: - return luaL_error (L, "field has bad kind %d", kind); + marshal_2lua_int(L, tag, arg, parent); } - } - - GICallableInfo *ci = GI_IS_CALLABLE_INFO (pi) ? GI_CALLABLE_INFO (pi) : NULL; - if (getmode) - { - lua_gobject_marshal_2lua (L, ti, NULL, GI_DIRECTION_OUT, GI_TRANSFER_NOTHING, - field_addr, parent_arg, ci, object); - nret = 1; - } - else - { - lua_gobject_marshal_2c (L, ti, NULL, GI_TRANSFER_EVERYTHING, field_addr, val_arg, - 0, NULL, NULL); - nret = 0; - } - - lua_remove (L, to_remove); - return nret; } int -lua_gobject_marshal_access (lua_State *L, gboolean getmode, - int compound_arg, int element_arg, int val_arg) +lua_gobject_marshal_field(lua_State *L, gpointer object, gboolean getmode, + int parent_arg, int field_arg, int val_arg) { - lua_getfield (L, -1, "_access"); - lua_pushvalue (L, -2); - lua_pushvalue (L, compound_arg); - lua_pushvalue (L, element_arg); - if (getmode) - { - lua_call (L, 3, 1); - return 1; - } - else - { - lua_pushvalue (L, val_arg); - lua_call (L, 4, 0); - return 0; - } + GITypeInfo *ti; + int to_remove, nret; + GIBaseInfo *pi = NULL; + gpointer field_addr; + + /* Check the type of the field information. */ + if (lua_gobject_udata_test(L, field_arg, LUA_GOBJECT_GI_INFO)) { + GIFieldInfoFlags flags; + GIFieldInfo **fi = lua_touserdata(L, field_arg); + pi = gi_base_info_get_container(GI_BASE_INFO(*fi)); + + /* Check, whether field is readable/writable. */ + flags = gi_field_info_get_flags(*fi); + if ((flags &(getmode ? GI_FIELD_IS_READABLE + : GI_FIELD_IS_WRITABLE)) == 0) { + /* Check, whether parent did not disable access checks completely. */ + lua_getfield(L, -1, "_allow"); + if (!lua_toboolean(L, -1)) { + /* Prepare proper error message. */ + lua_concat(L, lua_gobject_type_get_name(L, + gi_base_info_get_container(GI_BASE_INFO(*fi)))); + return luaL_error(L, "%s: field `%s' is not %s", + lua_tostring(L, -1), + gi_base_info_get_name(GI_BASE_INFO(*fi)), + getmode ? "readable" : "writable"); + } + lua_pop(L, 1); + } + + /* Map GIArgument to proper memory location, get typeinfo of the field and perform actual marshalling. */ + field_addr = (char *) object + gi_field_info_get_offset(*fi); + ti = gi_field_info_get_type_info(*fi); + lua_gobject_gi_info_new(L, GI_BASE_INFO(ti)); + to_remove = lua_gettop(L); + } else { + /* Consult field table, get kind of field and offset. */ + int kind; + lua_gobject_makeabs(L, field_arg); + luaL_checktype(L, field_arg, LUA_TTABLE); + lua_rawgeti(L, field_arg, 1); + field_addr = (char *) object + lua_tointeger(L, -1); + lua_rawgeti(L, field_arg, 2); + kind = lua_tointeger(L, -1); + lua_pop(L, 2); + + /* Load type information from the table and decide how to handle it according to 'kind' */ + lua_rawgeti(L, field_arg, 3); + switch (kind) { + case 0: + /* field[3] contains typeinfo, load it and fall through. */ + ti = *(GITypeInfo **) luaL_checkudata(L, -1, LUA_GOBJECT_GI_INFO); + to_remove = lua_gettop(L); + break; + + case 1: + case 2: + { + GIArgument *arg = (GIArgument *) field_addr; + if (getmode) { + if (kind == 1) { + field_addr = arg->v_pointer; + parent_arg = 0; + } + lua_gobject_record_2lua(L, field_addr, FALSE, parent_arg); + return 1; + } else { + g_assert(kind == 1); + lua_gobject_record_2c(L, val_arg, arg->v_pointer, + FALSE, TRUE, FALSE, FALSE); + return 0; + } + break; + } + + case 3: + { + /* Get the typeinfo for marshalling the numeric enum value. */ + lua_rawgeti(L, field_arg, 4); + ti = *(GITypeInfo **) luaL_checkudata(L, -1, LUA_GOBJECT_GI_INFO); + if (getmode) { + /* Use typeinfo to unmarshal numeric value. */ + lua_gobject_marshal_2lua(L, ti, NULL, GI_DIRECTION_OUT, + GI_TRANSFER_NOTHING, field_addr, 0, + NULL, NULL); + + /* Replace numeric field with symbolic value. */ + lua_gettable(L, -3); + lua_replace(L, -3); + lua_pop(L, 1); + return 1; + } else { + /* Convert enum symbol to numeric value. */ + if (lua_type(L, val_arg != LUA_TNUMBER)) { + lua_pushvalue(L, -1); + lua_pushvalue(L, val_arg); + lua_call(L, 1, 1); + lua_replace(L, val_arg); + } + + /* Use typeinfo to marshal the numeric value. */ + lua_gobject_marshal_2c(L, ti, NULL, + GI_TRANSFER_NOTHING, field_addr, + val_arg, 0, NULL, NULL); + lua_pop(L, 2); + return 0; + } + } + + default: + return luaL_error(L, "field has bad kind %d", kind); + } + } + + GICallableInfo *ci = GI_IS_CALLABLE_INFO(pi) + ? GI_CALLABLE_INFO(pi) : NULL; + if (getmode) { + lua_gobject_marshal_2lua(L, ti, NULL, GI_DIRECTION_OUT, + GI_TRANSFER_NOTHING, field_addr, parent_arg, ci, object); + nret = 1; + } else { + lua_gobject_marshal_2c(L, ti, NULL, GI_TRANSFER_EVERYTHING, + field_addr, val_arg, 0, NULL, NULL); + nret = 0; + } + + lua_remove(L, to_remove); + return nret; +} + +int +lua_gobject_marshal_access(lua_State *L, gboolean getmode, + int compound_arg, int element_arg, int val_arg) +{ + lua_getfield(L, -1, "_access"); + lua_pushvalue(L, -2); + lua_pushvalue(L, compound_arg); + lua_pushvalue(L, element_arg); + if (getmode) { + lua_call(L, 3, 1); + return 1; + } else { + lua_pushvalue(L, val_arg); + lua_call(L, 4, 0); + return 0; + } } /* Container marshaller function. */ static int -marshal_container_marshaller (lua_State *L) +marshal_container_marshaller(lua_State *L) { - GValue *value; - GITypeInfo **ti; - GITypeTag tag; - GITransfer transfer; - gpointer data; - int nret = 0; - gboolean get_mode = lua_isnone (L, 3); - - /* Get GValue to operate on. */ - lua_gobject_type_get_repotype (L, G_TYPE_VALUE, NULL); - lua_gobject_record_2c (L, 1, &value, FALSE, FALSE, FALSE, FALSE); - - /* Get raw pointer from the value. */ - if (get_mode) - { - if (G_VALUE_TYPE (value) == G_TYPE_POINTER) - data = g_value_get_pointer (value); - else - data = g_value_get_boxed (value); - } - - /* Get info and transfer from upvalue. */ - ti = lua_touserdata (L, lua_upvalueindex (1)); - tag = gi_type_info_get_tag (*ti); - transfer = lua_tointeger (L, lua_upvalueindex (2)); - - switch (tag) - { - case GI_TYPE_TAG_ARRAY: - { - GIArrayType atype = gi_type_info_get_array_type (*ti); - gssize size = -1; - if (get_mode) - { - if (lua_type (L, 2) == LUA_TTABLE) - { - lua_getfield (L, 2, "length"); - size = luaL_optinteger (L, -1, -1); - lua_pop (L, 1); - } - marshal_2lua_array (L, *ti, GI_DIRECTION_OUT, atype, transfer, + GValue *value; + GITypeInfo **ti; + GITypeTag tag; + GITransfer transfer; + gpointer data; + int nret = 0; + gboolean get_mode = lua_isnone(L, 3); + + /* Get GValue to operate on. */ + lua_gobject_type_get_repotype(L, G_TYPE_VALUE, NULL); + lua_gobject_record_2c(L, 1, &value, FALSE, FALSE, FALSE, FALSE); + + /* Get raw pointer from the value. */ + if (get_mode) { + if (G_VALUE_TYPE(value) == G_TYPE_POINTER) + data = g_value_get_pointer(value); + else + data = g_value_get_boxed(value); + } + + /* Get info and transfer from upvalue. */ + ti = lua_touserdata(L, lua_upvalueindex(1)); + tag = gi_type_info_get_tag(*ti); + transfer = lua_tointeger(L, lua_upvalueindex(2)); + + switch (tag) { + case GI_TYPE_TAG_ARRAY: + { + GIArrayType atype = gi_type_info_get_array_type(*ti); + gssize size = -1; + if (get_mode) { + if (lua_type(L, 2) == LUA_TTABLE) { + lua_getfield(L, 2, "length"); + size = luaL_optinteger(L, -1, -1); + lua_pop(L, 1); + } + marshal_2lua_array(L, *ti, GI_DIRECTION_OUT, atype, transfer, data, size, 0); - } - else - { - nret = marshal_2c_array (L, *ti, atype, &data, &size, 3, FALSE, - transfer); - if (lua_type (L, 2) == LUA_TTABLE) - { - lua_pushinteger (L, size); - lua_setfield (L, 2, "length"); - } - } + } else { + nret = marshal_2c_array(L, *ti, atype, &data, &size, 3, FALSE, + transfer); + if (lua_type(L, 2) == LUA_TTABLE) { + lua_pushinteger(L, size); + lua_setfield(L, 2, "length"); + } + } + break; + } + + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GLIST: + if (get_mode) + marshal_2lua_list(L, *ti, GI_DIRECTION_OUT, tag, transfer, data); + else + nret = marshal_2c_list(L, *ti, tag, &data, 3, transfer); break; - } - - case GI_TYPE_TAG_GSLIST: - case GI_TYPE_TAG_GLIST: - if (get_mode) - marshal_2lua_list (L, *ti, GI_DIRECTION_OUT, tag, transfer, data); - else - nret = marshal_2c_list (L, *ti, tag, &data, 3, transfer); - break; - - case GI_TYPE_TAG_GHASH: - if (get_mode) - marshal_2lua_hash (L, *ti, GI_DIRECTION_OUT, transfer, data); - else - nret = marshal_2c_hash (L, *ti, (GHashTable **) &data, 3, FALSE, + + case GI_TYPE_TAG_GHASH: + if (get_mode) + marshal_2lua_hash(L, *ti, GI_DIRECTION_OUT, transfer, data); + else + nret = marshal_2c_hash(L, *ti,(GHashTable **) &data, 3, FALSE, transfer); - break; - - default: - g_assert_not_reached (); - } - - /* Store result pointer to the value. */ - if (!get_mode) - { - if (G_VALUE_TYPE (value) == G_TYPE_POINTER) - g_value_set_pointer (value, data); - else - g_value_set_boxed (value, data); - } - - /* If there are any temporary objects, try to store them into - attrs.keepalive table, if it is present. */ - if (!lua_isnoneornil (L, 2)) - { - lua_getfield (L, 2, "keepalive"); - if (!lua_isnil (L, -1)) - for (lua_insert (L, -nret - 1); nret > 0; nret--) - { - lua_pushinteger (L, lua_objlen (L, -nret - 1)); - lua_insert (L, -2); - lua_settable (L, -nret - 3); - lua_pop (L, 1); - } - else - lua_pop (L, nret); - lua_pop (L, 1); - } - else - lua_pop (L, nret); - - return get_mode ? 1 : 0; + break; + + default: + g_assert_not_reached(); + } + + /* Store result pointer to the value. */ + if (!get_mode) { + if (G_VALUE_TYPE(value) == G_TYPE_POINTER) + g_value_set_pointer(value, data); + else + g_value_set_boxed(value, data); + } + + /* If there are any temporary objects, try to store them into + attrs.keepalive table, if it is present. */ + if (!lua_isnoneornil(L, 2)) { + lua_getfield(L, 2, "keepalive"); + if (!lua_isnil(L, -1)) + for (lua_insert(L, -nret - 1); nret > 0; nret--) { + lua_pushinteger(L, lua_objlen(L, -nret - 1)); + lua_insert(L, -2); + lua_settable(L, -nret - 3); + lua_pop(L, 1); + } + else + lua_pop(L, nret); + lua_pop(L, 1); + } else + lua_pop(L, nret); + + return get_mode ? 1 : 0; } static const char* const transfers[] = { "none", "container", "full", NULL }; -/* Creates container (array, list, slist, hash) marshaller for - specified container typeinfo. Signature is: - marshaller = marshal.container(typeinfo, transfer) */ +/* Creates container(array, list, slist, hash) marshaller for specified container typeinfo. Signature is: marshaller = marshal.container(typeinfo, transfer) */ static int -marshal_container (lua_State *L) +marshal_container(lua_State *L) { - GIBaseInfo **info = luaL_checkudata (L, 1, LUA_GOBJECT_GI_INFO); - GITypeTag tag = gi_type_info_get_tag (GI_TYPE_INFO (*info)); - GITransfer transfer = luaL_checkoption (L, 2, transfers[0], transfers); - if (tag == GI_TYPE_TAG_ARRAY || tag == GI_TYPE_TAG_GHASH || - tag == GI_TYPE_TAG_GSLIST || tag == GI_TYPE_TAG_GLIST) - { - lua_pushvalue (L, 1); - lua_pushinteger (L, transfer); - lua_pushcclosure (L, marshal_container_marshaller, 2); - } - else - lua_pushnil (L); - return 1; + GIBaseInfo **info = luaL_checkudata(L, 1, LUA_GOBJECT_GI_INFO); + GITypeTag tag = gi_type_info_get_tag(GI_TYPE_INFO(*info)); + GITransfer transfer = luaL_checkoption(L, 2, transfers[0], transfers); + if (tag == GI_TYPE_TAG_ARRAY || tag == GI_TYPE_TAG_GHASH || + tag == GI_TYPE_TAG_GSLIST || tag == GI_TYPE_TAG_GLIST) { + lua_pushvalue(L, 1); + lua_pushinteger(L, transfer); + lua_pushcclosure(L, marshal_container_marshaller, 2); + } else + lua_pushnil(L); + return 1; } /* Fundamental marshaller closure. */ static int -marshal_fundamental_marshaller (lua_State *L) +marshal_fundamental_marshaller(lua_State *L) { - gpointer obj; - gboolean get_mode = lua_isnone (L, 3); - GValue *value; - lua_gobject_type_get_repotype (L, G_TYPE_VALUE, NULL); - lua_gobject_record_2c (L, 1, &value, FALSE, FALSE, FALSE, FALSE); - if (get_mode) - { - /* Get fundamental from value. */ - GIObjectInfoGetValueFunction get_value = - lua_touserdata (L, lua_upvalueindex (1)); - obj = get_value (value); - lua_gobject_object_2lua (L, obj, FALSE, FALSE); - return 1; - } - else - { - /* Set fundamental to value. */ - GIObjectInfoSetValueFunction set_value = - lua_touserdata (L, lua_upvalueindex (2)); - obj = lua_gobject_object_2c (L, 3, G_TYPE_INVALID, FALSE, FALSE, FALSE); - set_value (value, obj); - return 0; - } + gpointer obj; + gboolean get_mode = lua_isnone(L, 3); + GValue *value; + lua_gobject_type_get_repotype(L, G_TYPE_VALUE, NULL); + lua_gobject_record_2c(L, 1, &value, FALSE, FALSE, FALSE, FALSE); + if (get_mode) { + /* Get fundamental from value. */ + GIObjectInfoGetValueFunction get_value = + lua_touserdata(L, lua_upvalueindex(1)); + obj = get_value(value); + lua_gobject_object_2lua(L, obj, FALSE, FALSE); + return 1; + } else { + /* Set fundamental to value. */ + GIObjectInfoSetValueFunction set_value = + lua_touserdata(L, lua_upvalueindex(2)); + obj = lua_gobject_object_2c(L, 3, G_TYPE_INVALID, FALSE, FALSE, FALSE); + set_value(value, obj); + return 0; + } } -/* Creates marshaller closure for specified fundamental object type. - If specified object does not have custom setvalue/getvalue - functions registered, returns nil. Signature is: - marshaller = marshal.fundamental(gtype) */ +/* Creates marshaller closure for specified fundamental object type. If specified object does not have custom setvalue/getvalue functions registered, returns nil. Signature is: marshaller = marshal.fundamental(gtype) */ static int -marshal_fundamental (lua_State *L) +marshal_fundamental(lua_State *L) { - /* Find associated baseinfo. */ - GIBaseInfo *info = gi_repository_find_by_gtype (lua_gobject_gi_get_repository (), - lua_gobject_type_get_gtype (L, 1)); - if (info) - { - lua_gobject_gi_info_new (L, info); - if (GI_IS_OBJECT_INFO (info) && gi_object_info_get_fundamental (GI_OBJECT_INFO (info))) - { - GIObjectInfoGetValueFunction get_value = - lua_gobject_object_get_function_ptr (GI_OBJECT_INFO (info), - gi_object_info_get_get_value_function_name); - GIObjectInfoSetValueFunction set_value = - lua_gobject_object_get_function_ptr (GI_OBJECT_INFO (info), - gi_object_info_get_set_value_function_name); - if (get_value && set_value) - { - lua_pushlightuserdata (L, get_value); - lua_pushlightuserdata (L, set_value); - lua_pushcclosure (L, marshal_fundamental_marshaller, 2); - return 1; - } + /* Find associated baseinfo. */ + GIBaseInfo *info = gi_repository_find_by_gtype(lua_gobject_gi_get_repository(), + lua_gobject_type_get_gtype(L, 1)); + if (info) { + lua_gobject_gi_info_new(L, info); + if (GI_IS_OBJECT_INFO(info) && + gi_object_info_get_fundamental(GI_OBJECT_INFO(info))) { + GIObjectInfoGetValueFunction get_value = + lua_gobject_object_get_function_ptr(GI_OBJECT_INFO(info), + gi_object_info_get_get_value_function_name); + GIObjectInfoSetValueFunction set_value = + lua_gobject_object_get_function_ptr(GI_OBJECT_INFO(info), + gi_object_info_get_set_value_function_name); + if (get_value && set_value) { + lua_pushlightuserdata(L, get_value); + lua_pushlightuserdata(L, set_value); + lua_pushcclosure(L, marshal_fundamental_marshaller, 2); + return 1; + } + } } - } - lua_pushnil (L); - return 1; + lua_pushnil(L); + return 1; } -/* Creates or marshalls content of GIArgument to/from lua according to - specified typeinfo. - arg, ptr = marshal.argument() - value = marshal.argument(arg, typeinfo, transfer) - marshal.argument(arg, typeinfo, transfer, value) */ +/* Creates or marshalls content of GIArgument to/from lua according to specified typeinfo. + arg, ptr = marshal.argument() + value = marshal.argument(arg, typeinfo, transfer) + marshal.argument(arg, typeinfo, transfer, value) */ static int -marshal_argument (lua_State *L) +marshal_argument(lua_State *L) { - GITypeInfo **info; - GITransfer transfer; - GIArgument *arg; - - if (lua_isnone (L, 1)) - { - /* Create new argument userdata. */ - GIArgument *arg = lua_newuserdata (L, sizeof (*arg)); - memset (arg, 0, sizeof (*arg)); - lua_pushlightuserdata (L, arg); - return 2; - } - - arg = lua_touserdata (L, 1); - info = luaL_checkudata (L, 2, LUA_GOBJECT_GI_INFO); - transfer = luaL_checkoption (L, 3, transfers[0], transfers); - if (lua_isnone (L, 4)) - { - lua_gobject_marshal_2lua (L, *info, NULL, GI_DIRECTION_IN, transfer, arg, + GITypeInfo **info; + GITransfer transfer; + GIArgument *arg; + + if (lua_isnone(L, 1)) { + /* Create new argument userdata. */ + GIArgument *arg = lua_newuserdata(L, sizeof(*arg)); + memset(arg, 0, sizeof(*arg)); + lua_pushlightuserdata(L, arg); + return 2; + } + + arg = lua_touserdata(L, 1); + info = luaL_checkudata(L, 2, LUA_GOBJECT_GI_INFO); + transfer = luaL_checkoption(L, 3, transfers[0], transfers); + if (lua_isnone(L, 4)) { + lua_gobject_marshal_2lua(L, *info, NULL, GI_DIRECTION_IN, transfer, arg, 0, NULL, NULL); - return 1; - } - else - { - lua_pop (L, lua_gobject_marshal_2c (L, *info, NULL, transfer, arg, 4, - 0, NULL, NULL)); - return 0; - } + return 1; + } else { + lua_pop(L, lua_gobject_marshal_2c(L, *info, NULL, transfer, arg, 4, + 0, NULL, NULL)); + return 0; + } } static int -marshal_callback (lua_State *L) +marshal_callback(lua_State *L) { - gpointer user_data, addr; - GICallableInfo **ci; - - user_data = lua_gobject_closure_allocate (L, 1); - *lua_gobject_guard_create (L, lua_gobject_closure_destroy) = user_data; - if (lua_istable (L, 1)) - lua_gobject_callable_parse (L, 1, NULL); - else - { - ci = lua_gobject_udata_test (L, 1, LUA_GOBJECT_GI_INFO); - lua_gobject_callable_create (L, *ci, NULL); - } - addr = lua_gobject_closure_create (L, user_data, 2, FALSE); - lua_pushlightuserdata (L, addr); - return 2; + gpointer user_data, addr; + GICallableInfo **ci; + + user_data = lua_gobject_closure_allocate(L, 1); + *lua_gobject_guard_create(L, lua_gobject_closure_destroy) = user_data; + if (lua_istable(L, 1)) + lua_gobject_callable_parse(L, 1, NULL); + else { + ci = lua_gobject_udata_test(L, 1, LUA_GOBJECT_GI_INFO); + lua_gobject_callable_create(L, *ci, NULL); + } + addr = lua_gobject_closure_create(L, user_data, 2, FALSE); + lua_pushlightuserdata(L, addr); + return 2; } static void -gclosure_destroy (gpointer user_data, GClosure *closure) +gclosure_destroy(gpointer user_data, GClosure *closure) { - (void) closure; - lua_gobject_closure_destroy (user_data); + (void) closure; + lua_gobject_closure_destroy(user_data); } -/* Workaround for incorrectly annotated g_closure_invoke. Since it is - pretty performance-sensitive, it is implemented here in native code - instead of creating overlay with custom ffi for it. */ +/* Workaround for incorrectly annotated g_closure_invoke. Since it is pretty performance-sensitive, it is implemented here in native code instead of creating overlay with custom ffi for it. */ static int -marshal_closure_invoke (lua_State *L) +marshal_closure_invoke(lua_State *L) { - GClosure *closure; - GValue *result, *params; - gint n_params, i; - - lua_gobject_type_get_repotype (L, G_TYPE_CLOSURE, NULL); - lua_gobject_record_2c (L, 1, &closure, FALSE, FALSE, FALSE, FALSE); - - lua_gobject_type_get_repotype (L, G_TYPE_VALUE, NULL); - lua_pushvalue (L, -1); - lua_gobject_record_2c (L, 2, &result, FALSE, FALSE, FALSE, FALSE); - - luaL_checktype (L, 3, LUA_TTABLE); - n_params = lua_objlen (L, 3); - - params = g_newa (GValue, n_params); - memset (params, 0, sizeof (GValue) * n_params); - for (i = 0; i < n_params; i++) - { - lua_pushinteger (L, i + 1); - lua_gettable (L, 3); - lua_pushvalue (L, -2); - lua_gobject_record_2c (L, -2, ¶ms[i], TRUE, FALSE, FALSE, FALSE); - lua_pop (L, 1); - } - - g_closure_invoke (closure, result, n_params, params, lua_touserdata (L, 4)); - return 0; + GClosure *closure; + GValue *result, *params; + gint n_params, i; + + lua_gobject_type_get_repotype(L, G_TYPE_CLOSURE, NULL); + lua_gobject_record_2c(L, 1, &closure, FALSE, FALSE, FALSE, FALSE); + + lua_gobject_type_get_repotype(L, G_TYPE_VALUE, NULL); + lua_pushvalue(L, -1); + lua_gobject_record_2c(L, 2, &result, FALSE, FALSE, FALSE, FALSE); + + luaL_checktype(L, 3, LUA_TTABLE); + n_params = lua_objlen(L, 3); + + params = g_newa(GValue, n_params); + memset(params, 0, sizeof(GValue) * n_params); + for (i = 0; i < n_params; i++) { + lua_pushinteger(L, i + 1); + lua_gettable(L, 3); + lua_pushvalue(L, -2); + lua_gobject_record_2c(L, -2, ¶ms[i], TRUE, FALSE, FALSE, FALSE); + lua_pop(L, 1); + } + + g_closure_invoke(closure, result, n_params, params, lua_touserdata(L, 4)); + return 0; } -/* This is workaround for missing glib function, which should look - like this: +/* This is workaround for missing glib function, which should look like this: - void g_closure_set_marshal_with_data (GClosure *closure, - GClosureMarshal marshal, - gpointer user_data, - GDestroyNotify destroy_notify); +void g_closure_set_marshal_with_data( + GClosure *closure, + GClosureMarshal marshal, + gpointer user_data, + GDestroyNotify destroy_notify); - Such method would be introspectable. -*/ +Such a method would be introspectable. */ static int -marshal_closure_set_marshal (lua_State *L) +marshal_closure_set_marshal(lua_State *L) { - GClosure *closure; - gpointer user_data; - GClosureMarshal marshal; - GIBaseInfo *ci; - - ci = gi_repository_find_by_name (lua_gobject_gi_get_repository (), "GObject", "ClosureMarshal"); - lua_gobject_type_get_repotype (L, G_TYPE_CLOSURE, NULL); - lua_gobject_record_2c (L, 1, &closure, FALSE, FALSE, FALSE, FALSE); - user_data = lua_gobject_closure_allocate (L, 1); - lua_gobject_callable_create (L, GI_CALLABLE_INFO (ci), NULL); - marshal = lua_gobject_closure_create (L, user_data, 2, FALSE); - g_closure_set_marshal (closure, marshal); - g_closure_add_invalidate_notifier (closure, user_data, gclosure_destroy); - return 0; + GClosure *closure; + gpointer user_data; + GClosureMarshal marshal; + GIBaseInfo *ci; + + ci = gi_repository_find_by_name(lua_gobject_gi_get_repository(), "GObject", "ClosureMarshal"); + lua_gobject_type_get_repotype(L, G_TYPE_CLOSURE, NULL); + lua_gobject_record_2c(L, 1, &closure, FALSE, FALSE, FALSE, FALSE); + user_data = lua_gobject_closure_allocate(L, 1); + lua_gobject_callable_create(L, GI_CALLABLE_INFO(ci), NULL); + marshal = lua_gobject_closure_create(L, user_data, 2, FALSE); + g_closure_set_marshal(closure, marshal); + g_closure_add_invalidate_notifier(closure, user_data, gclosure_destroy); + return 0; } /* Calculates size and alignment of specified type. - size, align = marshal.typeinfo(tiinfo) */ + size, align = marshal.typeinfo(tiinfo) */ static int -marshal_typeinfo (lua_State *L) +marshal_typeinfo(lua_State *L) { - GIBaseInfo **info = luaL_checkudata (L, 1, LUA_GOBJECT_GI_INFO); - switch (gi_type_info_get_tag (GI_TYPE_INFO (*info))) - { -#define HANDLE_INT(upper, type) \ - case GI_TYPE_TAG_ ## upper: \ - { \ - struct Test { char offender; type examined; }; \ - lua_pushinteger (L, sizeof (type)); \ - lua_pushinteger (L, G_STRUCT_OFFSET (struct Test, examined)); \ - } \ - break - - HANDLE_INT (VOID, gpointer); - HANDLE_INT (BOOLEAN, gboolean); - HANDLE_INT (INT8, gint8); - HANDLE_INT (UINT8, guint8); - HANDLE_INT (INT16, gint16); - HANDLE_INT (UINT16, guint16); - HANDLE_INT (INT32, gint32); - HANDLE_INT (UINT32, guint32); - HANDLE_INT (INT64, gint64); - HANDLE_INT (UINT64, guint64); - HANDLE_INT (FLOAT, gfloat); - HANDLE_INT (DOUBLE, gdouble); - HANDLE_INT (GTYPE, GType); - HANDLE_INT (UTF8, const gchar *); - HANDLE_INT (FILENAME, const gchar *); - HANDLE_INT (UNICHAR, gunichar); + GIBaseInfo **info = luaL_checkudata(L, 1, LUA_GOBJECT_GI_INFO); + switch (gi_type_info_get_tag(GI_TYPE_INFO(*info))) + { +#define HANDLE_INT(upper, type) \ + case GI_TYPE_TAG_ ## upper: \ + { \ + struct Test { char offender; type examined; }; \ + lua_pushinteger(L, sizeof(type)); \ + lua_pushinteger(L, G_STRUCT_OFFSET(struct Test, examined)); \ + } \ + break + + HANDLE_INT(VOID, gpointer); + HANDLE_INT(BOOLEAN, gboolean); + HANDLE_INT(INT8, gint8); + HANDLE_INT(UINT8, guint8); + HANDLE_INT(INT16, gint16); + HANDLE_INT(UINT16, guint16); + HANDLE_INT(INT32, gint32); + HANDLE_INT(UINT32, guint32); + HANDLE_INT(INT64, gint64); + HANDLE_INT(UINT64, guint64); + HANDLE_INT(FLOAT, gfloat); + HANDLE_INT(DOUBLE, gdouble); + HANDLE_INT(GTYPE, GType); + HANDLE_INT(UTF8, const gchar *); + HANDLE_INT(FILENAME, const gchar *); + HANDLE_INT(UNICHAR, gunichar); #undef HANDLE_INT - default: - return luaL_argerror (L, 1, "bad typeinfo"); - } + default: + return luaL_argerror(L, 1, "bad typeinfo"); + } - return 2; + return 2; } static const struct luaL_Reg marshal_api_reg[] = { - { "container", marshal_container }, - { "fundamental", marshal_fundamental }, - { "argument", marshal_argument }, - { "callback", marshal_callback }, - { "closure_set_marshal", marshal_closure_set_marshal }, - { "closure_invoke", marshal_closure_invoke }, - { "typeinfo", marshal_typeinfo }, - { NULL, NULL } + { "container", marshal_container }, + { "fundamental", marshal_fundamental }, + { "argument", marshal_argument }, + { "callback", marshal_callback }, + { "closure_set_marshal", marshal_closure_set_marshal }, + { "closure_invoke", marshal_closure_invoke }, + { "typeinfo", marshal_typeinfo }, + { NULL, NULL } }; void -lua_gobject_marshal_init (lua_State *L) +lua_gobject_marshal_init(lua_State *L) { - /* Create 'marshal' API table in main core API table. */ - lua_newtable (L); - luaL_register (L, NULL, marshal_api_reg); - lua_setfield (L, -2, "marshal"); + /* Create 'marshal' API table in main core API table. */ + lua_newtable(L); + luaL_register(L, NULL, marshal_api_reg); + lua_setfield(L, -2, "marshal"); } diff --git a/LuaGObject/namespace.lua b/LuaGObject/namespace.lua index 8efe186f..5a66d7af 100644 --- a/LuaGObject/namespace.lua +++ b/LuaGObject/namespace.lua @@ -1,15 +1,9 @@ ------------------------------------------------------------------------------- --- --- LuaGObject Support for repository namespace --- --- Copyright (c) 2010, 2011,2016 Pavel Holejsovsky --- Licensed under the MIT license: --- http://www.opensource.org/licenses/mit-license.php --- ------------------------------------------------------------------------------- +-- LuaGObject Support for repository namespace +-- Copyright (c) 2010, 2011,2016 Pavel Holejsovsky +-- Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php local type, rawget, next, pairs, require, pcall, setmetatable, assert - = type, rawget, next, pairs, require, pcall, setmetatable, assert + = type, rawget, next, pairs, require, pcall, setmetatable, assert local package = require 'package' local core = require 'LuaGObject.core' local enum = require 'LuaGObject.enum' @@ -17,179 +11,170 @@ local component = require 'LuaGObject.component' local record = require 'LuaGObject.record' local class = require 'LuaGObject.class' --- Table containing loaders for various GI types, indexed by --- gi.InfoType constants. +-- Table containing loaders for various GI types, indexed by gi.InfoType constants. local typeloader = {} typeloader['function'] = - function(namespace, info) - return core.callable.new(info), '_function' - end + function(namespace, info) + return core.callable.new(info), '_function' + end function typeloader.constant(namespace, info) - return core.constant(info), '_constant' + return core.constant(info), '_constant' end function typeloader.enum(namespace, info) - return enum.load(info, enum.enum_mt), '_enum' + return enum.load(info, enum.enum_mt), '_enum' end function typeloader.flags(namespace, info) - return enum.load(info, enum.bitflags_mt), '_enum' + return enum.load(info, enum.bitflags_mt), '_enum' end function typeloader.struct(namespace, info) - -- Avoid exposing internal structs created for object implementations. - if not info.is_gtype_struct then - return record.load(info), '_struct' - end + -- Avoid exposing internal structs created for object implementations. + if not info.is_gtype_struct then + return record.load(info), '_struct' + end end function typeloader.union(namespace, info) - return record.load(info), '_union' + return record.load(info), '_union' end function typeloader.interface(namespace, info) - return class.load_interface(namespace, info), '_interface' + return class.load_interface(namespace, info), '_interface' end function typeloader.object(namespace, info) - return class.load_class(namespace, info), '_class' + return class.load_class(namespace, info), '_class' end -- Repo namespace metatable. local namespace = { - mt = { - _categories = { '_class', '_interface', '_struct', '_union', '_enum', - '_function', '_constant', }, - _category_mt = {}, - } + mt = { + _categories = { + '_class', '_interface', '_struct', '_union', '_enum', '_function', '_constant', + }, + _category_mt = {}, + } } --- Gets symbol of the specified namespace, if not present yet, tries to load it --- on-demand. +-- Gets symbol of the specified namespace, if not present yet, tries to load it on-demand. function namespace.mt:__index(symbol) - -- Check whether symbol is present in the metatable. - local val = namespace.mt[symbol] - if val then return val end - - -- Check, whether there is some precondition in the lazy-loading table. - local preconditions = rawget(self, '_precondition') - local precondition = preconditions and preconditions[symbol] - if precondition then - local package = preconditions[symbol] - if not preconditions[package] then - preconditions[package] = true - require('LuaGObject.override.' .. package) - preconditions[package] = nil - end - preconditions[symbol] = nil - if not next(preconditions) then self._precondition = nil end - end - - -- Check, whether symbol is already loaded. - val = component.mt._element(self, nil, symbol, namespace.mt._categories) - if val then return val end - - -- Lookup baseinfo of requested symbol in the GIRepository. - local info = core.gi[self._name][symbol] - if not info then return nil end - - -- Decide according to symbol type what to do. - local loader = typeloader[info.type] - if loader then - local category - val, category = loader(self, info) - - -- Cache the symbol in specified category in the namespace. - if val then - local cat = rawget(self, category) - if not cat then - local mt = namespace.mt._category_mt[category] - if not mt then - mt = {} - namespace.mt._category_mt[category] = mt - end - cat = setmetatable({ _namespace = self }, mt) - self[category] = cat - end - -- Store symbol into the repo, but only if it is not already - -- there. It could by added to repo as byproduct of loading - -- other symbol. - if not cat[symbol] then cat[symbol] = val end - elseif info.is_gtype_struct then - -- If we have XxxClass name, try to lookup class structure of - -- the Xxx object. - local class = (symbol:match('^(%w+)Class$') - or symbol:match('^(%w+)Iface$') - or symbol:match('^(%w+)Interface$')) - if class then - class = self[class] - if class then val = class._class end - end - end - else - val = info - end - return val + -- Check whether symbol is present in the metatable. + local val = namespace.mt[symbol] + if val then return val end + + -- Check, whether there is some precondition in the lazy-loading table. + local preconditions = rawget(self, '_precondition') + local precondition = preconditions and preconditions[symbol] + if precondition then + local package = preconditions[symbol] + if not preconditions[package] then + preconditions[package] = true + require('LuaGObject.override.' .. package) + preconditions[package] = nil + end + preconditions[symbol] = nil + if not next(preconditions) then self._precondition = nil end + end + + -- Check, whether symbol is already loaded. + val = component.mt._element(self, nil, symbol, namespace.mt._categories) + if val then return val end + + -- Lookup baseinfo of requested symbol in the GIRepository. + local info = core.gi[self._name][symbol] + if not info then return nil end + + -- Decide according to symbol type what to do. + local loader = typeloader[info.type] + if loader then + local category + val, category = loader(self, info) + + -- Cache the symbol in specified category in the namespace. + if val then + local cat = rawget(self, category) + if not cat then + local mt = namespace.mt._category_mt[category] + if not mt then + mt = {} + namespace.mt._category_mt[category] = mt + end + cat = setmetatable({ _namespace = self }, mt) + self[category] = cat + end + -- Store symbol into the repo, but only if it is not already there. It could by added to repo as byproduct of loading other symbol. + if not cat[symbol] then cat[symbol] = val end + elseif info.is_gtype_struct then + -- If we have XxxClass name, try to lookup class structure of the Xxx object. + local class = (symbol:match('^(%w+)Class$') + or symbol:match('^(%w+)Iface$') + or symbol:match('^(%w+)Interface$')) + if class then + class = self[class] + if class then val = class._class end + end + end + else + val = info + end + return val end -- Resolves everything in the namespace by iterating through it. function namespace.mt:_resolve(recurse) - -- Iterate through all items in the namespace and dereference them, - -- which causes them to be loaded in and cached inside the namespace - -- table. - local gi_ns = core.gi[self._name] - for i = 1, #gi_ns do - local ok, component = pcall(function() return self[gi_ns[i].name] end) - if ok and recurse and type(component) == 'table' then - local resolve = component._resolve - if resolve then resolve(component, recurse) end - end - end - return self + -- Iterate through all items in the namespace and dereference them, which causes them to be loaded in and cached inside the namespace table. + local gi_ns = core.gi[self._name] + for i = 1, #gi_ns do + local ok, component = pcall(function() return self[gi_ns[i].name] end) + if ok and recurse and type(component) == 'table' then + local resolve = component._resolve + if resolve then resolve(component, recurse) end + end + end + return self end --- Makes sure that the namespace (optionally with requested version) --- is properly loaded. +-- Makes sure that the namespace (optionally with requested version) is properly loaded. function namespace.require(name, version) - -- Load the namespace info for GIRepository. This also verifies - -- whether requested version can be loaded. - local ns_info = assert(core.gi.require(name, version)) - - -- If the repository table does not exist yet, create it. - local ns = rawget(core.repo, name) - if not ns then - ns = setmetatable({ _name = name, _version = ns_info.version, - _dependencies = ns_info.dependencies }, - namespace.mt) - core.repo[name] = ns - - -- Make sure that all dependent namespaces are also loaded. - for name, version in pairs(ns._dependencies or {}) do - namespace.require(name, version) - end - - -- Try to load override, if it is present. - local override_name = 'LuaGObject.override.' .. ns._name - local ok, msg = pcall(require, override_name) - if not ok then - -- Try parsing message; if it is something different than - -- "module xxx not found", then attempt to load again and let - -- the exception fly out. - if not msg:find("module '" .. override_name .. "' not found:", - 1, true) then - package.loaded[override_name] = nil - require(override_name) - end - end - if ok and type(msg) == "string" then - -- It's an error message for something that does not want to be - -- re-loaded, see e.g. the call to Gtk.init_check() in Gtk.lua. - error(msg) - end - end - return ns + -- Load the namespace info for GIRepository. This also verifies whether requested version can be loaded. + local ns_info = assert(core.gi.require(name, version)) + + -- If the repository table does not exist yet, create it. + local ns = rawget(core.repo, name) + if not ns then + ns = setmetatable({ + _name = name, + _version = ns_info.version, + _dependencies = ns_info.dependencies + }, namespace.mt) + core.repo[name] = ns + + -- Make sure that all dependent namespaces are also loaded. + for name, version in pairs(ns._dependencies or {}) do + namespace.require(name, version) + end + + -- Try to load override, if it is present. + local override_name = 'LuaGObject.override.' .. ns._name + local ok, msg = pcall(require, override_name) + if not ok then + -- Try parsing message; if it is something different than "module xxx not found", then attempt to load again and let the exception fly out. + if not msg:find("module '" .. override_name .. "' not found:", + 1, true) then + package.loaded[override_name] = nil + require(override_name) + end + end + if ok and type(msg) == "string" then + -- It's an error message for something that does not want to be re-loaded, see e.g. the call to Gtk.init_check() in Gtk.lua. + error(msg) + end + end + return ns end return namespace diff --git a/LuaGObject/object.c b/LuaGObject/object.c index 023e578a..d4aaab3c 100644 --- a/LuaGObject/object.c +++ b/LuaGObject/object.c @@ -1,635 +1,592 @@ -/* - * Dynamic Lua binding to GObject using dynamic gobject-introspection. - * - * Copyright (c) 2010, 2011 Pavel Holejsovsky - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - * GObject and GTypeInstance handling. - */ +/* Dynamic Lua binding to GObject using dynamic gobject-introspection. +Copyright(c) 2010, 2011 Pavel Holejsovsky +Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php +GObject and GTypeInstance handling. */ #include #include "lua_gobject.h" -/* lightuserdata key to registry, containing table representing weak - cache of known objects. */ +/* lightuserdata key to registry, containing table representing weak cache of known objects. */ static int cache; /* lightuserdata key to registry for metatable of objects. */ static int object_mt; -/* lightuserdata key to registry, containing 'env' table, which maps - lightuserdata(obj-addr) -> obj-env-table. */ +/* lightuserdata key to registry, containing 'env' table, which maps lightuserdata(obj-addr) -> obj-env-table. */ static int env; -/* Keys in 'env' table containing quark used as object's qdata for env - and thread which is used from qdata destroy callback. */ +/* Keys in 'env' table containing quark used as object's qdata for env and thread which is used from qdata destroy callback. */ enum { - OBJECT_QDATA_ENV = 1, - OBJECT_QDATA_THREAD + OBJECT_QDATA_ENV = 1, + OBJECT_QDATA_THREAD }; /* Structure stored in GObject's qdata at OBJECT_QDATA_ENV. */ -typedef struct _ObjectData -{ - gpointer object; - gpointer state_lock; - lua_State *L; +typedef struct _ObjectData { + gpointer object; + gpointer state_lock; + lua_State *L; } ObjectData; -/* lightuserdata key to registry, containing metatable for object env - guard. */ +/* lightuserdata key to registry, containing metatable for object env guard. */ static int env_mt; /* Structure containing object_env_guard userdata. */ -typedef struct _ObjectEnvGuard -{ - gpointer object; - GQuark id; +typedef struct _ObjectEnvGuard { + gpointer object; + GQuark id; } ObjectEnvGuard; -/* Checks that given narg is object type and returns pointer to type - instance representing it. */ +/* Checks that given narg is object type and returns pointer to type instance representing it. */ static gpointer -object_check (lua_State *L, int narg) +object_check(lua_State *L, int narg) { - gpointer *obj = lua_touserdata (L, narg); - luaL_checkstack (L, 3, ""); - if (!lua_getmetatable (L, narg)) - return NULL; - lua_pushlightuserdata (L, &object_mt); - lua_rawget (L, LUA_REGISTRYINDEX); - if (!lua_equal (L, -1, -2)) - obj = NULL; - - lua_pop (L, 2); - g_assert (obj == NULL || *obj != NULL); - return obj ? *obj : NULL; + gpointer *obj = lua_touserdata(L, narg); + luaL_checkstack(L, 3, ""); + if (!lua_getmetatable(L, narg)) + return NULL; + lua_pushlightuserdata(L, &object_mt); + lua_rawget(L, LUA_REGISTRYINDEX); + if (!lua_equal(L, -1, -2)) + obj = NULL; + + lua_pop(L, 2); + g_assert(obj == NULL || *obj != NULL); + return obj ? *obj : NULL; } -/* Walks given type and tries to find the closest known match of the - object present in the repo. If found, leaves found type table on - the stack and returns real found gtype, otherwise returns - G_TYPE_INVALID. */ +/* Walks given type and tries to find the closest known match of the object present in the repo. If found, leaves found type table on the stack and returns real found gtype, otherwise returns G_TYPE_INVALID. */ static GType -object_type (lua_State *L, GType gtype) +object_type(lua_State *L, GType gtype) { - for (; gtype != G_TYPE_INVALID; gtype = g_type_parent (gtype)) - { - /* Get appropriate repo table, if present. */ - lua_gobject_type_get_repotype (L, gtype, NULL); - if (!lua_isnil (L, -1)) - break; + for (; gtype != G_TYPE_INVALID; gtype = g_type_parent(gtype)) { + /* Get appropriate repo table, if present. */ + lua_gobject_type_get_repotype(L, gtype, NULL); + if (!lua_isnil(L, -1)) + break; - lua_pop (L, 1); - } + lua_pop(L, 1); + } - return gtype; + return gtype; } -/* Throws type error for object at given argument, gtype can - optionally contain name of requested type. */ +/* Throws type error for object at given argument, gtype can optionally contain name of requested type. */ static int -object_type_error (lua_State *L, int narg, GType gtype) +object_type_error(lua_State *L, int narg, GType gtype) { - GType found_gtype; - /* Look up type table and get name from it. */ - luaL_checkstack (L, 4, ""); - found_gtype = object_type (L, gtype); - if (found_gtype != G_TYPE_INVALID) - { - lua_getfield (L, -1, "_name"); - lua_pushfstring (L, gtype == found_gtype ? "%s" : "%s(%s)", - lua_tostring (L, -1), g_type_name (gtype)); - } - else - { - if (gtype == G_TYPE_INVALID) - lua_pushliteral (L, "lua_gobject.object"); - else - lua_pushstring (L, g_type_name (gtype)); - } - - /* Create error message. */ - lua_pushstring (L, lua_typename (L, lua_type (L, narg))); - lua_pushfstring (L, "%s expected, got %s", lua_tostring (L, -2), - lua_tostring (L, -1)); - return luaL_argerror (L, narg, lua_tostring (L, -1)); + GType found_gtype; + /* Look up type table and get name from it. */ + luaL_checkstack(L, 4, ""); + found_gtype = object_type(L, gtype); + if (found_gtype != G_TYPE_INVALID) { + lua_getfield(L, -1, "_name"); + lua_pushfstring(L, gtype == found_gtype ? "%s" : "%s(%s)", + lua_tostring(L, -1), g_type_name(gtype)); + } else { + if (gtype == G_TYPE_INVALID) + lua_pushliteral(L, "lua_gobject.object"); + else + lua_pushstring(L, g_type_name(gtype)); + } + + /* Create error message. */ + lua_pushstring(L, lua_typename(L, lua_type(L, narg))); + lua_pushfstring(L, "%s expected, got %s", lua_tostring(L, -2), + lua_tostring(L, -1)); + return luaL_argerror(L, narg, lua_tostring(L, -1)); } static gpointer -object_get (lua_State *L, int narg) +object_get(lua_State *L, int narg) { - gpointer obj = object_check (L, narg); - if (G_UNLIKELY (!obj)) - object_type_error (L, narg, G_TYPE_INVALID); - return obj; + gpointer obj = object_check(L, narg); + if (G_UNLIKELY(!obj)) + object_type_error(L, narg, G_TYPE_INVALID); + return obj; } -/* This is workaround method for broken - gi_object_info_get_*_function_pointer() in GI 1.32.0. (see - https://bugzilla.gnome.org/show_bug.cgi?id=673282) */ +/* This is workaround method for broken gi_object_info_get_*_function_pointer() in GI 1.32.0.(see https://bugzilla.gnome.org/show_bug.cgi?id=673282) */ gpointer -lua_gobject_object_get_function_ptr (GIObjectInfo *info, - const gchar *(*getter)(GIObjectInfo *)) +lua_gobject_object_get_function_ptr(GIObjectInfo *info, + const gchar *(*getter)(GIObjectInfo *)) { - gpointer func = NULL; - gi_base_info_ref (info); - while (info != NULL) - { - GIBaseInfo *parent; - const gchar *func_name; - - /* Try to get the name and the symbol. */ - func_name = getter (info); - if (func_name && gi_typelib_symbol (gi_base_info_get_typelib (GI_BASE_INFO (info)), - func_name, &func)) - { - gi_base_info_unref (info); - break; + gpointer func = NULL; + gi_base_info_ref(info); + while (info != NULL) { + GIBaseInfo *parent; + const gchar *func_name; + + /* Try to get the name and the symbol. */ + func_name = getter(info); + if (func_name && + gi_typelib_symbol(gi_base_info_get_typelib(GI_BASE_INFO(info)), + func_name, &func)) { + gi_base_info_unref(info); + break; + } + + /* Iterate to the parent info. */ + parent = GI_BASE_INFO(gi_object_info_get_parent(info)); + gi_base_info_unref(info); + info = GI_OBJECT_INFO(parent); } - /* Iterate to the parent info. */ - parent = GI_BASE_INFO (gi_object_info_get_parent (info)); - gi_base_info_unref (info); - info = GI_OBJECT_INFO (parent); - } - - return func; + return func; } /* Retrieves requested typetable function for the object. */ static gpointer -object_load_function (lua_State *L, GType gtype, const gchar *name) +object_load_function(lua_State *L, GType gtype, const gchar *name) { - gpointer func = NULL; - if (object_type (L, gtype) != G_TYPE_INVALID) - { - func = lua_gobject_gi_load_function (L, -1, name); - lua_pop (L, 1); - } - return func; + gpointer func = NULL; + if (object_type(L, gtype) != G_TYPE_INVALID) { + func = lua_gobject_gi_load_function(L, -1, name); + lua_pop(L, 1); + } + return func; } /* Adds one reference to the object, returns TRUE if succeded. */ static gboolean -object_refsink (lua_State *L, gpointer obj, gboolean no_sink) +object_refsink(lua_State *L, gpointer obj, gboolean no_sink) { - GType gtype = G_TYPE_FROM_INSTANCE (obj); - if (G_TYPE_IS_OBJECT (gtype)) - { - if (G_UNLIKELY (no_sink)) - g_object_ref (obj); - else - g_object_ref_sink (obj); - return TRUE; - } - - /* Check whether object has registered fundamental 'ref' - function. */ - GIObjectInfo *info = GI_OBJECT_INFO (gi_repository_find_by_gtype (lua_gobject_gi_get_repository (), gtype)); - if (info == NULL) - info = GI_OBJECT_INFO (gi_repository_find_by_gtype (lua_gobject_gi_get_repository (), G_TYPE_FUNDAMENTAL (gtype))); - if (info != NULL && gi_object_info_get_fundamental (info)) - { - GIObjectInfoRefFunction ref = - lua_gobject_object_get_function_ptr (info, gi_object_info_get_ref_function_name); - gi_base_info_unref (info); - if (ref != NULL) - { - ref (obj); - return TRUE; + GType gtype = G_TYPE_FROM_INSTANCE(obj); + if (G_TYPE_IS_OBJECT(gtype)) { + if (G_UNLIKELY(no_sink)) + g_object_ref(obj); + else + g_object_ref_sink(obj); + return TRUE; } - } - - /* Finally check custom _refsink method in typetable. */ - gpointer (*refsink_func)(gpointer) = - object_load_function (L, gtype, "_refsink"); - if (refsink_func) - { - refsink_func (obj); - return TRUE; - } - - /* There is no known wasy how to ref this kind of object. But this - typically appears when handling GParamSpec, and GParamSpec - handling generally works fine even without ref/unref, so the - warnings produced are generally junk, so disabled until a way to - handle ParamSpec properly is found. */ + + /* Check whether object has registered fundamental 'ref' function. */ + GIObjectInfo *info = GI_OBJECT_INFO( + gi_repository_find_by_gtype(lua_gobject_gi_get_repository(), gtype)); + if (info == NULL) + info = GI_OBJECT_INFO(gi_repository_find_by_gtype( + lua_gobject_gi_get_repository(), G_TYPE_FUNDAMENTAL(gtype))); + if (info != NULL && gi_object_info_get_fundamental(info)) { + GIObjectInfoRefFunction ref = + lua_gobject_object_get_function_ptr(info, + gi_object_info_get_ref_function_name); + gi_base_info_unref(info); + if (ref != NULL) { + ref(obj); + return TRUE; + } + } + + /* Finally check custom _refsink method in typetable. */ + gpointer(*refsink_func)(gpointer) = + object_load_function(L, gtype, "_refsink"); + if (refsink_func) { + refsink_func(obj); + return TRUE; + } + + /* There is no known easy to ref this kind of object. But this typically appears when handling GParamSpec, and GParamSpec handling generally works fine even without ref/unref, so the warnings produced are generally junk, so disabled until a way to handle ParamSpec properly is found. */ #if 0 - g_warning ("no way to ref type `%s'", g_type_name (gtype)); + g_warning("no way to ref type `%s'", g_type_name(gtype)); #endif - return FALSE; + return FALSE; } /* Removes one reference from the object. */ static void -object_unref (lua_State *L, gpointer obj) +object_unref(lua_State *L, gpointer obj) { - GType gtype = G_TYPE_FROM_INSTANCE (obj); - if (G_TYPE_IS_OBJECT (gtype)) - { - g_object_unref (obj); - return; - } - - /* Some other fundamental type, check, whether it has registered - custom unref method. */ - GIObjectInfo *info = GI_OBJECT_INFO (gi_repository_find_by_gtype (lua_gobject_gi_get_repository (), gtype)); - if (info == NULL) - info = GI_OBJECT_INFO (gi_repository_find_by_gtype (lua_gobject_gi_get_repository (), G_TYPE_FUNDAMENTAL (gtype))); - if (info != NULL && gi_object_info_get_fundamental (info)) - { - GIObjectInfoUnrefFunction unref = - lua_gobject_object_get_function_ptr (info, gi_object_info_get_unref_function_name); - gi_base_info_unref (info); - if (unref != NULL) - { - unref (obj); - return; + GType gtype = G_TYPE_FROM_INSTANCE(obj); + if (G_TYPE_IS_OBJECT(gtype)) { + g_object_unref(obj); + return; + } + + /* Some other fundamental type, check, whether it has registered + custom unref method. */ + GIObjectInfo *info = GI_OBJECT_INFO(gi_repository_find_by_gtype( + lua_gobject_gi_get_repository(), gtype)); + if (info == NULL) + info = GI_OBJECT_INFO(gi_repository_find_by_gtype( + lua_gobject_gi_get_repository(), G_TYPE_FUNDAMENTAL(gtype))); + if (info != NULL && gi_object_info_get_fundamental(info)) { + GIObjectInfoUnrefFunction unref = + lua_gobject_object_get_function_ptr(info, + gi_object_info_get_unref_function_name); + gi_base_info_unref(info); + if (unref != NULL) { + unref(obj); + return; + } } - } - void (*unref_func)(gpointer) = object_load_function (L, gtype, "_unref"); - if (unref_func) - { - unref_func (obj); - return; - } + void(*unref_func)(gpointer) = object_load_function(L, gtype, "_unref"); + if (unref_func) { + unref_func(obj); + return; + } #if 0 - g_warning ("no way to unref type `%s'", g_type_name (gtype)); + g_warning("no way to unref type `%s'", g_type_name(gtype)); #endif } static int -object_gc (lua_State *L) +object_gc(lua_State *L) { - object_unref (L, object_get (L, 1)); + object_unref(L, object_get(L, 1)); - /* Unset the metatable / make the object unusable */ - lua_pushnil (L); - lua_setmetatable (L, 1); - return 0; + /* Unset the metatable / make the object unusable */ + lua_pushnil(L); + lua_setmetatable(L, 1); + return 0; } static int -object_tostring (lua_State *L) +object_tostring(lua_State *L) { - gpointer obj = object_get (L, 1); - GType gtype = G_TYPE_FROM_INSTANCE (obj); - lua_getfenv (L, 1); - if (lua_isnil (L, -1)) - lua_pushliteral (L, ""); - else - { - lua_getfield (L, -1, "_tostring"); - if (!lua_isnil (L, -1)) - { - lua_pushvalue (L, 1); - lua_call (L, 1, 1); - return 1; - } - lua_getfield (L, -2, "_name"); - } - lua_pushfstring (L, "lua_gobject.obj %p:%s(%s)", obj, lua_tostring (L, -1), - g_type_name (gtype)); - return 1; + gpointer obj = object_get(L, 1); + GType gtype = G_TYPE_FROM_INSTANCE(obj); + lua_getfenv(L, 1); + if (lua_isnil(L, -1)) + lua_pushliteral(L, ""); + else { + lua_getfield(L, -1, "_tostring"); + if (!lua_isnil(L, -1)) { + lua_pushvalue(L, 1); + lua_call(L, 1, 1); + return 1; + } + lua_getfield(L, -2, "_name"); + } + lua_pushfstring(L, "lua_gobject.obj %p:%s(%s)", obj, lua_tostring(L, -1), + g_type_name(gtype)); + return 1; } gpointer -lua_gobject_object_2c (lua_State *L, int narg, GType gtype, gboolean optional, - gboolean nothrow, gboolean transfer) +lua_gobject_object_2c(lua_State *L, int narg, GType gtype, gboolean optional, + gboolean nothrow, gboolean transfer) { - gpointer obj; + gpointer obj; - /* Check for nil. */ - if (optional && lua_isnoneornil (L, narg)) - return NULL; + /* Check for nil. */ + if (optional && lua_isnoneornil(L, narg)) + return NULL; - /* Get instance and perform type check. */ - obj = object_check (L, narg); - if (!nothrow - && (!obj || (gtype != G_TYPE_INVALID - && !g_type_is_a (G_TYPE_FROM_INSTANCE (obj), gtype)))) - object_type_error (L, narg, gtype); + /* Get instance and perform type check. */ + obj = object_check(L, narg); + if (!nothrow &&(!obj ||(gtype != G_TYPE_INVALID + && !g_type_is_a(G_TYPE_FROM_INSTANCE(obj), gtype)))) + object_type_error(L, narg, gtype); - if (transfer) - object_refsink (L, obj, FALSE); + if (transfer) + object_refsink(L, obj, FALSE); - return obj; + return obj; } int -lua_gobject_object_2lua (lua_State *L, gpointer obj, gboolean own, gboolean no_sink) +lua_gobject_object_2lua(lua_State *L, gpointer obj, gboolean own, gboolean no_sink) { - /* NULL pointer results in nil. */ - if (!obj) - { - lua_pushnil (L); - return 1; - } - - /* Check, whether the object is already created (in the cache). */ - luaL_checkstack (L, 6, ""); - lua_pushlightuserdata (L, &cache); - lua_rawget (L, LUA_REGISTRYINDEX); - lua_pushlightuserdata (L, obj); - lua_rawget (L, -2); - if (!lua_isnil (L, -1)) - { - /* Use the object from the cache. */ - lua_replace (L, -2); - - /* If the object was already owned, remove one reference, - because our proxy always keeps only one reference, which we - already have. */ - if (own) - object_unref (L, obj); - return 1; - } - - /* Create new userdata object. */ - *(gpointer *) lua_newuserdata (L, sizeof (obj)) = obj; - lua_pushlightuserdata (L, &object_mt); - lua_rawget (L, LUA_REGISTRYINDEX); - lua_setmetatable (L, -2); - object_type (L, G_TYPE_FROM_INSTANCE (obj)); - lua_setfenv (L, -2); - - - /* Store newly created userdata proxy into cache. */ - lua_pushlightuserdata (L, obj); - lua_pushvalue (L, -2); - lua_rawset (L, -5); - - /* Stack cleanup, remove unnecessary cache and nil under userdata. */ - lua_replace (L, -3); - lua_pop (L, 1); - - /* If we don't own the object, take its ownership (and also remove - floating reference if there is any). */ - if (!own) - object_refsink (L, obj, no_sink); - - return 1; + /* NULL pointer results in nil. */ + if (!obj) { + lua_pushnil(L); + return 1; + } + + /* Check, whether the object is already created(in the cache). */ + luaL_checkstack(L, 6, ""); + lua_pushlightuserdata(L, &cache); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushlightuserdata(L, obj); + lua_rawget(L, -2); + if (!lua_isnil(L, -1)) + { + /* Use the object from the cache. */ + lua_replace(L, -2); + + /* If the object was already owned, remove one reference, because our proxy always keeps only one reference, which we already have. */ + if (own) + object_unref(L, obj); + return 1; + } + + /* Create new userdata object. */ + *(gpointer *) lua_newuserdata(L, sizeof(obj)) = obj; + lua_pushlightuserdata(L, &object_mt); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + object_type(L, G_TYPE_FROM_INSTANCE(obj)); + lua_setfenv(L, -2); + + + /* Store newly created userdata proxy into cache. */ + lua_pushlightuserdata(L, obj); + lua_pushvalue(L, -2); + lua_rawset(L, -5); + + /* Stack cleanup, remove unnecessary cache and nil under userdata. */ + lua_replace(L, -3); + lua_pop(L, 1); + + /* If we don't own the object, take its ownership(and also remove floating reference if there is any). */ + if (!own) + object_refsink(L, obj, no_sink); + + return 1; } /* Worker method for __index and __newindex implementation. */ static int -object_access (lua_State *L) +object_access(lua_State *L) { - gboolean getmode = lua_isnone (L, 3); - - /* Check that 1st arg is an object and invoke one of the forms: - result = type:_access(objectinstance, name) - type:_access(objectinstance, name, val) */ - object_get (L, 1); - lua_getfenv (L, 1); - return lua_gobject_marshal_access (L, getmode, 1, 2, 3); + gboolean getmode = lua_isnone(L, 3); + + /* Check that 1st arg is an object and invoke one of the forms: + result = type:_access(objectinstance, name) + type:_access(objectinstance, name, val) */ + object_get(L, 1); + lua_getfenv(L, 1); + return lua_gobject_marshal_access(L, getmode, 1, 2, 3); } /* Registration table. */ static const luaL_Reg object_mt_reg[] = { - { "__gc", object_gc }, - { "__tostring", object_tostring }, - { "__index", object_access }, - { "__newindex", object_access }, - { NULL, NULL } + { "__gc", object_gc }, + { "__tostring", object_tostring }, + { "__index", object_access }, + { "__newindex", object_access }, + { NULL, NULL } }; static const char *const query_mode[] = { "addr", "repo", NULL }; /* Queries for assorted instance properties. Lua-side prototype: - res = object.query(objectinstance, mode [, iface-gtype]) - Supported mode strings are: - 'repo': returns repotable for this instance. - 'addr': returns lightuserdata with pointer to the object. */ +res = object.query(objectinstance, mode [, iface-gtype]) +Supported mode strings are: +'repo': returns repotable for this instance. +'addr': returns lightuserdata with pointer to the object. */ static int -object_query (lua_State *L) +object_query(lua_State *L) { - gpointer object = object_check (L, 1); - if (object) - { - int mode = luaL_checkoption (L, 2, query_mode[0], query_mode); - if (mode == 0) - lua_pushlightuserdata (L, object); - else - lua_getfenv (L, 1); - return 1; - } - return 0; + gpointer object = object_check(L, 1); + if (object) { + int mode = luaL_checkoption(L, 2, query_mode[0], query_mode); + if (mode == 0) + lua_pushlightuserdata(L, object); + else + lua_getfenv(L, 1); + return 1; + } + return 0; } /* Object field accessor. Lua-side prototypes: - res = object.field(objectinstance, gi.fieldinfo) - object.field(objectinstance, gi.fieldinfo, newvalue) */ +res = object.field(objectinstance, gi.fieldinfo) +object.field(objectinstance, gi.fieldinfo, newvalue) */ static int -object_field (lua_State *L) +object_field(lua_State *L) { - /* Check, whether we are doing set or get operation. */ - gboolean getmode = lua_isnone (L, 3); + /* Check, whether we are doing set or get operation. */ + gboolean getmode = lua_isnone(L, 3); - /* Get object instance. */ - gpointer object = object_get (L, 1); + /* Get object instance. */ + gpointer object = object_get(L, 1); - /* Call field marshalling worker. */ - lua_getfenv (L, 1); - return lua_gobject_marshal_field (L, object, getmode, 1, 2, 3); + /* Call field marshalling worker. */ + lua_getfenv(L, 1); + return lua_gobject_marshal_field(L, object, getmode, 1, 2, 3); } static void -object_data_destroy (gpointer user_data) +object_data_destroy(gpointer user_data) { - ObjectData *data = user_data; - lua_State *L = data->L; - lua_gobject_state_enter (data->state_lock); - luaL_checkstack (L, 4, NULL); - - /* Release 'obj' entry from 'env' table. */ - lua_pushlightuserdata (L, &env); - lua_rawget (L, LUA_REGISTRYINDEX); - - /* Deactivate env_destroy, to avoid double destruction. */ - lua_pushlightuserdata (L, data->object); - lua_rawget (L, -2); - if (!lua_isnil (L, -1)) - *(gpointer **) lua_touserdata (L, -1) = NULL; - lua_pushlightuserdata (L, data->object); - lua_pushnil (L); - lua_rawset (L, -4); - lua_pop (L, 2); - - /* Leave the context and destroy data structure. */ - lua_gobject_state_leave (data->state_lock); - g_free (data); + ObjectData *data = user_data; + lua_State *L = data->L; + lua_gobject_state_enter(data->state_lock); + luaL_checkstack(L, 4, NULL); + + /* Release 'obj' entry from 'env' table. */ + lua_pushlightuserdata(L, &env); + lua_rawget(L, LUA_REGISTRYINDEX); + + /* Deactivate env_destroy, to avoid double destruction. */ + lua_pushlightuserdata(L, data->object); + lua_rawget(L, -2); + if (!lua_isnil(L, -1)) + *(gpointer **) lua_touserdata(L, -1) = NULL; + lua_pushlightuserdata(L, data->object); + lua_pushnil(L); + lua_rawset(L, -4); + lua_pop(L, 2); + + /* Leave the context and destroy data structure. */ + lua_gobject_state_leave(data->state_lock); + g_free(data); } static int -object_env_guard_gc (lua_State *L) +object_env_guard_gc(lua_State *L) { - ObjectEnvGuard *guard = lua_touserdata (L, -1); - g_free (g_object_steal_qdata (G_OBJECT (guard->object), guard->id)); - return 0; + ObjectEnvGuard *guard = lua_touserdata(L, -1); + g_free(g_object_steal_qdata(G_OBJECT(guard->object), guard->id)); + return 0; } /* Object environment table accessor. Lua-side prototype: - env = object.env(objectinstance) */ +env = object.env(objectinstance) */ static int -object_env (lua_State *L) +object_env(lua_State *L) { - ObjectData *data; - gpointer obj = object_get (L, 1); - if (!G_IS_OBJECT (obj)) - /* Only GObject instances can have environment. */ - return 0; - - /* Lookup 'env' table. */ - lua_pushlightuserdata (L, &env); - lua_rawget (L, LUA_REGISTRYINDEX); - lua_pushlightuserdata (L, obj); - lua_rawget (L, -2); - if (!lua_isnil (L, -1)) - /* Object's env table for the object is attached to the - controlling userdata in the 'env' table. */ - lua_getfenv (L, -1); - else - { - ObjectEnvGuard *guard; - - /* Create new table which will serve as an object env table. */ - lua_newtable (L); - - /* Create userdata guard, which disconnects env when the state - dies. Attach the actual env table as env table to the guard - udata. */ - guard = lua_newuserdata (L, sizeof (ObjectEnvGuard)); - guard->object = obj; - lua_rawgeti (L, -4, OBJECT_QDATA_ENV); - guard->id = lua_tointeger (L, -1); - lua_pop (L, 1); - lua_pushvalue (L, -2); - lua_setfenv (L, -2); - - /* Store it to the 'env' table. */ - lua_pushlightuserdata (L, obj); - lua_pushvalue (L, -2); - lua_rawset (L, -6); - - /* Create and fill new ObjectData structure, to attach it to - object's qdata. */ - data = g_new (ObjectData, 1); - data->object = obj; - lua_rawgeti (L, -4, OBJECT_QDATA_THREAD); - data->L = lua_tothread (L, -1); - data->state_lock = lua_gobject_state_get_lock (data->L); - - /* Attach ObjectData to the object. */ - g_object_set_qdata_full (G_OBJECT (obj), guard->id, - data, object_data_destroy); - lua_pop (L, 2); - } - - return 1; + ObjectData *data; + gpointer obj = object_get(L, 1); + if (!G_IS_OBJECT(obj)) + /* Only GObject instances can have environment. */ + return 0; + + /* Lookup 'env' table. */ + lua_pushlightuserdata(L, &env); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushlightuserdata(L, obj); + lua_rawget(L, -2); + if (!lua_isnil(L, -1)) + /* Object's env table for the object is attached to the controlling userdata in the 'env' table. */ + lua_getfenv(L, -1); + else { + ObjectEnvGuard *guard; + + /* Create new table which will serve as an object env table. */ + lua_newtable(L); + + /* Create userdata guard, which disconnects env when the state dies. Attach the actual env table as env table to the guard + udata. */ + guard = lua_newuserdata(L, sizeof(ObjectEnvGuard)); + guard->object = obj; + lua_rawgeti(L, -4, OBJECT_QDATA_ENV); + guard->id = lua_tointeger(L, -1); + lua_pop(L, 1); + lua_pushvalue(L, -2); + lua_setfenv(L, -2); + + /* Store it to the 'env' table. */ + lua_pushlightuserdata(L, obj); + lua_pushvalue(L, -2); + lua_rawset(L, -6); + + /* Create and fill new ObjectData structure, to attach it to + object's qdata. */ + data = g_new(ObjectData, 1); + data->object = obj; + lua_rawgeti(L, -4, OBJECT_QDATA_THREAD); + data->L = lua_tothread(L, -1); + data->state_lock = lua_gobject_state_get_lock(data->L); + + /* Attach ObjectData to the object. */ + g_object_set_qdata_full(G_OBJECT(obj), guard->id, + data, object_data_destroy); + lua_pop(L, 2); + } + + return 1; } /* Creates new object. Lua-side prototypes: - res = object.new(luserdata-ptr[, already_own[, no_sink]]) - res = object.new(gtype, { GParameter }) */ +res = object.new(luserdata-ptr[, already_own[, no_sink]]) +res = object.new(gtype, { GParameter }) */ static int -object_new (lua_State *L) +object_new(lua_State *L) { - if (lua_islightuserdata (L, 1)) - /* Create object from the given pointer. */ - return lua_gobject_object_2lua (L, lua_touserdata (L, 1), lua_toboolean (L, 2), - lua_toboolean (L, 3)); - else - { - G_GNUC_BEGIN_IGNORE_DEPRECATIONS - /* Normally Lua code uses GObject.Object.new(), which maps - directly to g_object_newv(), but for some reason GOI < 1.0 does - not export this method in the typelib. */ - - /* Get GType - 1st argument. */ - GParameter *params; - size_t size, i; - GIBaseInfo *gparam_info; - GType gtype = lua_gobject_type_get_gtype (L, 1); - luaL_checktype (L, 2, LUA_TTABLE); - - /* Find BaseInfo of GParameter. */ - gparam_info = gi_repository_find_by_name (lua_gobject_gi_get_repository (), "GObject", "Parameter"); - *lua_gobject_guard_create (L, (GDestroyNotify) gi_base_info_unref) = gparam_info; - - /* Prepare array of GParameter structures. */ - size = lua_objlen (L, 2); - params = g_newa (GParameter, size); - for (i = 0; i < size; ++i) - { - lua_pushinteger (L, i + 1); - lua_gettable (L, 2); - lua_gobject_type_get_repotype (L, G_TYPE_INVALID, gparam_info); - lua_gobject_record_2c (L, -2, ¶ms[i], TRUE, FALSE, FALSE, FALSE); - lua_pop (L, 1); + if (lua_islightuserdata(L, 1)) + /* Create object from the given pointer. */ + return lua_gobject_object_2lua(L, lua_touserdata(L, 1), lua_toboolean(L, 2), + lua_toboolean(L, 3)); + else { + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + /* Normally Lua code uses GObject.Object.new(), which maps directly to g_object_newv(), but for some reason GOI < 1.0 does not export this method in the typelib. */ + + /* Get GType - 1st argument. */ + GParameter *params; + size_t size, i; + GIBaseInfo *gparam_info; + GType gtype = lua_gobject_type_get_gtype(L, 1); + luaL_checktype(L, 2, LUA_TTABLE); + + /* Find BaseInfo of GParameter. */ + gparam_info = gi_repository_find_by_name( + lua_gobject_gi_get_repository(), "GObject", "Parameter"); + *lua_gobject_guard_create(L, + (GDestroyNotify) gi_base_info_unref) = gparam_info; + + /* Prepare array of GParameter structures. */ + size = lua_objlen(L, 2); + params = g_newa(GParameter, size); + for (i = 0; i < size; ++i) { + lua_pushinteger(L, i + 1); + lua_gettable(L, 2); + lua_gobject_type_get_repotype(L, G_TYPE_INVALID, gparam_info); + lua_gobject_record_2c(L, -2, ¶ms[i], + TRUE, FALSE, FALSE, FALSE); + lua_pop(L, 1); + } + + /* Create the object and return it. */ + return lua_gobject_object_2lua(L, g_object_newv(gtype, size, params), + TRUE, FALSE); + + G_GNUC_END_IGNORE_DEPRECATIONS } - - /* Create the object and return it. */ - return lua_gobject_object_2lua (L, g_object_newv (gtype, size, params), - TRUE, FALSE); - - G_GNUC_END_IGNORE_DEPRECATIONS - } } /* Object API table. */ static const luaL_Reg object_api_reg[] = { - { "query", object_query }, - { "field", object_field }, - { "new", object_new }, - { "env", object_env }, - { NULL, NULL } + { "query", object_query }, + { "field", object_field }, + { "new", object_new }, + { "env", object_env }, + { NULL, NULL } }; void -lua_gobject_object_init (lua_State *L) +lua_gobject_object_init(lua_State *L) { - char *id; - - /* Register metatable. */ - lua_pushlightuserdata (L, &object_mt); - lua_newtable (L); - luaL_register (L, NULL, object_mt_reg); - lua_rawset (L, LUA_REGISTRYINDEX); - - /* Initialize object cache. */ - lua_gobject_cache_create (L, &cache, "v"); - - /* Create table for 'env' tables. */ - lua_pushlightuserdata (L, &env); - lua_newtable (L); - - /* Add OBJECT_QDATA_ENV quark to env table. */ - id = g_strdup_printf ("lua_gobject:%p", L); - lua_pushinteger (L, g_quark_from_string (id)); - g_free (id); - lua_rawseti (L, -2, OBJECT_QDATA_ENV); - - /* Add OBJECT_QDATA_THREAD to env table. */ - lua_newthread (L); - lua_rawseti (L, -2, OBJECT_QDATA_THREAD); - - /* Add 'env' table to the registry. */ - lua_rawset (L, LUA_REGISTRYINDEX); - - /* Register env_mt table. */ - lua_pushlightuserdata (L, &env_mt); - lua_newtable (L); - lua_pushcfunction (L, object_env_guard_gc); - lua_setfield (L, -2, "__gc"); - lua_rawset (L, LUA_REGISTRYINDEX); - - /* Create object API table and set it to the parent. */ - lua_newtable (L); - luaL_register (L, NULL, object_api_reg); - lua_setfield (L, -2, "object"); + char *id; + + /* Register metatable. */ + lua_pushlightuserdata(L, &object_mt); + lua_newtable(L); + luaL_register(L, NULL, object_mt_reg); + lua_rawset(L, LUA_REGISTRYINDEX); + + /* Initialize object cache. */ + lua_gobject_cache_create(L, &cache, "v"); + + /* Create table for 'env' tables. */ + lua_pushlightuserdata(L, &env); + lua_newtable(L); + + /* Add OBJECT_QDATA_ENV quark to env table. */ + id = g_strdup_printf("lua_gobject:%p", L); + lua_pushinteger(L, g_quark_from_string(id)); + g_free(id); + lua_rawseti(L, -2, OBJECT_QDATA_ENV); + + /* Add OBJECT_QDATA_THREAD to env table. */ + lua_newthread(L); + lua_rawseti(L, -2, OBJECT_QDATA_THREAD); + + /* Add 'env' table to the registry. */ + lua_rawset(L, LUA_REGISTRYINDEX); + + /* Register env_mt table. */ + lua_pushlightuserdata(L, &env_mt); + lua_newtable(L); + lua_pushcfunction(L, object_env_guard_gc); + lua_setfield(L, -2, "__gc"); + lua_rawset(L, LUA_REGISTRYINDEX); + + /* Create object API table and set it to the parent. */ + lua_newtable(L); + luaL_register(L, NULL, object_api_reg); + lua_setfield(L, -2, "object"); } diff --git a/LuaGObject/package.lua b/LuaGObject/package.lua index fadd14b0..5c5d23ce 100644 --- a/LuaGObject/package.lua +++ b/LuaGObject/package.lua @@ -1,16 +1,8 @@ ------------------------------------------------------------------------------- --- --- LGI Support for repository packages (namespaces with classes --- overriden in LuaGObject) --- +-- LGI Support for repository packages (namespaces with classes overriden in LuaGObject) -- Copyright (c) 2012 Pavel Holejsovsky --- Licensed under the MIT license: --- http://www.opensource.org/licenses/mit-license.php --- ------------------------------------------------------------------------------- +-- Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php -local rawget, setmetatable, assert, error - = rawget, setmetatable, assert, error +local rawget, setmetatable, assert, error = rawget, setmetatable, assert, error local core = require 'LuaGObject.core' @@ -18,35 +10,32 @@ local core = require 'LuaGObject.core' local package = { mt = {} } package.mt.__index = package.mt --- There is no lazy-loading, but define _resolve to do nothing to --- achieve API compatibility with GI-based namespaces. +-- There is no lazy-loading, but define _resolve to do nothing to achieve API compatibility with GI-based namespaces. function package.mt:_resolve(recurse) - return self + return self end --- Defines new class, deriving from existing one. If the class --- already exists, does nothing and returns nil, otherwise returns --- newly created class type. +-- Defines new class, deriving from existing one. If the class already exists, does nothing and returns nil, otherwise returns newly created class type. function package.mt:class(name, parent, ...) - if self[name] then return nil end - local class = parent:derive(self._name .. '.' .. name, ...) - self[name] = class - return class + if self[name] then return nil end + local class = parent:derive(self._name .. '.' .. name, ...) + self[name] = class + return class end -- Makes sure that given package exists, creates it if it does not. function package.ensure(name, version) - local ns = rawget(core.repo, name) - if not ns then - ns = setmetatable({ _name = name, _version = version }, package.mt) - core.repo[name] = ns - else - if version and ns._version and version ~= nv._version then - error(("%s-%s: required version %s "):format( - ns._name, ns._version, version)) - end - end - return ns + local ns = rawget(core.repo, name) + if not ns then + ns = setmetatable({ _name = name, _version = version }, package.mt) + core.repo[name] = ns + else + if version and ns._version and version ~= nv._version then + error(("%s-%s: required version %s "):format( + ns._name, ns._version, version)) + end + end + return ns end return package diff --git a/LuaGObject/record.c b/LuaGObject/record.c index da30b79e..2ffdcb1f 100644 --- a/LuaGObject/record.c +++ b/LuaGObject/record.c @@ -1,765 +1,671 @@ -/* - * Dynamic Lua binding to GObject using dynamic gobject-introspection. - * - * Copyright (c) 2010, 2011, 2012, 2013 Pavel Holejsovsky - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - * Management of structures and unions (i.e. records). - */ +/* Dynamic Lua binding to GObject using dynamic gobject-introspection. +Copyright(c) 2010, 2011, 2012, 2013 Pavel Holejsovsky +Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php +Management of structures and unions(i.e. records). */ #include #include "lua_gobject.h" /* Available record store modes. */ -typedef enum _RecordStore - { - /* We do not have ownership of the record. */ - RECORD_STORE_EXTERNAL, - - /* Record is stored in data section of Record proxy itself. */ - RECORD_STORE_EMBEDDED, - - /* Record is placed inside some other (parent) record. In order - to keep parent record alive, parent record is stored in - parent_cache table. */ - RECORD_STORE_NESTED, - - /* Record is allocated by its GLib means and must be freed (by - g_boxed_free). */ - RECORD_STORE_ALLOCATED, - } RecordStore; - -/* Userdata containing record reference. Table with record type is - attached as userdata environment. */ -typedef struct _Record -{ - /* Address of the record memory data. */ - gpointer addr; - - /* Store mode of the record. */ - RecordStore store; - - /* If the record is allocated 'on the stack', its data is - here. Anonymous union makes sure that data is properly aligned to - hold (hopefully) any structure. */ - union { - gchar data[1]; - double align_double; - long align_long; - gpointer align_ptr; - }; +typedef enum _RecordStore { + /* We do not have ownership of the record. */ + RECORD_STORE_EXTERNAL, + + /* Record is stored in data section of Record proxy itself. */ + RECORD_STORE_EMBEDDED, + + /* Record is placed inside some other(parent) record. In order to keep parent record alive, parent record is stored in parent_cache table. */ + RECORD_STORE_NESTED, + + /* Record is allocated by its GLib means and must be freed(by g_boxed_free). */ + RECORD_STORE_ALLOCATED, + } RecordStore; + +/* Userdata containing record reference. Table with record type is attached as userdata environment. */ +typedef struct _Record { + /* Address of the record memory data. */ + gpointer addr; + + /* Store mode of the record. */ + RecordStore store; + + /* If the record is allocated 'on the stack', its data is here. Anonymous union makes sure that data is properly aligned to hold(hopefully) any structure. */ + union { + gchar data[1]; + double align_double; + long align_long; + gpointer align_ptr; + }; } Record; -/* lightuserdata key to LUA_REGISTRYINDEX containing metatable for - record. */ +/* lightuserdata key to LUA_REGISTRYINDEX containing metatable for record. */ static int record_mt; -/* lightuserdata key to cache table containing - lightuserdata(record->addr) -> weak(record) */ +/* lightuserdata key to cache table containing lightuserdata(record->addr) -> weak(record) */ static int record_cache; -/* lightuserdata key to cache table containing - recordproxy(weak) -> parent */ +/* lightuserdata key to cache table containing recordproxy(weak) -> parent */ static int parent_cache; gpointer -lua_gobject_record_new (lua_State *L, int count, gboolean alloc) +lua_gobject_record_new(lua_State *L, int count, gboolean alloc) { - Record *record; - size_t size; - - luaL_checkstack (L, 4, ""); - - /* Calculate size of the record to allocate. */ - lua_getfield (L, -1, "_size"); - size = lua_tointeger (L, -1) * count; - lua_pop (L, 1); - - /* Allocate new userdata for record object, attach proper - metatable. */ - record = lua_newuserdata (L, G_STRUCT_OFFSET (Record, data) + - (alloc ? 0 : size)); - lua_pushlightuserdata (L, &record_mt); - lua_rawget (L, LUA_REGISTRYINDEX); - lua_setmetatable (L, -2); - if (G_LIKELY (!alloc)) - { - record->addr = record->data; - memset (record->addr, 0, size); - record->store = RECORD_STORE_EMBEDDED; - } - else - { - record->addr = g_malloc0 (size); - record->store = RECORD_STORE_ALLOCATED; - } - - /* Get ref_repo table, attach it as an environment. */ - lua_pushvalue (L, -2); - lua_setfenv (L, -2); - - /* Store newly created record into the cache. */ - lua_pushlightuserdata (L, &record_cache); - lua_rawget (L, LUA_REGISTRYINDEX); - lua_pushlightuserdata (L, record->addr); - lua_pushvalue (L, -3); - lua_rawset (L, -3); - lua_pop (L, 1); - - /* Invoke '_attach' method if present on the typetable. */ - lua_getfield (L, -2, "_attach"); - if (!lua_isnil (L, -1)) - { - lua_pushvalue (L, -3); - lua_pushvalue (L, -3); - lua_call (L, 2, 0); - } - else - lua_pop (L, 1); - - /* Remove refrepo table from the stack. */ - lua_remove (L, -2); - return record->addr; + Record *record; + size_t size; + + luaL_checkstack(L, 4, ""); + + /* Calculate size of the record to allocate. */ + lua_getfield(L, -1, "_size"); + size = lua_tointeger(L, -1) * count; + lua_pop(L, 1); + + /* Allocate new userdata for record object, attach proper metatable. */ + record = lua_newuserdata(L, + G_STRUCT_OFFSET(Record, data) +(alloc ? 0 : size)); + lua_pushlightuserdata(L, &record_mt); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + if (G_LIKELY(!alloc)) { + record->addr = record->data; + memset(record->addr, 0, size); + record->store = RECORD_STORE_EMBEDDED; + } else { + record->addr = g_malloc0(size); + record->store = RECORD_STORE_ALLOCATED; + } + + /* Get ref_repo table, attach it as an environment. */ + lua_pushvalue(L, -2); + lua_setfenv(L, -2); + + /* Store newly created record into the cache. */ + lua_pushlightuserdata(L, &record_cache); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushlightuserdata(L, record->addr); + lua_pushvalue(L, -3); + lua_rawset(L, -3); + lua_pop(L, 1); + + /* Invoke '_attach' method if present on the typetable. */ + lua_getfield(L, -2, "_attach"); + if (!lua_isnil(L, -1)) { + lua_pushvalue(L, -3); + lua_pushvalue(L, -3); + lua_call(L, 2, 0); + } + else + lua_pop(L, 1); + + /* Remove refrepo table from the stack. */ + lua_remove(L, -2); + return record->addr; } static void -record_free (lua_State *L, Record *record, int narg) +record_free(lua_State *L, Record *record, int narg) { - GType gtype; - g_assert (record->store == RECORD_STORE_ALLOCATED); - lua_getfenv (L, narg); - for (;;) - { - lua_getfield (L, -1, "_gtype"); - gtype = (GType) lua_touserdata (L, -1); - lua_pop (L, 1); - if (G_TYPE_IS_BOXED (gtype)) - { - g_boxed_free (gtype, record->addr); - break; - } - else - { - /* Use custom _free function. */ - void (*free_func)(gpointer) = - lua_gobject_gi_load_function (L, -1, "_free"); - if (free_func) - { - free_func (record->addr); - break; - } - } + GType gtype; + g_assert(record->store == RECORD_STORE_ALLOCATED); + lua_getfenv(L, narg); + for (;;) { + lua_getfield(L, -1, "_gtype"); + gtype =(GType) lua_touserdata(L, -1); + lua_pop(L, 1); + if (G_TYPE_IS_BOXED(gtype)) { + g_boxed_free(gtype, record->addr); + break; + } else { + /* Use custom _free function. */ + void(*free_func)(gpointer) = + lua_gobject_gi_load_function(L, -1, "_free"); + if (free_func) { + free_func(record->addr); + break; + } + } - /* Try to get parent of the type. */ - lua_getfield (L, -1, "_parent"); - lua_replace (L, -2); - if (lua_isnil (L, -1)) - { - lua_getfenv (L, 1); - lua_getfield (L, -1, "_name"); - g_warning ("unable to free record %s, leaking it", - lua_tostring (L, -1)); - lua_pop (L, 2); - break; + /* Try to get parent of the type. */ + lua_getfield(L, -1, "_parent"); + lua_replace(L, -2); + if (lua_isnil(L, -1)) { + lua_getfenv(L, 1); + lua_getfield(L, -1, "_name"); + g_warning("unable to free record %s, leaking it", + lua_tostring(L, -1)); + lua_pop(L, 2); + break; + } } - } - lua_pop (L, 1); + lua_pop(L, 1); } void -lua_gobject_record_2lua (lua_State *L, gpointer addr, gboolean own, int parent) +lua_gobject_record_2lua(lua_State *L, gpointer addr, gboolean own, int parent) { - Record *record; - - luaL_checkstack (L, 5, ""); - - /* NULL pointer results in 'nil'. */ - if (addr == NULL) - { - lua_pop (L, 1); - lua_pushnil (L); - return; - } - - /* Convert 'parent' index to an absolute one. */ - if (parent == LUA_GOBJECT_PARENT_IS_RETVAL || parent == LUA_GOBJECT_PARENT_FORCE_POINTER) - parent = 0; - else - lua_gobject_makeabs (L, parent); - - /* Prepare access to cache. */ - lua_pushlightuserdata (L, &record_cache); - lua_rawget (L, LUA_REGISTRYINDEX); - - /* Check whether the record is already cached. */ - lua_pushlightuserdata (L, addr); - lua_rawget (L, -2); - if (!lua_isnil (L, -1) && parent == 0) - { - /* Remove unneeded tables under our requested object. */ - lua_replace (L, -3); - lua_pop (L, 1); - - /* In case that we want to own the record, make sure that the - ownership is properly updated. */ - record = lua_touserdata (L, -1); - g_assert (record->addr == addr); - if (own) - { - if (record->store == RECORD_STORE_EXTERNAL) - record->store = RECORD_STORE_ALLOCATED; - else if (record->store == RECORD_STORE_ALLOCATED) - record_free (L, record, -1); + Record *record; + + luaL_checkstack(L, 5, ""); + + /* NULL pointer results in 'nil'. */ + if (addr == NULL) { + lua_pop(L, 1); + lua_pushnil(L); + return; } - return; - } - - /* Allocate new userdata for record object, attach proper - metatable. */ - record = lua_newuserdata (L, G_STRUCT_OFFSET (Record, data)); - lua_pushlightuserdata (L, &record_mt); - lua_rawget (L, LUA_REGISTRYINDEX); - lua_setmetatable (L, -2); - record->addr = addr; - if (parent != 0) - { - /* Store reference to the parent argument into parent reference - cache. */ - lua_pushlightuserdata (L, &parent_cache); - lua_rawget (L, LUA_REGISTRYINDEX); - lua_pushvalue (L, -2); - lua_pushvalue (L, parent); - lua_rawset (L, -3); - lua_pop (L, 1); - record->store = RECORD_STORE_NESTED; - } - else - { - if (!own) - { - /* Check, whether refrepo table specifies custom _refsink - function. */ - void (*refsink_func)(gpointer) = - lua_gobject_gi_load_function (L, -4, "_refsink"); - if (refsink_func) - { - refsink_func(addr); - own = TRUE; - } + /* Convert 'parent' index to an absolute one. */ + if (parent == LUA_GOBJECT_PARENT_IS_RETVAL + || parent == LUA_GOBJECT_PARENT_FORCE_POINTER) + parent = 0; + else + lua_gobject_makeabs(L, parent); + + /* Prepare access to cache. */ + lua_pushlightuserdata(L, &record_cache); + lua_rawget(L, LUA_REGISTRYINDEX); + + /* Check whether the record is already cached. */ + lua_pushlightuserdata(L, addr); + lua_rawget(L, -2); + if (!lua_isnil(L, -1) && parent == 0) { + /* Remove unneeded tables under our requested object. */ + lua_replace(L, -3); + lua_pop(L, 1); + + /* In case that we want to own the record, make sure that the + ownership is properly updated. */ + record = lua_touserdata(L, -1); + g_assert(record->addr == addr); + if (own) { + if (record->store == RECORD_STORE_EXTERNAL) + record->store = RECORD_STORE_ALLOCATED; + else if (record->store == RECORD_STORE_ALLOCATED) + record_free(L, record, -1); + } + + return; + } + + /* Allocate new userdata for record object, attach proper metatable. */ + record = lua_newuserdata(L, G_STRUCT_OFFSET(Record, data)); + lua_pushlightuserdata(L, &record_mt); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + record->addr = addr; + if (parent != 0) { + /* Store reference to the parent argument into parent reference cache. */ + lua_pushlightuserdata(L, &parent_cache); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushvalue(L, -2); + lua_pushvalue(L, parent); + lua_rawset(L, -3); + lua_pop(L, 1); + record->store = RECORD_STORE_NESTED; + } else { + if (!own) { + /* Check, whether refrepo table specifies custom _refsink function. */ + void(*refsink_func)(gpointer) = + lua_gobject_gi_load_function(L, -4, "_refsink"); + if (refsink_func) { + refsink_func(addr); + own = TRUE; + } + } + + record->store = own ? RECORD_STORE_ALLOCATED : RECORD_STORE_EXTERNAL; } - record->store = own ? RECORD_STORE_ALLOCATED : RECORD_STORE_EXTERNAL; - } - - /* Assign refrepo table (on the stack when we are called) as - environment for our proxy. */ - lua_pushvalue (L, -4); - lua_setfenv (L, -2); - - /* Store newly created record into the cache. */ - if (parent == 0 && own) - { - lua_pushlightuserdata (L, addr); - lua_pushvalue (L, -2); - lua_rawset (L, -5); - } - - /* Invoke '_attach' method if present on the typetable. */ - lua_getfield (L, -4, "_attach"); - if (!lua_isnil (L, -1)) - { - lua_pushvalue (L, -5); - lua_pushvalue (L, -3); - lua_call (L, 2, 0); - } - else - lua_pop (L, 1); - - /* Clean up the stack; remove cache table from under our result, and - remove also typetable which was present when we were called. */ - lua_replace (L, -4); - lua_pop (L, 2); + /* Assign refrepo table(on the stack when we are called) as environment for our proxy. */ + lua_pushvalue(L, -4); + lua_setfenv(L, -2); + + /* Store newly created record into the cache. */ + if (parent == 0 && own) { + lua_pushlightuserdata(L, addr); + lua_pushvalue(L, -2); + lua_rawset(L, -5); + } + + /* Invoke '_attach' method if present on the typetable. */ + lua_getfield(L, -4, "_attach"); + if (!lua_isnil(L, -1)) { + lua_pushvalue(L, -5); + lua_pushvalue(L, -3); + lua_call(L, 2, 0); + } + else + lua_pop(L, 1); + + /* Clean up the stack; remove cache table from under our result, and remove also typetable which was present when we were called. */ + lua_replace(L, -4); + lua_pop(L, 2); } -/* Checks that given argument is Record userdata and returns pointer - to it. Returns NULL if narg has bad type. */ +/* Checks that given argument is Record userdata and returns pointer to it. Returns NULL if narg has bad type. */ static Record * -record_check (lua_State *L, int narg) +record_check(lua_State *L, int narg) { - /* Check using metatable that narg is really Record type. */ - Record *record = lua_touserdata (L, narg); - luaL_checkstack (L, 3, ""); - if (!lua_getmetatable (L, narg)) - return NULL; - lua_pushlightuserdata (L, &record_mt); - lua_rawget (L, LUA_REGISTRYINDEX); - if (!lua_equal (L, -1, -2)) - record = NULL; - lua_pop (L, 2); - return record; + /* Check using metatable that narg is really Record type. */ + Record *record = lua_touserdata(L, narg); + luaL_checkstack(L, 3, ""); + if (!lua_getmetatable(L, narg)) + return NULL; + lua_pushlightuserdata(L, &record_mt); + lua_rawget(L, LUA_REGISTRYINDEX); + if (!lua_equal(L, -1, -2)) + record = NULL; + lua_pop(L, 2); + return record; } /* Throws error that narg is not of expected type. */ static int -record_error (lua_State *L, int narg, const gchar *expected_name) +record_error(lua_State *L, int narg, const gchar *expected_name) { - luaL_checkstack (L, 2, ""); - lua_pushstring (L, lua_typename (L, lua_type (L, narg))); - lua_pushfstring (L, "%s expected, got %s", - expected_name ? expected_name : "lua_gobject.record", - lua_tostring (L, -1)); - return luaL_argerror (L, narg, lua_tostring (L, -1)); + luaL_checkstack(L, 2, ""); + lua_pushstring(L, lua_typename(L, lua_type(L, narg))); + lua_pushfstring(L, "%s expected, got %s", + expected_name ? expected_name : "lua_gobject.record", + lua_tostring(L, -1)); + return luaL_argerror(L, narg, lua_tostring(L, -1)); } /* Similar to record_check, but throws in case of failure. */ static Record * -record_get (lua_State *L, int narg) +record_get(lua_State *L, int narg) { - Record *record = record_check (L, narg); - if (record == NULL) - record_error (L, narg, NULL); + Record *record = record_check(L, narg); + if (record == NULL) + record_error(L, narg, NULL); - return record; + return record; } void -lua_gobject_record_2c (lua_State *L, int narg, gpointer target, gboolean by_value, - gboolean own, gboolean optional, gboolean nothrow) +lua_gobject_record_2c(lua_State *L, int narg, gpointer target, gboolean by_value, + gboolean own, gboolean optional, gboolean nothrow) { - Record *record = NULL; - - /* Check for nil. */ - if (!optional || !lua_isnoneornil (L, narg)) - { - /* Get record and check its type. */ - lua_gobject_makeabs (L, narg); - luaL_checkstack (L, 4, ""); - record = record_check (L, narg); - if (record) - { - /* Check, whether type fits. Also take into account possible - inheritance. */ - lua_getfenv (L, narg); - for (;;) - { - if (lua_equal (L, -1, -2)) - break; - - /* Try to get parent of the real type. */ - lua_getfield (L, -1, "_parent"); - lua_replace (L, -2); - if (lua_isnil (L, -1)) - { - record = NULL; - break; + Record *record = NULL; + + /* Check for nil. */ + if (!optional || !lua_isnoneornil(L, narg)) { + /* Get record and check its type. */ + lua_gobject_makeabs(L, narg); + luaL_checkstack(L, 4, ""); + record = record_check(L, narg); + if (record) { + /* Check, whether type fits. Also take into account possible inheritance. */ + lua_getfenv(L, narg); + for (;;) { + if (lua_equal(L, -1, -2)) + break; + + /* Try to get parent of the real type. */ + lua_getfield(L, -1, "_parent"); + lua_replace(L, -2); + if (lua_isnil(L, -1)) { + record = NULL; + break; + } + } + + lua_pop(L, 1); } - } - - lua_pop (L, 1); - } - if (!nothrow && !record) - { - const gchar *name = NULL; - if (!lua_isnil (L, -1)) - { - lua_getfield (L, -1, "_name"); - name = lua_tostring (L, -1); - } - record_error (L, narg, name); + if (!nothrow && !record) + { + const gchar *name = NULL; + if (!lua_isnil(L, -1)) + { + lua_getfield(L, -1, "_name"); + name = lua_tostring(L, -1); + } + record_error(L, narg, name); + } } - } - if (G_LIKELY (!by_value)) - { - *(gpointer *) target = record ? record->addr : NULL; - if (record && own) - { - /* Caller wants to steal ownership from us. */ - if (G_LIKELY (record->store == RECORD_STORE_ALLOCATED)) - { - /* Check, whether refrepo table specifies custom _refsink - function. */ - void (*refsink_func)(gpointer) = - lua_gobject_gi_load_function (L, narg, "_refsink"); - if (refsink_func) - refsink_func(record->addr); - else - record->store = RECORD_STORE_EXTERNAL; - } - else - g_critical ("attempt to steal record ownership from unowned rec"); - } - } - else - { - gsize size; - lua_getfield (L, -1, "_size"); - size = lua_tointeger (L, -1); - lua_pop (L, 1); - - if (record) - { - /* Check, whether custom _copy is registered. */ - void (*copy_func)(gpointer, gpointer) = - lua_gobject_gi_load_function (L, -1, "_copy"); - if (copy_func) - copy_func (record->addr, target); - else - memcpy (target, record->addr, size); + if (G_LIKELY(!by_value)) { + *(gpointer *) target = record ? record->addr : NULL; + if (record && own) { + /* Caller wants to steal ownership from us. */ + if (G_LIKELY(record->store == RECORD_STORE_ALLOCATED)) { + /* Check, whether refrepo table specifies custom _refsink function. */ + void(*refsink_func)(gpointer) = + lua_gobject_gi_load_function(L, narg, "_refsink"); + if (refsink_func) + refsink_func(record->addr); + else + record->store = RECORD_STORE_EXTERNAL; + } else + g_critical("attempt to steal record ownership from unowned rec"); + } + } else { + gsize size; + lua_getfield(L, -1, "_size"); + size = lua_tointeger(L, -1); + lua_pop(L, 1); + + if (record) { + /* Check, whether custom _copy is registered. */ + void(*copy_func)(gpointer, gpointer) = + lua_gobject_gi_load_function(L, -1, "_copy"); + if (copy_func) + copy_func(record->addr, target); + else + memcpy(target, record->addr, size); + } else + /* Transferring NULL ptr, simply NULL target. */ + memset(target, 0, size); } - else - /* Transferring NULL ptr, simply NULL target. */ - memset (target, 0, size); - } - lua_pop (L, 1); + lua_pop(L, 1); } static int -record_gc (lua_State *L) +record_gc(lua_State *L) { - Record *record = record_get (L, 1); - - if (record->store == RECORD_STORE_EMBEDDED - || record->store == RECORD_STORE_NESTED) - { - /* Check whether record has registered '_uninit' function, and - invoke it if yes. */ - lua_getfenv (L, 1); - void (*uninit)(gpointer) = lua_gobject_gi_load_function (L, -1, "_uninit"); - if (uninit != NULL) - uninit (record->addr); - } - else if (record->store == RECORD_STORE_ALLOCATED) - /* Free the owned record. */ - record_free (L, record, 1); - - if (record->store == RECORD_STORE_NESTED) - { - /* Free the reference to the parent. */ - lua_pushlightuserdata (L, record); - lua_pushnil (L); - lua_rawset (L, LUA_REGISTRYINDEX); - } - - /* Unset the metatable / make the record unusable */ - lua_pushnil (L); - lua_setmetatable (L, 1); - return 0; + Record *record = record_get(L, 1); + + if (record->store == RECORD_STORE_EMBEDDED + || record->store == RECORD_STORE_NESTED) { + /* Check whether record has registered '_uninit' function, and invoke it if yes. */ + lua_getfenv(L, 1); + void(*uninit)(gpointer) = lua_gobject_gi_load_function(L, -1, "_uninit"); + if (uninit != NULL) + uninit(record->addr); + } else if (record->store == RECORD_STORE_ALLOCATED) + /* Free the owned record. */ + record_free(L, record, 1); + + if (record->store == RECORD_STORE_NESTED) { + /* Free the reference to the parent. */ + lua_pushlightuserdata(L, record); + lua_pushnil(L); + lua_rawset(L, LUA_REGISTRYINDEX); + } + + /* Unset the metatable / make the record unusable */ + lua_pushnil(L); + lua_setmetatable(L, 1); + return 0; } static int -record_tostring (lua_State *L) +record_tostring(lua_State *L) { - Record *record = record_get (L, 1); - lua_getfenv (L, 1); - lua_getfield (L, -1, "_tostring"); - if (lua_isnil (L, -1)) - { - lua_pop (L, 1); - lua_pushfstring (L, "lua_gobject.rec %p:", record->addr); - lua_getfield (L, -2, "_name"); - if (!lua_isnil (L, -1)) - lua_concat (L, 2); - else - lua_pop (L, 1); - } - else - { - lua_pushvalue (L, 1); - lua_call (L, 1, 1); - } - - return 1; + Record *record = record_get(L, 1); + lua_getfenv(L, 1); + lua_getfield(L, -1, "_tostring"); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + lua_pushfstring(L, "lua_gobject.rec %p:", record->addr); + lua_getfield(L, -2, "_name"); + if (!lua_isnil(L, -1)) + lua_concat(L, 2); + else + lua_pop(L, 1); + } else { + lua_pushvalue(L, 1); + lua_call(L, 1, 1); + } + + return 1; } /* Worker method for __index and __newindex implementation. */ static int -record_access (lua_State *L) +record_access(lua_State *L) { - gboolean getmode = lua_isnone (L, 3); - - /* Check that 1st arg is a record and invoke one of the forms: - result = type:_access(recordinstance, name) - type:_access(recordinstance, name, val) */ - record_get (L, 1); - lua_getfenv (L, 1); - return lua_gobject_marshal_access (L, getmode, 1, 2, 3); + gboolean getmode = lua_isnone(L, 3); + + /* Check that 1st arg is a record and invoke one of the forms: + result = type:_access(recordinstance, name) + type:_access(recordinstance, name, val) */ + record_get(L, 1); + lua_getfenv(L, 1); + return lua_gobject_marshal_access(L, getmode, 1, 2, 3); } /* Worker method for __len implementation. */ static int -record_len (lua_State *L) +record_len(lua_State *L) { - /* Check record, get its typetable and try to invoke _len method. */ - record_get (L, 1); - lua_getfenv (L, 1); - lua_getfield (L, -1, "_len"); - if (lua_isnil (L, -1)) - { - lua_getfield (L, -2, "_name"); - return luaL_error (L, "`%s': attempt to get length", - lua_tostring (L, -1)); - } - lua_pushvalue (L, 1); - lua_call (L, 1, 1); - return 1; + /* Check record, get its typetable and try to invoke _len method. */ + record_get(L, 1); + lua_getfenv(L, 1); + lua_getfield(L, -1, "_len"); + if (lua_isnil(L, -1)) { + lua_getfield(L, -2, "_name"); + return luaL_error(L, "`%s': attempt to get length", + lua_tostring(L, -1)); + } + lua_pushvalue(L, 1); + lua_call(L, 1, 1); + return 1; } static const struct luaL_Reg record_meta_reg[] = { - { "__gc", record_gc }, - { "__tostring", record_tostring }, - { "__index", record_access }, - { "__newindex", record_access }, - { "__len", record_len }, - { NULL, NULL } + { "__gc", record_gc }, + { "__tostring", record_tostring }, + { "__index", record_access }, + { "__newindex", record_access }, + { "__len", record_len }, + { NULL, NULL } }; -/* Implements generic record creation. Creates new record instance, - unless 'addr' argument (lightuserdata or integer) is specified, in - which case wraps specified address as record. Lua prototype: - - recordinstance = core.record.new(repotable[, nil[, count[, alloc]]]) - recordinstance = core.record.new(repotable[, addr[, own]]) +/* Implements generic record creation. Creates new record instance, unless 'addr' argument(lightuserdata or integer) is specified, in which case wraps specified address as record. Lua prototype: +recordinstance = core.record.new(repotable[, nil[, count[, alloc]]]) +recordinstance = core.record.new(repotable[, addr[, own]]) - own (default false) means whether Lua takes record ownership - (i.e. if it tries to deallocate the record when created Lua proxy - dies). */ +own(default false) means whether Lua takes record ownership (i.e. if it tries to deallocate the record when created Lua proxy dies). */ static int -record_new (lua_State *L) +record_new(lua_State *L) { - if (lua_isnoneornil (L, 2)) - { - /* Create new record instance. */ - gboolean alloc = lua_toboolean (L, 4); - luaL_checktype (L, 1, LUA_TTABLE); - lua_pushvalue (L, 1); - lua_gobject_record_new (L, luaL_optinteger (L, 3, 1), alloc); - } - else - { - /* Wrap record at existing address. */ - gpointer addr = (lua_type (L, 2) == LUA_TLIGHTUSERDATA) - ? addr = lua_touserdata (L, 2) - : (gpointer) luaL_checkinteger (L, 2); - gboolean own = lua_toboolean (L, 3); - lua_pushvalue (L, 1); - lua_gobject_record_2lua (L, addr, own, 0); - } - - return 1; + if (lua_isnoneornil(L, 2)) + { + /* Create new record instance. */ + gboolean alloc = lua_toboolean(L, 4); + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushvalue(L, 1); + lua_gobject_record_new(L, luaL_optinteger(L, 3, 1), alloc); + } else { + /* Wrap record at existing address. */ + gpointer addr =(lua_type(L, 2) == LUA_TLIGHTUSERDATA) + ? addr = lua_touserdata(L, 2) + : (gpointer) luaL_checkinteger(L, 2); + gboolean own = lua_toboolean(L, 3); + lua_pushvalue(L, 1); + lua_gobject_record_2lua(L, addr, own, 0); + } + + return 1; } static const char* const query_modes[] = { "gtype", "repo", "addr", NULL }; /* Returns specific information mode about given record. Lua prototype: - res = record.query(instance, mode) - Supported 'mode' strings are: - - 'gtype': returns real gtype of this instance, nil when it is not boxed. - 'repo': returns repotable of this instance. - 'addr': returns address of the object. If 3rd argument is either - repotable, checks, whether record conforms to the specs and - if not, throws an error. */ +res = record.query(instance, mode) +Supported 'mode' strings are: +- 'gtype': returns real gtype of this instance, nil when it is not boxed. +- 'repo': returns repotable of this instance. +- 'addr': returns address of the object. If 3rd argument is either repotable, checks, whether record conforms to the specs and if not, throws an error. */ static int -record_query (lua_State *L) +record_query(lua_State *L) { - Record *record; - int mode = luaL_checkoption (L, 2, query_modes[0], query_modes); - if (mode < 2) - { - record = record_check (L, 1); - if (!record) - return 0; - - lua_getfenv (L, 1); - if (mode == 0) - { - GType gtype; - if (lua_isnil (L, -1)) - return 0; - - lua_getfield (L, -1, "_gtype"); - gtype = luaL_optinteger (L, -1, G_TYPE_INVALID); - lua_pushstring (L, g_type_name (gtype)); - } - return 1; - } - else - { - if (lua_isnoneornil (L, 3)) - { - record = record_check (L, 1); - if (!record) - return 0; + Record *record; + int mode = luaL_checkoption(L, 2, query_modes[0], query_modes); + if (mode < 2) { + record = record_check(L, 1); + if (!record) + return 0; + + lua_getfenv(L, 1); + if (mode == 0) { + GType gtype; + if (lua_isnil(L, -1)) + return 0; + + lua_getfield(L, -1, "_gtype"); + gtype = luaL_optinteger(L, -1, G_TYPE_INVALID); + lua_pushstring(L, g_type_name(gtype)); + } + return 1; + } else { + if (lua_isnoneornil(L, 3)) { + record = record_check(L, 1); + if (!record) + return 0; + + lua_pushlightuserdata(L, record->addr); + } else { + gpointer addr; + lua_pushvalue(L, 3); + lua_gobject_record_2c(L, 1, &addr, FALSE, FALSE, TRUE, FALSE); + lua_pushlightuserdata(L, addr); + } - lua_pushlightuserdata (L, record->addr); - } - else - { - gpointer addr; - lua_pushvalue (L, 3); - lua_gobject_record_2c (L, 1, &addr, FALSE, FALSE, TRUE, FALSE); - lua_pushlightuserdata (L, addr); + return 1; } - - return 1; - } } /* Implements set/get field operation. Lua prototypes: - res = core.record.field(recordinstance, fieldinfo) - core.record.field(recordinstance, fieldinfo, newval) */ +res = core.record.field(recordinstance, fieldinfo) +core.record.field(recordinstance, fieldinfo, newval) */ static int -record_field (lua_State *L) +record_field(lua_State *L) { - gboolean getmode; - Record *record; + gboolean getmode; + Record *record; - /* Check, whether we are doing set or get operation. */ - getmode = lua_isnone (L, 3); + /* Check, whether we are doing set or get operation. */ + getmode = lua_isnone(L, 3); - /* Get record instance. */ - record = record_get (L, 1); + /* Get record instance. */ + record = record_get(L, 1); - /* Call field marshalling worker. */ - lua_getfenv (L, 1); - return lua_gobject_marshal_field (L, record->addr, getmode, 1, 2, 3); + /* Call field marshalling worker. */ + lua_getfenv(L, 1); + return lua_gobject_marshal_field(L, record->addr, getmode, 1, 2, 3); } /* Casts given record to another record type. Lua prototype: - res = core.record.cast(recordinstance, targettypetable) */ +res = core.record.cast(recordinstance, targettypetable) */ static int -record_cast (lua_State *L) +record_cast(lua_State *L) { - Record *record = record_get (L, 1); - luaL_checktype (L, 2, LUA_TTABLE); - lua_gobject_record_2lua (L, record->addr, FALSE, 1); - return 1; + Record *record = record_get(L, 1); + luaL_checktype(L, 2, LUA_TTABLE); + lua_gobject_record_2lua(L, record->addr, FALSE, 1); + return 1; } -/* Assumes that given record is the first of the array of records and - fetches record with specified index. Negative indices are allowed, - but no boundschecking is made. - res = core.record.fromarray(recordinstance, index) */ +/* Assumes that given record is the first of the array of records and fetches record with specified index. Negative indices are allowed, but no bounds checking is attempted. +res = core.record.fromarray(recordinstance, index) */ static int -record_fromarray (lua_State *L) +record_fromarray(lua_State *L) { - Record *record = record_get (L, 1); - int index = luaL_checkinteger (L, 2); - int parent = 0; - gboolean own = FALSE; - int size; - - /* Find out the size of this record. */ - lua_getfenv (L, 1); - lua_getfield (L, -1, "_size"); - size = lua_tointeger (L, -1); - - if (record->store == RECORD_STORE_EMBEDDED) - /* Parent is actually our embedded record. */ - parent = 1; - else if (record->store == RECORD_STORE_NESTED) - { - /* Share parent with the original record. */ - lua_pushlightuserdata (L, &parent_cache); - lua_rawget (L, LUA_REGISTRYINDEX); - lua_pushvalue (L, 1); - lua_rawget (L, -2); - parent = -2; - } - - lua_getfenv (L, 1); - lua_gobject_record_2lua (L, ((guint8 *) record->addr) + size * index, own, parent); - return 1; + Record *record = record_get(L, 1); + int index = luaL_checkinteger(L, 2); + int parent = 0; + gboolean own = FALSE; + int size; + + /* Find out the size of this record. */ + lua_getfenv(L, 1); + lua_getfield(L, -1, "_size"); + size = lua_tointeger(L, -1); + + if (record->store == RECORD_STORE_EMBEDDED) + /* Parent is actually our embedded record. */ + parent = 1; + else if (record->store == RECORD_STORE_NESTED) { + /* Share parent with the original record. */ + lua_pushlightuserdata(L, &parent_cache); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushvalue(L, 1); + lua_rawget(L, -2); + parent = -2; + } + + lua_getfenv(L, 1); + lua_gobject_record_2lua(L, ((guint8 *) record->addr) + size * index, + own, parent); + return 1; } /* Changes ownership mode or repotable of the record. - record.set(recordinstance, true|false) - - 'own' if true, changing ownership to owned, otherwise to - unowned. - - record.set(recordinstance, repotable) - - 'repotable' record repotable to which this instance should be - reassigned. */ +record.set(recordinstance, true|false) +- 'own' if true, changing ownership to owned, otherwise to unowned. +record.set(recordinstance, repotable) +- 'repotable' record repotable to which this instance should be reassigned. */ static int -record_set (lua_State *L) +record_set(lua_State *L) { - Record *record = record_get (L, 1); - if (lua_type (L, 2) == LUA_TTABLE) - { - /* Assign new typeinfo to the record instance. */ - lua_pushvalue (L, 2); - lua_setfenv (L, 1); - } - else - { - /* Change ownership type of the record. */ - if (lua_toboolean (L, 2)) - { - if (record->store == RECORD_STORE_EXTERNAL) - record->store = RECORD_STORE_ALLOCATED; - } - else - { - if (record->store == RECORD_STORE_ALLOCATED) - record->store = RECORD_STORE_EXTERNAL; + Record *record = record_get(L, 1); + if (lua_type(L, 2) == LUA_TTABLE) { + /* Assign new typeinfo to the record instance. */ + lua_pushvalue(L, 2); + lua_setfenv(L, 1); + } else { + /* Change ownership type of the record. */ + if (lua_toboolean(L, 2)) { + if (record->store == RECORD_STORE_EXTERNAL) + record->store = RECORD_STORE_ALLOCATED; + } else { + if (record->store == RECORD_STORE_ALLOCATED) + record->store = RECORD_STORE_EXTERNAL; + } } - } - return 0; + return 0; } static const struct luaL_Reg record_api_reg[] = { - { "new", record_new }, - { "query", record_query }, - { "field", record_field }, - { "cast", record_cast }, - { "fromarray", record_fromarray }, - { "set", record_set }, - { NULL, NULL } + { "new", record_new }, + { "query", record_query }, + { "field", record_field }, + { "cast", record_cast }, + { "fromarray", record_fromarray }, + { "set", record_set }, + { NULL, NULL } }; -/* Workaround for g_value_unset(), which complains when invoked on - uninitialized GValue instance. */ +/* Workaround for g_value_unset(), which complains when invoked on uninitialized GValue instance. */ static void -record_value_unset (GValue *value) +record_value_unset(GValue *value) { - if (G_IS_VALUE (value)) - g_value_unset (value); + if (G_IS_VALUE(value)) + g_value_unset(value); } -/* Similar stuff for g_value_copy(), requires target argument to be - preinitialized with proper type. */ +/* Similar stuff for g_value_copy(), requires target argument to be preinitialized with proper type. */ static void -record_value_copy (const GValue *src, GValue *dest) +record_value_copy(const GValue *src, GValue *dest) { - g_value_init (dest, G_VALUE_TYPE (src)); - g_value_copy (src, dest); + g_value_init(dest, G_VALUE_TYPE(src)); + g_value_copy(src, dest); } void -lua_gobject_record_init (lua_State *L) +lua_gobject_record_init(lua_State *L) { - /* Register record metatable. */ - lua_pushlightuserdata (L, &record_mt); - lua_newtable (L); - luaL_register (L, NULL, record_meta_reg); - lua_rawset (L, LUA_REGISTRYINDEX); - - /* Create caches. */ - lua_gobject_cache_create (L, &record_cache, "v"); - lua_gobject_cache_create (L, &parent_cache, "k"); - - /* Create 'record' API table in main core API table. */ - lua_newtable (L); - luaL_register (L, NULL, record_api_reg); - lua_pushlightuserdata (L, record_value_unset); - lua_setfield (L, -2, "value_unset"); - lua_pushlightuserdata (L, record_value_copy); - lua_setfield (L, -2, "value_copy"); - lua_setfield (L, -2, "record"); + /* Register record metatable. */ + lua_pushlightuserdata(L, &record_mt); + lua_newtable(L); + luaL_register(L, NULL, record_meta_reg); + lua_rawset(L, LUA_REGISTRYINDEX); + + /* Create caches. */ + lua_gobject_cache_create(L, &record_cache, "v"); + lua_gobject_cache_create(L, &parent_cache, "k"); + + /* Create 'record' API table in main core API table. */ + lua_newtable(L); + luaL_register(L, NULL, record_api_reg); + lua_pushlightuserdata(L, record_value_unset); + lua_setfield(L, -2, "value_unset"); + lua_pushlightuserdata(L, record_value_copy); + lua_setfield(L, -2, "value_copy"); + lua_setfield(L, -2, "record"); } diff --git a/LuaGObject/record.lua b/LuaGObject/record.lua index e5175c2c..2aac3faf 100644 --- a/LuaGObject/record.lua +++ b/LuaGObject/record.lua @@ -1,215 +1,202 @@ ------------------------------------------------------------------------------- --- --- LuaGObject - handling of structs and unions --- --- Copyright (c) 2010, 2011,2013 Pavel Holejsovsky --- Licensed under the MIT license: --- http://www.opensource.org/licenses/mit-license.php --- ------------------------------------------------------------------------------- +-- LuaGObject - handling of structs and unions +-- Copyright (c) 2010, 2011,2013 Pavel Holejsovsky +-- Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php local rawget, assert, select, pairs, type, error, setmetatable - = rawget, assert, select, pairs, type, error, setmetatable + = rawget, assert, select, pairs, type, error, setmetatable -- Require core LuaGObject utilities, used during bootstrap. local core = require 'LuaGObject.core' local gi = core.gi local component = require 'LuaGObject.component' --- Implementation of record_mt, which is inherited from component --- and provides customizations for structures and unions. +-- Implementation of record_mt, which is inherited from component and provides customizations for structures and unions. local record = { - struct_mt = component.mt:clone('struct', { '_method', '_field' }), + struct_mt = component.mt:clone('struct', { '_method', '_field' }), } -- Checks whether given argument is type of this class. function record.struct_mt:is_type_of(instance) - if type(instance) == 'userdata' then - local instance_type = core.record.query(instance, 'repo') - while instance_type do - if instance_type == self then return true end - instance_type = rawget(instance_type, '_parent') - end - end - return false + if type(instance) == 'userdata' then + local instance_type = core.record.query(instance, 'repo') + while instance_type do + if instance_type == self then return true end + instance_type = rawget(instance_type, '_parent') + end + end + return false end -- Resolver for records, recursively resolves also all parents. function record.struct_mt:_resolve(recursive) - -- Resolve itself using inherited implementation. - component.mt._resolve(self) - - -- Go to parent and resolve it too. - if recursive and self._parent then - self._parent:_resolve(recursive) - end - return self + -- Resolve itself using inherited implementation. + component.mt._resolve(self) + + -- Go to parent and resolve it too. + if recursive and self._parent then + self._parent:_resolve(recursive) + end + return self end function record.struct_mt:_element(instance, symbol) - -- First of all, try normal inherited functionality. - local element, category = component.mt._element(self, instance, symbol) - if element then - if category == '_field' then - if type(element) == 'table' and element.ret then - category = '_cbkfield' - local ffi = require 'LuaGObject.ffi' - element = { - name = element.name, - ptrfield = { element.offset, 0, ffi.types.ptr }, - callable = element - } - elseif gi.isinfo(element) and element.is_field then - local ii = element.typeinfo.interface - if ii and ii.type == 'callback' then - category = '_cbkfield' - local ffi = require 'LuaGObject.ffi' - element = { - name = element.name, - ptrfield = { element.offset, 0, ffi.types.ptr }, - callable = ii - } - end - end - end - return element, category - end - - -- Special handling of '_native' attribute. - if symbol == '_native' then return symbol, '_internal' - elseif symbol == '_type' then return symbol, '_internal' - elseif symbol == '_refsink' then return symbol, '_internal' - end - - -- If the record has parent struct, try it there. - local parent = rawget(self, '_parent') - if parent then - return parent:_element(instance, symbol) - end + -- First of all, try normal inherited functionality. + local element, category = component.mt._element(self, instance, symbol) + if element then + if category == '_field' then + if type(element) == 'table' and element.ret then + category = '_cbkfield' + local ffi = require 'LuaGObject.ffi' + element = { + name = element.name, + ptrfield = { element.offset, 0, ffi.types.ptr }, + callable = element + } + elseif gi.isinfo(element) and element.is_field then + local ii = element.typeinfo.interface + if ii and ii.type == 'callback' then + category = '_cbkfield' + local ffi = require 'LuaGObject.ffi' + element = { + name = element.name, + ptrfield = { element.offset, 0, ffi.types.ptr }, + callable = ii + } + end + end + end + return element, category + end + + -- Special handling of '_native' attribute. + if symbol == '_native' then return symbol, '_internal' + elseif symbol == '_type' then return symbol, '_internal' + elseif symbol == '_refsink' then return symbol, '_internal' + end + + -- If the record has parent struct, try it there. + local parent = rawget(self, '_parent') + if parent then + return parent:_element(instance, symbol) + end end -- Add accessor for handling fields. function record.struct_mt:_access_field(instance, element, ...) - -- Check whether we are marshalling subrecord - local subrecord - if select('#', ...) > 0 then - if gi.isinfo(element) and element.is_field then - local ii = element.typeinfo.interface - if ii and (ii.type == 'struct' or ii.type == 'union') then - subrecord = true - end - else - if type(element) == 'table' and (element[2] == 1 - or element[2] == 2) then - subrecord = true - end - end - end - - if subrecord then - -- Write to nested structure, handle assignment to it by - -- assigning separate fields. - subrecord = core.record.field(instance, element) - for name, value in pairs(...) do - subrecord[name] = value - end - else - -- In other cases, just access the instance using given info. - return core.record.field(instance, element, ...) - end + -- Check whether we are marshalling subrecord + local subrecord + if select('#', ...) > 0 then + if gi.isinfo(element) and element.is_field then + local ii = element.typeinfo.interface + if ii and (ii.type == 'struct' or ii.type == 'union') then + subrecord = true + end + else + if type(element) == 'table' and + (element[2] == 1 or element[2] == 2) then + subrecord = true + end + end + end + + if subrecord then + -- Write to nested structure, handle assignment to it by assigning separate fields. + subrecord = core.record.field(instance, element) + for name, value in pairs(...) do + subrecord[name] = value + end + else + -- In other cases, just access the instance using given info. + return core.record.field(instance, element, ...) + end end -- Add accessor for handling fields containing callbacks local guards_station = setmetatable({}, { __mode = 'k' }) function record.struct_mt:_access_cbkfield(instance, element, ...) - if select('#', ...) == 0 then - -- Reading callback field, get pointer and wrap it in proper - -- callable, so that caller can actually call it. - local addr = core.record.field(instance, element.ptrfield) - return core.callable.new(element.callable, addr) - else - local target = ... - if type(target) ~= 'userdata' then - -- Create closure over Lua target, keep guard stored. - local guard - guard, target = core.marshal.callback(element.callable, target) - local guards = guards_station[instance] - if not guards then - guards = {} - guards_station[instance] = guards - end - guards[element.name] = guard - end - core.record.field(instance, element.ptrfield, target) - end + if select('#', ...) == 0 then + -- Reading callback field, get pointer and wrap it in proper + -- callable, so that caller can actually call it. + local addr = core.record.field(instance, element.ptrfield) + return core.callable.new(element.callable, addr) + else + local target = ... + if type(target) ~= 'userdata' then + -- Create closure over Lua target, keep guard stored. + local guard + guard, target = core.marshal.callback(element.callable, target) + local guards = guards_station[instance] + if not guards then + guards = {} + guards_station[instance] = guards + end + guards[element.name] = guard + end + core.record.field(instance, element.ptrfield, target) + end end -- Add accessor for 'internal' fields handling. function record.struct_mt:_access_internal(instance, element, ...) - if select('#', ...) ~= 0 then return end - if element == '_native' then - return core.record.query(instance, 'addr') - elseif element == '_type' then - return core.record.query(instance, 'repo') - end + if select('#', ...) ~= 0 then return end + if element == '_native' then + return core.record.query(instance, 'addr') + elseif element == '_type' then + return core.record.query(instance, 'repo') + end end function record.struct_mt:_index_internal(element) - return nil + return nil end -- Create structure instance and initialize it with given fields. function record.struct_mt:_new(param, owns) - local struct - if type(param) == 'userdata' or type(param) == 'number' then - -- Wrap existing pointer. - struct = core.record.new(self, param, owns) - else - -- Check that we are allowed to create the record. - if not self._size then - error(("%s: not directly instantiable"):format(self._name), 2) - end - - -- Create the structure instance. - struct = core.record.new(self) - - -- Set values of fields. - for name, value in pairs(param or {}) do - struct[name] = value - end - end - return struct + local struct + if type(param) == 'userdata' or type(param) == 'number' then + -- Wrap existing pointer. + struct = core.record.new(self, param, owns) + else + -- Check that we are allowed to create the record. + if not self._size then + error(("%s: not directly instantiable"):format(self._name), 2) + end + + -- Create the structure instance. + struct = core.record.new(self) + + -- Set values of fields. + for name, value in pairs(param or {}) do + struct[name] = value + end + end + return struct end -- Loads structure information into table representing the structure function record.load(info) - local record = component.create( - info, info.is_struct and record.struct_mt or record.union_mt) - record._size = info.size - record._method = component.get_category(info.methods, core.callable.new) - record._field = component.get_category(info.fields) - - -- Check, whether global namespace contains 'constructor' method, - -- i.e. method which has the same name as our record type (except - -- that type is in CamelCase, while method is - -- under_score_delimited). If not found, check for 'new' method. - local func = core.downcase(info.name:gsub('([%l%d])([%u])', '%1_%2')) - local ctor = gi[info.namespace][func] or gi[info.namespace][func .. '_new'] - if not ctor then ctor = info.methods.new end - - -- Check, whether ctor is valid. In order to be valid, it must - -- return instance of this record. - if (ctor and ctor.type == 'function' - and ctor.return_type.tag =='interface' - and ctor.return_type.interface == info) then - ctor = core.callable.new(ctor) - record._new = function(typetable, ...) return ctor(...) end - end - return record + local record = component.create( + info, info.is_struct and record.struct_mt or record.union_mt) + record._size = info.size + record._method = component.get_category(info.methods, core.callable.new) + record._field = component.get_category(info.fields) + + -- Check, whether global namespace contains 'constructor' method, i.e. method which has the same name as our record type (except that type is in CamelCase, while method is under_score_delimited). If not found, check for 'new' method. + local func = core.downcase(info.name:gsub('([%l%d])([%u])', '%1_%2')) + local ctor = gi[info.namespace][func] or gi[info.namespace][func .. '_new'] + if not ctor then ctor = info.methods.new end + + -- Check, whether ctor is valid. In order to be valid, it must return instance of this record. + if (ctor and ctor.type == 'function' + and ctor.return_type.tag =='interface' + and ctor.return_type.interface == info) then + ctor = core.callable.new(ctor) + record._new = function(typetable, ...) return ctor(...) end + end + return record end --- Union metatable is the same as struct one, but has different name --- to differentiate unions. +-- Union metatable is the same as struct one, but has different name to differentiate unions. record.union_mt = record.struct_mt:clone('union') return record From 57fbb54b41bbed04873b66e059cd96b3632fe277 Mon Sep 17 00:00:00 2001 From: Victoria Lacroix Date: Mon, 29 Dec 2025 10:48:25 -0500 Subject: [PATCH 2/2] Update formatting of regression tests --- tests/gireg.lua | 2181 ++++++++++++++++++++++++----------------------- 1 file changed, 1097 insertions(+), 1084 deletions(-) diff --git a/tests/gireg.lua b/tests/gireg.lua index 396bbfd0..daf66d9c 100644 --- a/tests/gireg.lua +++ b/tests/gireg.lua @@ -1,15 +1,6 @@ ---[[-------------------------------------------------------------------------- - - LGI testsuite, GI Regress-based testsuite. - - Copyright (c) 2010, 2011 Pavel Holejsovsky - Licensed under the MIT license: - http://www.opensource.org/licenses/mit-license.php - ---]]-------------------------------------------------------------------------- - --- Note: changed during Lua 5.3 integer support conversion. --- Now 64bit integers work, but floats without representation are no longer auto-converted. +-- LuaGObject test suite using GI Regress tests. +-- Copyright (c) 2010, 2011 Pavel Holejsovsky +-- Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php local LuaGObject = require 'LuaGObject' local bytes = require 'bytes' @@ -23,1440 +14,1462 @@ local gireg = testsuite.group.new('gireg') local nativeIntegers = math.maxinteger and true or false function gireg.type_boolean() - local R = LuaGObject.Regress - checkv(R.test_boolean(true), true, 'boolean') - checkv(R.test_boolean(false), false, 'boolean') - check(select('#', R.test_boolean(true)) == 1) - check(select('#', R.test_boolean(false)) == 1) - checkv(R.test_boolean(), false, 'boolean') - checkv(R.test_boolean(nil), false, 'boolean') - checkv(R.test_boolean(0), true, 'boolean') - checkv(R.test_boolean(1), true, 'boolean') - checkv(R.test_boolean('string'), true, 'boolean') - checkv(R.test_boolean({}), true, 'boolean') - checkv(R.test_boolean(function() end), true, 'boolean') + local R = LuaGObject.Regress + checkv(R.test_boolean(true), true, 'boolean') + checkv(R.test_boolean(false), false, 'boolean') + check(select('#', R.test_boolean(true)) == 1) + check(select('#', R.test_boolean(false)) == 1) + checkv(R.test_boolean(), false, 'boolean') + checkv(R.test_boolean(nil), false, 'boolean') + checkv(R.test_boolean(0), true, 'boolean') + checkv(R.test_boolean(1), true, 'boolean') + checkv(R.test_boolean('string'), true, 'boolean') + checkv(R.test_boolean({}), true, 'boolean') + checkv(R.test_boolean(function() end), true, 'boolean') end function gireg.type_int8() - local R = LuaGObject.Regress - checkv(R.test_int8(0), 0, 'number') - checkv(R.test_int8(1), 1, 'number') - checkv(R.test_int8(-1), -1, 'number') - if not nativeIntegers then - checkv(R.test_int8(1.1), 1, 'number') - checkv(R.test_int8(-1.1), -1, 'number') - end - checkv(R.test_int8(0x7f), 0x7f, 'number') - checkv(R.test_int8(-0x80), -0x80, 'number') - check(not pcall(R.test_int8, 0x80)) - check(not pcall(R.test_int8, -0x81)) - check(not pcall(R.test_int8)) - check(not pcall(R.test_int8, nil)) - check(not pcall(R.test_int8, 'string')) - check(not pcall(R.test_int8, true)) - check(not pcall(R.test_int8, {})) - check(not pcall(R.test_int8, function() end)) + local R = LuaGObject.Regress + checkv(R.test_int8(0), 0, 'number') + checkv(R.test_int8(1), 1, 'number') + checkv(R.test_int8(-1), -1, 'number') + if not nativeIntegers then + checkv(R.test_int8(1.1), 1, 'number') + checkv(R.test_int8(-1.1), -1, 'number') + end + checkv(R.test_int8(0x7f), 0x7f, 'number') + checkv(R.test_int8(-0x80), -0x80, 'number') + check(not pcall(R.test_int8, 0x80)) + check(not pcall(R.test_int8, -0x81)) + check(not pcall(R.test_int8)) + check(not pcall(R.test_int8, nil)) + check(not pcall(R.test_int8, 'string')) + check(not pcall(R.test_int8, true)) + check(not pcall(R.test_int8, {})) + check(not pcall(R.test_int8, function() end)) end function gireg.type_uint8() - local R = LuaGObject.Regress - checkv(R.test_uint8(0), 0, 'number') - checkv(R.test_uint8(1), 1, 'number') - if not nativeIntegers then - checkv(R.test_uint8(1.1), 1, 'number') - end - checkv(R.test_uint8(0xff), 0xff, 'number') - check(not pcall(R.test_uint8, 0x100)) - check(not pcall(R.test_uint8, -1)) - check(not pcall(R.test_uint8)) - check(not pcall(R.test_uint8, nil)) - check(not pcall(R.test_uint8, 'string')) - check(not pcall(R.test_uint8, true)) - check(not pcall(R.test_uint8, {})) - check(not pcall(R.test_uint8, function() end)) + local R = LuaGObject.Regress + checkv(R.test_uint8(0), 0, 'number') + checkv(R.test_uint8(1), 1, 'number') + if not nativeIntegers then + checkv(R.test_uint8(1.1), 1, 'number') + end + checkv(R.test_uint8(0xff), 0xff, 'number') + check(not pcall(R.test_uint8, 0x100)) + check(not pcall(R.test_uint8, -1)) + check(not pcall(R.test_uint8)) + check(not pcall(R.test_uint8, nil)) + check(not pcall(R.test_uint8, 'string')) + check(not pcall(R.test_uint8, true)) + check(not pcall(R.test_uint8, {})) + check(not pcall(R.test_uint8, function() end)) end function gireg.type_int16() - local R = LuaGObject.Regress - checkv(R.test_int16(0), 0, 'number') - checkv(R.test_int16(1), 1, 'number') - checkv(R.test_int16(-1), -1, 'number') - if not nativeIntegers then - checkv(R.test_int16(1.1), 1, 'number') - checkv(R.test_int16(-1.1), -1, 'number') - end - checkv(R.test_int16(0x7fff), 0x7fff, 'number') - checkv(R.test_int16(-0x8000), -0x8000, 'number') - check(not pcall(R.test_int16, 0x8000)) - check(not pcall(R.test_int16, -0x8001)) - check(not pcall(R.test_int16)) - check(not pcall(R.test_int16, nil)) - check(not pcall(R.test_int16, 'string')) - check(not pcall(R.test_int16, true)) - check(not pcall(R.test_int16, {})) - check(not pcall(R.test_int16, function() end)) + local R = LuaGObject.Regress + checkv(R.test_int16(0), 0, 'number') + checkv(R.test_int16(1), 1, 'number') + checkv(R.test_int16(-1), -1, 'number') + if not nativeIntegers then + checkv(R.test_int16(1.1), 1, 'number') + checkv(R.test_int16(-1.1), -1, 'number') + end + checkv(R.test_int16(0x7fff), 0x7fff, 'number') + checkv(R.test_int16(-0x8000), -0x8000, 'number') + check(not pcall(R.test_int16, 0x8000)) + check(not pcall(R.test_int16, -0x8001)) + check(not pcall(R.test_int16)) + check(not pcall(R.test_int16, nil)) + check(not pcall(R.test_int16, 'string')) + check(not pcall(R.test_int16, true)) + check(not pcall(R.test_int16, {})) + check(not pcall(R.test_int16, function() end)) end function gireg.type_uint16() - local R = LuaGObject.Regress - checkv(R.test_uint16(0), 0, 'number') - checkv(R.test_uint16(1), 1, 'number') - if not nativeIntegers then - checkv(R.test_uint16(1.1), 1, 'number') - end - checkv(R.test_uint16(0xffff), 0xffff, 'number') - check(not pcall(R.test_uint16, 0x10000)) - check(not pcall(R.test_uint16, -1)) - check(not pcall(R.test_uint16)) - check(not pcall(R.test_uint16, nil)) - check(not pcall(R.test_uint16, 'string')) - check(not pcall(R.test_uint16, true)) - check(not pcall(R.test_uint16, {})) - check(not pcall(R.test_uint16, function() end)) + local R = LuaGObject.Regress + checkv(R.test_uint16(0), 0, 'number') + checkv(R.test_uint16(1), 1, 'number') + if not nativeIntegers then + checkv(R.test_uint16(1.1), 1, 'number') + end + checkv(R.test_uint16(0xffff), 0xffff, 'number') + check(not pcall(R.test_uint16, 0x10000)) + check(not pcall(R.test_uint16, -1)) + check(not pcall(R.test_uint16)) + check(not pcall(R.test_uint16, nil)) + check(not pcall(R.test_uint16, 'string')) + check(not pcall(R.test_uint16, true)) + check(not pcall(R.test_uint16, {})) + check(not pcall(R.test_uint16, function() end)) end function gireg.type_int32() - local R = LuaGObject.Regress - checkv(R.test_int32(0), 0, 'number') - checkv(R.test_int32(1), 1, 'number') - checkv(R.test_int32(-1), -1, 'number') - if not nativeIntegers then - checkv(R.test_int32(1.1), 1, 'number') - checkv(R.test_int32(-1.1), -1, 'number') - end - checkv(R.test_int32(0x7fffffff), 0x7fffffff, 'number') - checkv(R.test_int32(-0x80000000), -0x80000000, 'number') - check(not pcall(R.test_int32, 0x80000000)) - check(not pcall(R.test_int32, -0x80000001)) - check(not pcall(R.test_int32)) - check(not pcall(R.test_int32, nil)) - check(not pcall(R.test_int32, 'string')) - check(not pcall(R.test_int32, true)) - check(not pcall(R.test_int32, {})) - check(not pcall(R.test_int32, function() end)) + local R = LuaGObject.Regress + checkv(R.test_int32(0), 0, 'number') + checkv(R.test_int32(1), 1, 'number') + checkv(R.test_int32(-1), -1, 'number') + if not nativeIntegers then + checkv(R.test_int32(1.1), 1, 'number') + checkv(R.test_int32(-1.1), -1, 'number') + end + checkv(R.test_int32(0x7fffffff), 0x7fffffff, 'number') + checkv(R.test_int32(-0x80000000), -0x80000000, 'number') + check(not pcall(R.test_int32, 0x80000000)) + check(not pcall(R.test_int32, -0x80000001)) + check(not pcall(R.test_int32)) + check(not pcall(R.test_int32, nil)) + check(not pcall(R.test_int32, 'string')) + check(not pcall(R.test_int32, true)) + check(not pcall(R.test_int32, {})) + check(not pcall(R.test_int32, function() end)) end function gireg.type_uint32() - local R = LuaGObject.Regress - checkv(R.test_uint32(0), 0, 'number') - checkv(R.test_uint32(1), 1, 'number') - if not nativeIntegers then - checkv(R.test_uint32(1.1), 1, 'number') - end - checkv(R.test_uint32(0xffffffff), 0xffffffff, 'number') - check(not pcall(R.test_uint32, 0x100000000)) - check(not pcall(R.test_uint32, -1)) - check(not pcall(R.test_uint32)) - check(not pcall(R.test_uint32, nil)) - check(not pcall(R.test_uint32, 'string')) - check(not pcall(R.test_uint32, true)) - check(not pcall(R.test_uint32, {})) - check(not pcall(R.test_uint32, function() end)) + local R = LuaGObject.Regress + checkv(R.test_uint32(0), 0, 'number') + checkv(R.test_uint32(1), 1, 'number') + if not nativeIntegers then + checkv(R.test_uint32(1.1), 1, 'number') + end + checkv(R.test_uint32(0xffffffff), 0xffffffff, 'number') + check(not pcall(R.test_uint32, 0x100000000)) + check(not pcall(R.test_uint32, -1)) + check(not pcall(R.test_uint32)) + check(not pcall(R.test_uint32, nil)) + check(not pcall(R.test_uint32, 'string')) + check(not pcall(R.test_uint32, true)) + check(not pcall(R.test_uint32, {})) + check(not pcall(R.test_uint32, function() end)) end function gireg.type_int64() - local R = LuaGObject.Regress - checkv(R.test_int64(0), 0, 'number') - checkv(R.test_int64(1), 1, 'number') - checkv(R.test_int64(-1), -1, 'number') - if not nativeIntegers then - checkv(R.test_int64(1.1), 1, 'number') - checkv(R.test_int64(-1.1), -1, 'number') - end - check(not pcall(R.test_int64)) - check(not pcall(R.test_int64, nil)) - check(not pcall(R.test_int64, 'string')) - check(not pcall(R.test_int64, true)) - check(not pcall(R.test_int64, {})) - check(not pcall(R.test_int64, function() end)) - --- Following tests fail because Lua's internal number representation --- is always 'double', and conversion between double and int64 big --- constants is always lossy. Not sure if it can be solved somehow. - --- UPDATE: It IS working in Lua 5.3 because of its integer support, --- so tests are enabled there. + local R = LuaGObject.Regress + checkv(R.test_int64(0), 0, 'number') + checkv(R.test_int64(1), 1, 'number') + checkv(R.test_int64(-1), -1, 'number') + if not nativeIntegers then + checkv(R.test_int64(1.1), 1, 'number') + checkv(R.test_int64(-1.1), -1, 'number') + end + check(not pcall(R.test_int64)) + check(not pcall(R.test_int64, nil)) + check(not pcall(R.test_int64, 'string')) + check(not pcall(R.test_int64, true)) + check(not pcall(R.test_int64, {})) + check(not pcall(R.test_int64, function() end)) + + -- These tests fail on versions of Lua before 5.3 as their only numeric type is double-precision floating point, which cannot represent 64-bit integers. Lua 5.3 and later run these tests without issue. + if nativeIntegers then + checkv(R.test_int64(0x7fffffffffffffff), 0x7fffffffffffffff, 'number') + checkv(R.test_int64(-0x8000000000000000), -0x8000000000000000, 'number') + + -- These two tests have been disabled because they are inconsistent with expected behaviour. + --check(not pcall(R.test_int64, 0x8000000000000000)) + --check(not pcall(R.test_int64, -0x8000000000000001)) + end - if nativeIntegers then - checkv(R.test_int64(0x7fffffffffffffff), 0x7fffffffffffffff, 'number') - checkv(R.test_int64(-0x8000000000000000), -0x8000000000000000, 'number') - end - - -- Following two lines succeed in Lua 5.3 but make no sense. - - --check(not pcall(R.test_int64, 0x8000000000000000)) - --check(not pcall(R.test_int64, -0x8000000000000001)) end function gireg.type_uint64() - local R = LuaGObject.Regress - checkv(R.test_uint64(0), 0, 'number') - checkv(R.test_uint64(1), 1, 'number') - if not nativeIntegers then - checkv(R.test_uint64(1.1), 1, 'number') - end - check(not pcall(R.test_uint64, -1)) - check(not pcall(R.test_uint64)) - check(not pcall(R.test_uint64, nil)) - check(not pcall(R.test_uint64, 'string')) - check(not pcall(R.test_uint64, true)) - check(not pcall(R.test_uint64, {})) - check(not pcall(R.test_uint64, function() end)) - --- See comment above about lossy conversions. - --- UPDATE: fail in Lua 5.3 too because it don't have unsigned integers. --- 0xffffffffffffffff == -1 - --- checkv(R.test_uint64(0xffffffffffffffff), 0xffffffffffffffff, 'number') --- check(not pcall(R.test_uint64, 0x10000000000000000)) + local R = LuaGObject.Regress + checkv(R.test_uint64(0), 0, 'number') + checkv(R.test_uint64(1), 1, 'number') + if not nativeIntegers then + checkv(R.test_uint64(1.1), 1, 'number') + end + check(not pcall(R.test_uint64, -1)) + check(not pcall(R.test_uint64)) + check(not pcall(R.test_uint64, nil)) + check(not pcall(R.test_uint64, 'string')) + check(not pcall(R.test_uint64, true)) + check(not pcall(R.test_uint64, {})) + check(not pcall(R.test_uint64, function() end)) + + -- See comment above about lossy conversions. + --checkv(R.test_uint64(0xffffffffffffffff), 0xffffffffffffffff, 'number') + --check(not pcall(R.test_uint64, 0x10000000000000000)) end function gireg.type_short() - local R = LuaGObject.Regress - checkv(R.test_short(0), 0, 'number') - checkv(R.test_short(1), 1, 'number') - checkv(R.test_short(-1), -1, 'number') - if not nativeIntegers then - checkv(R.test_short(1.1), 1, 'number') - checkv(R.test_short(-1.1), -1, 'number') - end + local R = LuaGObject.Regress + checkv(R.test_short(0), 0, 'number') + checkv(R.test_short(1), 1, 'number') + checkv(R.test_short(-1), -1, 'number') + if not nativeIntegers then + checkv(R.test_short(1.1), 1, 'number') + checkv(R.test_short(-1.1), -1, 'number') + end end function gireg.type_ushort() - local R = LuaGObject.Regress - checkv(R.test_ushort(0), 0, 'number') - checkv(R.test_ushort(1), 1, 'number') - if not nativeIntegers then - checkv(R.test_ushort(1.1), 1, 'number') - end - check(not pcall(R.test_ushort, -1)) + local R = LuaGObject.Regress + checkv(R.test_ushort(0), 0, 'number') + checkv(R.test_ushort(1), 1, 'number') + if not nativeIntegers then + checkv(R.test_ushort(1.1), 1, 'number') + end + check(not pcall(R.test_ushort, -1)) end function gireg.type_int() - local R = LuaGObject.Regress - checkv(R.test_int(0), 0, 'number') - checkv(R.test_int(1), 1, 'number') - checkv(R.test_int(-1), -1, 'number') - if not nativeIntegers then - checkv(R.test_int(1.1), 1, 'number') - checkv(R.test_int(-1.1), -1, 'number') - end + local R = LuaGObject.Regress + checkv(R.test_int(0), 0, 'number') + checkv(R.test_int(1), 1, 'number') + checkv(R.test_int(-1), -1, 'number') + if not nativeIntegers then + checkv(R.test_int(1.1), 1, 'number') + checkv(R.test_int(-1.1), -1, 'number') + end end function gireg.type_uint() - local R = LuaGObject.Regress - checkv(R.test_uint(0), 0, 'number') - checkv(R.test_uint(1), 1, 'number') - if not nativeIntegers then - checkv(R.test_uint(1.1), 1, 'number') - end - check(not pcall(R.test_uint, -1)) + local R = LuaGObject.Regress + checkv(R.test_uint(0), 0, 'number') + checkv(R.test_uint(1), 1, 'number') + if not nativeIntegers then + checkv(R.test_uint(1.1), 1, 'number') + end + check(not pcall(R.test_uint, -1)) end function gireg.type_ssize() - local R = LuaGObject.Regress - checkv(R.test_ssize(0), 0, 'number') - checkv(R.test_ssize(1), 1, 'number') - checkv(R.test_ssize(-1), -1, 'number') - if not nativeIntegers then - checkv(R.test_ssize(1.1), 1, 'number') - checkv(R.test_ssize(-1.1), -1, 'number') - end + local R = LuaGObject.Regress + checkv(R.test_ssize(0), 0, 'number') + checkv(R.test_ssize(1), 1, 'number') + checkv(R.test_ssize(-1), -1, 'number') + if not nativeIntegers then + checkv(R.test_ssize(1.1), 1, 'number') + checkv(R.test_ssize(-1.1), -1, 'number') + end end function gireg.type_size() - local R = LuaGObject.Regress - checkv(R.test_size(0), 0, 'number') - checkv(R.test_size(1), 1, 'number') - if not nativeIntegers then - checkv(R.test_size(1.1), 1, 'number') - end - check(not pcall(R.test_size, -1)) + local R = LuaGObject.Regress + checkv(R.test_size(0), 0, 'number') + checkv(R.test_size(1), 1, 'number') + if not nativeIntegers then + checkv(R.test_size(1.1), 1, 'number') + end + check(not pcall(R.test_size, -1)) end -- Helper, checks that given value has requested type and value, with some -- tolerance because of low precision of gfloat type. local function checkvf(val, exp, tolerance) - check(type(val) == 'number', string.format( - "got type `%s', expected `number'", type(val)), 2) - check(math.abs(val - exp) <= tolerance, - string.format("got value `%s', expected `%s'", + check(type(val) == 'number', + string.format("got type `%s', expected `number'", type(val)), 2) + check(math.abs(val - exp) <= tolerance, + string.format("got value `%s', expected `%s'", tostring(val), tostring(exp)), 2) end function gireg.type_float() - local R = LuaGObject.Regress - local t = 0.0000001 - checkvf(R.test_float(0), 0, t) - checkvf(R.test_float(1), 1, t) - checkvf(R.test_float(1.1), 1.1, t) - checkvf(R.test_float(-1), -1, t) - checkvf(R.test_float(-1.1), -1.1, t) - checkvf(R.test_float(0x8000), 0x8000, t) - checkvf(R.test_float(0xffff), 0xffff, t) - checkvf(R.test_float(-0x8000), -0x8000, t) - checkvf(R.test_float(-0xffff), -0xffff, t) - check(not pcall(R.test_float)) - check(not pcall(R.test_float, nil)) - check(not pcall(R.test_float, 'string')) - check(not pcall(R.test_float, true)) - check(not pcall(R.test_float, {})) - check(not pcall(R.test_float, function() end)) + local R = LuaGObject.Regress + local t = 0.0000001 + checkvf(R.test_float(0), 0, t) + checkvf(R.test_float(1), 1, t) + checkvf(R.test_float(1.1), 1.1, t) + checkvf(R.test_float(-1), -1, t) + checkvf(R.test_float(-1.1), -1.1, t) + checkvf(R.test_float(0x8000), 0x8000, t) + checkvf(R.test_float(0xffff), 0xffff, t) + checkvf(R.test_float(-0x8000), -0x8000, t) + checkvf(R.test_float(-0xffff), -0xffff, t) + check(not pcall(R.test_float)) + check(not pcall(R.test_float, nil)) + check(not pcall(R.test_float, 'string')) + check(not pcall(R.test_float, true)) + check(not pcall(R.test_float, {})) + check(not pcall(R.test_float, function() end)) end function gireg.type_double() - local R = LuaGObject.Regress - checkv(R.test_double(0), 0, 'number') - checkv(R.test_double(1), 1, 'number') - checkv(R.test_double(1.1), 1.1, 'number') - checkv(R.test_double(-1), -1, 'number') - checkv(R.test_double(-1.1), -1.1, 'number') - checkv(R.test_double(0x80000000), 0x80000000, 'number') - checkv(R.test_double(0xffffffff), 0xffffffff, 'number') - checkv(R.test_double(-0x80000000), -0x80000000, 'number') - checkv(R.test_double(-0xffffffff), -0xffffffff, 'number') - check(not pcall(R.test_double)) - check(not pcall(R.test_double, nil)) - check(not pcall(R.test_double, 'string')) - check(not pcall(R.test_double, true)) - check(not pcall(R.test_double, {})) - check(not pcall(R.test_double, function() end)) + local R = LuaGObject.Regress + checkv(R.test_double(0), 0, 'number') + checkv(R.test_double(1), 1, 'number') + checkv(R.test_double(1.1), 1.1, 'number') + checkv(R.test_double(-1), -1, 'number') + checkv(R.test_double(-1.1), -1.1, 'number') + checkv(R.test_double(0x80000000), 0x80000000, 'number') + checkv(R.test_double(0xffffffff), 0xffffffff, 'number') + checkv(R.test_double(-0x80000000), -0x80000000, 'number') + checkv(R.test_double(-0xffffffff), -0xffffffff, 'number') + check(not pcall(R.test_double)) + check(not pcall(R.test_double, nil)) + check(not pcall(R.test_double, 'string')) + check(not pcall(R.test_double, true)) + check(not pcall(R.test_double, {})) + check(not pcall(R.test_double, function() end)) end function gireg.type_timet() - local R = LuaGObject.Regress - checkv(R.test_timet(0), 0, 'number') - checkv(R.test_timet(1), 1, 'number') - checkv(R.test_timet(10000), 10000, 'number') - check(not pcall(R.test_timet)) - check(not pcall(R.test_timet, nil)) - check(not pcall(R.test_timet, 'string')) - check(not pcall(R.test_timet, true)) - check(not pcall(R.test_timet, {})) - check(not pcall(R.test_timet, function() end)) + local R = LuaGObject.Regress + checkv(R.test_timet(0), 0, 'number') + checkv(R.test_timet(1), 1, 'number') + checkv(R.test_timet(10000), 10000, 'number') + check(not pcall(R.test_timet)) + check(not pcall(R.test_timet, nil)) + check(not pcall(R.test_timet, 'string')) + check(not pcall(R.test_timet, true)) + check(not pcall(R.test_timet, {})) + check(not pcall(R.test_timet, function() end)) end function gireg.type_gtype() - local R = LuaGObject.Regress - checkv(R.test_gtype(), nil, 'nil') - checkv(R.test_gtype(nil), nil, 'nil') - checkv(R.test_gtype(0), nil, 'nil') - checkv(R.test_gtype('void'), 'void', 'string') - checkv(R.test_gtype(4), 'void', 'string') - checkv(R.test_gtype('GObject'), 'GObject', 'string') - checkv(R.test_gtype(80), 'GObject', 'string') - checkv(R.test_gtype(R.TestObj), 'RegressTestObj', 'string') - check(not pcall(R.test_gtype, true)) - check(not pcall(R.test_gtype, function() end)) + local R = LuaGObject.Regress + checkv(R.test_gtype(), nil, 'nil') + checkv(R.test_gtype(nil), nil, 'nil') + checkv(R.test_gtype(0), nil, 'nil') + checkv(R.test_gtype('void'), 'void', 'string') + checkv(R.test_gtype(4), 'void', 'string') + checkv(R.test_gtype('GObject'), 'GObject', 'string') + checkv(R.test_gtype(80), 'GObject', 'string') + checkv(R.test_gtype(R.TestObj), 'RegressTestObj', 'string') + check(not pcall(R.test_gtype, true)) + check(not pcall(R.test_gtype, function() end)) end function gireg.utf8_const_return() - local R = LuaGObject.Regress - local utf8_const = 'const \226\153\165 utf8' - check(R.test_utf8_const_return() == utf8_const) + local R = LuaGObject.Regress + local utf8_const = 'const \226\153\165 utf8' + check(R.test_utf8_const_return() == utf8_const) end function gireg.utf8_nonconst_return() - local R = LuaGObject.Regress - local utf8_nonconst = 'nonconst \226\153\165 utf8' - check(R.test_utf8_nonconst_return() == utf8_nonconst) + local R = LuaGObject.Regress + local utf8_nonconst = 'nonconst \226\153\165 utf8' + check(R.test_utf8_nonconst_return() == utf8_nonconst) end function gireg.utf8_const_in() - local R = LuaGObject.Regress - local utf8_const = 'const \226\153\165 utf8' - R.test_utf8_const_in(utf8_const) - R.test_utf8_const_in(bytes.new(utf8_const .. '\0')) + local R = LuaGObject.Regress + local utf8_const = 'const \226\153\165 utf8' + R.test_utf8_const_in(utf8_const) + R.test_utf8_const_in(bytes.new(utf8_const .. '\0')) end function gireg.utf8_out() - local R = LuaGObject.Regress - local utf8_nonconst = 'nonconst \226\153\165 utf8' - check(R.test_utf8_out() == utf8_nonconst) + local R = LuaGObject.Regress + local utf8_nonconst = 'nonconst \226\153\165 utf8' + check(R.test_utf8_out() == utf8_nonconst) end function gireg.utf8_inout() - local R = LuaGObject.Regress - local utf8_const = 'const \226\153\165 utf8' - local utf8_nonconst = 'nonconst \226\153\165 utf8' - check(R.test_utf8_inout(utf8_const) == utf8_nonconst) + local R = LuaGObject.Regress + local utf8_const = 'const \226\153\165 utf8' + local utf8_nonconst = 'nonconst \226\153\165 utf8' + check(R.test_utf8_inout(utf8_const) == utf8_nonconst) end function gireg.filename_return() - local R = LuaGObject.Regress - local fns = R.test_filename_return() - check(type(fns) == 'table') - check(#fns == 2) - check(fns[1] == 'åäö') - check(fns[2] == '/etc/fstab') + local R = LuaGObject.Regress + local fns = R.test_filename_return() + check(type(fns) == 'table') + check(#fns == 2) + check(fns[1] == 'åäö') + check(fns[2] == '/etc/fstab') end function gireg.utf8_int_out_utf8() - local R = LuaGObject.Regress - check(R.test_int_out_utf8('') == 0) - check(R.test_int_out_utf8('abc') == 3) - local utf8_const = 'const \226\153\165 utf8' - check(R.test_int_out_utf8(utf8_const) == 12) + local R = LuaGObject.Regress + check(R.test_int_out_utf8('') == 0) + check(R.test_int_out_utf8('abc') == 3) + local utf8_const = 'const \226\153\165 utf8' + check(R.test_int_out_utf8(utf8_const) == 12) end function gireg.multi_double_args() - local R = LuaGObject.Regress - local o1, o2 = R.test_multi_double_args(1) - check(o1 == 2 and o2 == 3) - check(#{R.test_multi_double_args(1)} == 2) + local R = LuaGObject.Regress + local o1, o2 = R.test_multi_double_args(1) + check(o1 == 2 and o2 == 3) + check(#{R.test_multi_double_args(1)} == 2) end function gireg.utf8_out_out() - local R = LuaGObject.Regress - local o1, o2 = R.test_utf8_out_out() - check(o1 == 'first' and o2 == 'second') - check(#{R.test_utf8_out_out()} == 2) + local R = LuaGObject.Regress + local o1, o2 = R.test_utf8_out_out() + check(o1 == 'first' and o2 == 'second') + check(#{R.test_utf8_out_out()} == 2) end function gireg.utf8_out_nonconst_return() - local R = LuaGObject.Regress - local o1, o2 = R.test_utf8_out_nonconst_return() - check(o1 == 'first' and o2 == 'second') - check(#{R.test_utf8_out_nonconst_return()} == 2) + local R = LuaGObject.Regress + local o1, o2 = R.test_utf8_out_nonconst_return() + check(o1 == 'first' and o2 == 'second') + check(#{R.test_utf8_out_nonconst_return()} == 2) end function gireg.utf8_null_in() - local R = LuaGObject.Regress - R.test_utf8_null_in(nil) - R.test_utf8_null_in() + local R = LuaGObject.Regress + R.test_utf8_null_in(nil) + R.test_utf8_null_in() end function gireg.utf8_null_out() - local R = LuaGObject.Regress - check(R.test_utf8_null_out() == nil) + local R = LuaGObject.Regress + check(R.test_utf8_null_out() == nil) end function gireg.array_int_in() - local R = LuaGObject.Regress - check(R.test_array_int_in{1,2,3} == 6) - if not nativeIntegers then - check(R.test_array_int_in{1.1,2,3} == 6) - end - check(R.test_array_int_in{} == 0) - check(not pcall(R.test_array_int_in, nil)) - check(not pcall(R.test_array_int_in, 'help')) - check(not pcall(R.test_array_int_in, {'help'})) + local R = LuaGObject.Regress + check(R.test_array_int_in{1,2,3} == 6) + if not nativeIntegers then + check(R.test_array_int_in{1.1,2,3} == 6) + end + check(R.test_array_int_in{} == 0) + check(not pcall(R.test_array_int_in, nil)) + check(not pcall(R.test_array_int_in, 'help')) + check(not pcall(R.test_array_int_in, {'help'})) end function gireg.array_int_out() - local R = LuaGObject.Regress - local a = R.test_array_int_out() - check(#a == 5) - check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) - check(#{R.test_array_int_out()} == 1) + local R = LuaGObject.Regress + local a = R.test_array_int_out() + check(#a == 5) + check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) + check(#{R.test_array_int_out()} == 1) end function gireg.array_int_inout() - local R = LuaGObject.Regress - local a = R.test_array_int_inout({1, 2, 3, 4, 5}) - check(#a == 4) - check(a[1] == 3 and a[2] == 4 and a[3] == 5 and a[4] == 6) - check(#{R.test_array_int_inout({1, 2, 3, 4, 5})} == 1) - check(not pcall(R.test_array_int_inout, nil)) - check(not pcall(R.test_array_int_inout, 'help')) - check(not pcall(R.test_array_int_inout, {'help'})) + local R = LuaGObject.Regress + local a = R.test_array_int_inout({1, 2, 3, 4, 5}) + check(#a == 4) + check(a[1] == 3 and a[2] == 4 and a[3] == 5 and a[4] == 6) + check(#{R.test_array_int_inout({1, 2, 3, 4, 5})} == 1) + check(not pcall(R.test_array_int_inout, nil)) + check(not pcall(R.test_array_int_inout, 'help')) + check(not pcall(R.test_array_int_inout, {'help'})) end function gireg.array_gint8_in() - local R = LuaGObject.Regress - check(R.test_array_gint8_in{1,2,3} == 6) - if not nativeIntegers then - check(R.test_array_gint8_in{1.1,2,3} == 6) - end - check(R.test_array_gint8_in('0123') == 48 + 49 + 50 + 51) - check(R.test_array_gint8_in(bytes.new('0123')) == 48 + 49 + 50 + 51) - check(R.test_array_gint8_in{} == 0) - check(not pcall(R.test_array_gint8_in, nil)) - check(not pcall(R.test_array_gint8_in, {'help'})) + local R = LuaGObject.Regress + check(R.test_array_gint8_in{1,2,3} == 6) + if not nativeIntegers then + check(R.test_array_gint8_in{1.1,2,3} == 6) + end + check(R.test_array_gint8_in('0123') == 48 + 49 + 50 + 51) + check(R.test_array_gint8_in(bytes.new('0123')) == 48 + 49 + 50 + 51) + check(R.test_array_gint8_in{} == 0) + check(not pcall(R.test_array_gint8_in, nil)) + check(not pcall(R.test_array_gint8_in, {'help'})) end function gireg.array_gint16_in() - local R = LuaGObject.Regress - check(R.test_array_gint16_in{1,2,3} == 6) - if not nativeIntegers then - check(R.test_array_gint16_in{1.1,2,3} == 6) - end - check(R.test_array_gint16_in{} == 0) - check(not pcall(R.test_array_gint16_in, nil)) - check(not pcall(R.test_array_gint16_in, 'help')) - check(not pcall(R.test_array_gint16_in, {'help'})) + local R = LuaGObject.Regress + check(R.test_array_gint16_in{1,2,3} == 6) + if not nativeIntegers then + check(R.test_array_gint16_in{1.1,2,3} == 6) + end + check(R.test_array_gint16_in{} == 0) + check(not pcall(R.test_array_gint16_in, nil)) + check(not pcall(R.test_array_gint16_in, 'help')) + check(not pcall(R.test_array_gint16_in, {'help'})) end function gireg.array_gint32_in() - local R = LuaGObject.Regress - check(R.test_array_gint32_in{1,2,3} == 6) - if not nativeIntegers then - check(R.test_array_gint32_in{1.1,2,3} == 6) - end - check(R.test_array_gint32_in{} == 0) - check(not pcall(R.test_array_gint32_in, nil)) - check(not pcall(R.test_array_gint32_in, 'help')) - check(not pcall(R.test_array_gint32_in, {'help'})) + local R = LuaGObject.Regress + check(R.test_array_gint32_in{1,2,3} == 6) + if not nativeIntegers then + check(R.test_array_gint32_in{1.1,2,3} == 6) + end + check(R.test_array_gint32_in{} == 0) + check(not pcall(R.test_array_gint32_in, nil)) + check(not pcall(R.test_array_gint32_in, 'help')) + check(not pcall(R.test_array_gint32_in, {'help'})) end function gireg.array_gint64_in() - local R = LuaGObject.Regress - check(R.test_array_gint64_in{1,2,3} == 6) - if not nativeIntegers then - check(R.test_array_gint64_in{1.1,2,3} == 6) - end - check(R.test_array_gint64_in{} == 0) - check(not pcall(R.test_array_gint64_in, nil)) - check(not pcall(R.test_array_gint64_in, 'help')) - check(not pcall(R.test_array_gint64_in, {'help'})) + local R = LuaGObject.Regress + check(R.test_array_gint64_in{1,2,3} == 6) + if not nativeIntegers then + check(R.test_array_gint64_in{1.1,2,3} == 6) + end + check(R.test_array_gint64_in{} == 0) + check(not pcall(R.test_array_gint64_in, nil)) + check(not pcall(R.test_array_gint64_in, 'help')) + check(not pcall(R.test_array_gint64_in, {'help'})) end function gireg.array_strv_in() - local R = LuaGObject.Regress - check(R.test_strv_in{'1', '2', '3'}) - check(not pcall(R.test_strv_in)) - check(not pcall(R.test_strv_in, '1')) - check(not pcall(R.test_strv_in, 1)) - check(not R.test_strv_in{'3', '2', '1'}) - check(not R.test_strv_in{'1', '2', '3', '4'}) + local R = LuaGObject.Regress + check(R.test_strv_in{'1', '2', '3'}) + check(not pcall(R.test_strv_in)) + check(not pcall(R.test_strv_in, '1')) + check(not pcall(R.test_strv_in, 1)) + check(not R.test_strv_in{'3', '2', '1'}) + check(not R.test_strv_in{'1', '2', '3', '4'}) end function gireg.array_gtype_in() - local R = LuaGObject.Regress - local GObject = LuaGObject.GObject - local str = R.test_array_gtype_in { - LuaGObject.GObject.Value._gtype, - LuaGObject.GObject.type_from_name('gchar') - } - check(str == '[GValue,gchar,]') - check(R.test_array_gtype_in({}) == '[]') - check(not pcall(R.test_array_gtype_in)) - check(not pcall(R.test_array_gtype_in, '')) - check(not pcall(R.test_array_gtype_in, 1)) - check(not pcall(R.test_array_gtype_in, function() end)) + local R = LuaGObject.Regress + local GObject = LuaGObject.GObject + local str = R.test_array_gtype_in { + LuaGObject.GObject.Value._gtype, + LuaGObject.GObject.type_from_name('gchar') + } + check(str == '[GValue,gchar,]') + check(R.test_array_gtype_in({}) == '[]') + check(not pcall(R.test_array_gtype_in)) + check(not pcall(R.test_array_gtype_in, '')) + check(not pcall(R.test_array_gtype_in, 1)) + check(not pcall(R.test_array_gtype_in, function() end)) end function gireg.array_strv_out() - local R = LuaGObject.Regress - local a = R.test_strv_out() - check(type(a) == 'table' and #a == 5) - check(table.concat(a, ' ') == 'thanks for all the fish') - check(#{R.test_strv_out()} == 1) + local R = LuaGObject.Regress + local a = R.test_strv_out() + check(type(a) == 'table' and #a == 5) + check(table.concat(a, ' ') == 'thanks for all the fish') + check(#{R.test_strv_out()} == 1) end function gireg.array_strv_out_container() - local R = LuaGObject.Regress - local a = R.test_strv_out_container() - check(type(a) == 'table' and #a == 3) - check(table.concat(a, ' ') == '1 2 3') + local R = LuaGObject.Regress + local a = R.test_strv_out_container() + check(type(a) == 'table' and #a == 3) + check(table.concat(a, ' ') == '1 2 3') end function gireg.array_strv_outarg() - local R = LuaGObject.Regress - local a = R.test_strv_outarg() - check(type(a) == 'table' and #a == 3) - check(table.concat(a, ' ') == '1 2 3') - check(#{R.test_strv_outarg()} == 1) + local R = LuaGObject.Regress + local a = R.test_strv_outarg() + check(type(a) == 'table' and #a == 3) + check(table.concat(a, ' ') == '1 2 3') + check(#{R.test_strv_outarg()} == 1) end function gireg.array_fixed_size_int_out() - local R = LuaGObject.Regress - local a = R.test_array_fixed_size_int_out() - check(type(a) == 'table' and #a == 5) - check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) - check(#{R.test_array_fixed_size_int_out()} == 1) + local R = LuaGObject.Regress + local a = R.test_array_fixed_size_int_out() + check(type(a) == 'table' and #a == 5) + check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) + check(#{R.test_array_fixed_size_int_out()} == 1) end function gireg.array_fixed_size_int_return() - local R = LuaGObject.Regress - local a = R.test_array_fixed_size_int_return() - check(type(a) == 'table' and #a == 5) - check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) - check(#{R.test_array_fixed_size_int_return()} == 1) + local R = LuaGObject.Regress + local a = R.test_array_fixed_size_int_return() + check(type(a) == 'table' and #a == 5) + check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) + check(#{R.test_array_fixed_size_int_return()} == 1) end function gireg.array_strv_out_c() - local R = LuaGObject.Regress - local a = R.test_strv_out_c() - check(type(a) == 'table' and #a == 5) - check(table.concat(a, ' ') == 'thanks for all the fish') + local R = LuaGObject.Regress + local a = R.test_strv_out_c() + check(type(a) == 'table' and #a == 5) + check(table.concat(a, ' ') == 'thanks for all the fish') end function gireg.array_int_full_out() - local R = LuaGObject.Regress - local a = R.test_array_int_full_out() - check(type(a) == 'table' and #a == 5) - check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) - check(#{R.test_array_int_full_out()} == 1) + local R = LuaGObject.Regress + local a = R.test_array_int_full_out() + check(type(a) == 'table' and #a == 5) + check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) + check(#{R.test_array_int_full_out()} == 1) end function gireg.array_int_full_out() - local R = LuaGObject.Regress - local a = R.test_array_int_full_out() - check(type(a) == 'table' and #a == 5) - check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) - check(#{R.test_array_int_full_out()} == 1) + local R = LuaGObject.Regress + local a = R.test_array_int_full_out() + check(type(a) == 'table' and #a == 5) + check(a[1] == 0 and a[2] == 1 and a[3] == 2 and a[4] == 3 and a[5] == 4) + check(#{R.test_array_int_full_out()} == 1) end function gireg.array_int_null_in() - local R = LuaGObject.Regress - R.test_array_int_null_in() - R.test_array_int_null_in(nil) + local R = LuaGObject.Regress + R.test_array_int_null_in() + R.test_array_int_null_in(nil) end function gireg.array_int_null_out() - local R = LuaGObject.Regress - local a = R.test_array_int_null_out() - check(type(a) == 'table' and not next(a)) + local R = LuaGObject.Regress + local a = R.test_array_int_null_out() + check(type(a) == 'table' and not next(a)) end function gireg.glist_nothing_return() - local R = LuaGObject.Regress - check(select('#', R.test_glist_nothing_return()) == 1) - a = R.test_glist_nothing_return() - check(type(a) == 'table' and #a == 3) - check(a[1] == '1' and a[2] == '2' and a[3] == '3') + local R = LuaGObject.Regress + check(select('#', R.test_glist_nothing_return()) == 1) + a = R.test_glist_nothing_return() + check(type(a) == 'table' and #a == 3) + check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.glist_nothing_return2() - local R = LuaGObject.Regress - check(select('#', R.test_glist_nothing_return2()) == 1) - a = R.test_glist_nothing_return2() - check(type(a) == 'table' and #a == 3) - check(a[1] == '1' and a[2] == '2' and a[3] == '3') + local R = LuaGObject.Regress + check(select('#', R.test_glist_nothing_return2()) == 1) + a = R.test_glist_nothing_return2() + check(type(a) == 'table' and #a == 3) + check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.glist_container_return() - local R = LuaGObject.Regress - check(select('#', R.test_glist_container_return()) == 1) - a = R.test_glist_container_return() - check(type(a) == 'table' and #a == 3) - check(a[1] == '1' and a[2] == '2' and a[3] == '3') + local R = LuaGObject.Regress + check(select('#', R.test_glist_container_return()) == 1) + a = R.test_glist_container_return() + check(type(a) == 'table' and #a == 3) + check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.glist_everything_return() - local R = LuaGObject.Regress - check(select('#', R.test_glist_everything_return()) == 1) - a = R.test_glist_everything_return() - check(type(a) == 'table' and #a == 3) - check(a[1] == '1' and a[2] == '2' and a[3] == '3') + local R = LuaGObject.Regress + check(select('#', R.test_glist_everything_return()) == 1) + a = R.test_glist_everything_return() + check(type(a) == 'table' and #a == 3) + check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.glist_nothing_in() - local R = LuaGObject.Regress - R.test_glist_nothing_in {'1', '2', '3'} + local R = LuaGObject.Regress + R.test_glist_nothing_in {'1', '2', '3'} end function gireg.glist_nothing_in2() - local R = LuaGObject.Regress - R.test_glist_nothing_in2 {'1', '2', '3'} + local R = LuaGObject.Regress + R.test_glist_nothing_in2 {'1', '2', '3'} end function gireg.glist_null_in() - local R = LuaGObject.Regress - R.test_glist_null_in {} - R.test_glist_null_in(nil) - R.test_glist_null_in() + local R = LuaGObject.Regress + R.test_glist_null_in {} + R.test_glist_null_in(nil) + R.test_glist_null_in() end function gireg.glist_null_out() - local R = LuaGObject.Regress - check(select('#', R.test_glist_null_out()) == 1) - local a = R.test_glist_null_out() - check(type(a) == 'table' and #a == 0) + local R = LuaGObject.Regress + check(select('#', R.test_glist_null_out()) == 1) + local a = R.test_glist_null_out() + check(type(a) == 'table' and #a == 0) end function gireg.gslist_nothing_return() - local R = LuaGObject.Regress - check(select('#', R.test_gslist_nothing_return()) == 1) - a = R.test_gslist_nothing_return() - check(type(a) == 'table' and #a == 3) - check(a[1] == '1' and a[2] == '2' and a[3] == '3') + local R = LuaGObject.Regress + check(select('#', R.test_gslist_nothing_return()) == 1) + a = R.test_gslist_nothing_return() + check(type(a) == 'table' and #a == 3) + check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.gslist_nothing_return2() - local R = LuaGObject.Regress - check(select('#', R.test_gslist_nothing_return2()) == 1) - a = R.test_gslist_nothing_return2() - check(type(a) == 'table' and #a == 3) - check(a[1] == '1' and a[2] == '2' and a[3] == '3') + local R = LuaGObject.Regress + check(select('#', R.test_gslist_nothing_return2()) == 1) + a = R.test_gslist_nothing_return2() + check(type(a) == 'table' and #a == 3) + check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.gslist_container_return() - local R = LuaGObject.Regress - check(select('#', R.test_gslist_container_return()) == 1) - a = R.test_gslist_container_return() - check(type(a) == 'table' and #a == 3) - check(a[1] == '1' and a[2] == '2' and a[3] == '3') + local R = LuaGObject.Regress + check(select('#', R.test_gslist_container_return()) == 1) + a = R.test_gslist_container_return() + check(type(a) == 'table' and #a == 3) + check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.gslist_everything_return() - local R = LuaGObject.Regress - check(select('#', R.test_gslist_everything_return()) == 1) - a = R.test_gslist_everything_return() - check(type(a) == 'table' and #a == 3) - check(a[1] == '1' and a[2] == '2' and a[3] == '3') + local R = LuaGObject.Regress + check(select('#', R.test_gslist_everything_return()) == 1) + a = R.test_gslist_everything_return() + check(type(a) == 'table' and #a == 3) + check(a[1] == '1' and a[2] == '2' and a[3] == '3') end function gireg.gslist_nothing_in() - local R = LuaGObject.Regress - R.test_gslist_nothing_in {'1', '2', '3'} + local R = LuaGObject.Regress + R.test_gslist_nothing_in {'1', '2', '3'} end function gireg.gslist_nothing_in2() - local R = LuaGObject.Regress - R.test_gslist_nothing_in2 {'1', '2', '3'} + local R = LuaGObject.Regress + R.test_gslist_nothing_in2 {'1', '2', '3'} end function gireg.gslist_null_in() - local R = LuaGObject.Regress - R.test_gslist_null_in {} - R.test_gslist_null_in(nil) - R.test_gslist_null_in() + local R = LuaGObject.Regress + R.test_gslist_null_in {} + R.test_gslist_null_in(nil) + R.test_gslist_null_in() end function gireg.gslist_null_out() - local R = LuaGObject.Regress - check(select('#', R.test_gslist_null_out()) == 1) - local a = R.test_gslist_null_out() - check(type(a) == 'table' and #a == 0) + local R = LuaGObject.Regress + check(select('#', R.test_gslist_null_out()) == 1) + local a = R.test_gslist_null_out() + check(type(a) == 'table' and #a == 0) end function gireg.ghash_null_return() - local R = LuaGObject.Regress - check(select('#', R.test_ghash_null_return()) == 1) - check(R.test_ghash_null_return() == nil) + local R = LuaGObject.Regress + check(select('#', R.test_ghash_null_return()) == 1) + check(R.test_ghash_null_return() == nil) end local function size_htab(h) - local size = 0 - for _ in pairs(h) do size = size + 1 end - return size + local size = 0 + for _ in pairs(h) do size = size + 1 end + return size end function gireg.ghash_nothing_return() - local R = LuaGObject.Regress - local count = 0 - check(select('#', R.test_ghash_nothing_return()) == 1) - local h = R.test_ghash_nothing_return() - check(type(h) == 'table') - check(size_htab(h) == 3) - check(h.foo == 'bar' and h.baz == 'bat' and h.qux == 'quux') + local R = LuaGObject.Regress + local count = 0 + check(select('#', R.test_ghash_nothing_return()) == 1) + local h = R.test_ghash_nothing_return() + check(type(h) == 'table') + check(size_htab(h) == 3) + check(h.foo == 'bar' and h.baz == 'bat' and h.qux == 'quux') end function gireg.ghash_container_return() - local R = LuaGObject.Regress - local count = 0 - check(select('#', R.test_ghash_container_return()) == 1) - local h = R.test_ghash_container_return() - check(type(h) == 'table') - check(size_htab(h) == 3) - check(h.foo == 'bar' and h.baz == 'bat' and h.qux == 'quux') + local R = LuaGObject.Regress + local count = 0 + check(select('#', R.test_ghash_container_return()) == 1) + local h = R.test_ghash_container_return() + check(type(h) == 'table') + check(size_htab(h) == 3) + check(h.foo == 'bar' and h.baz == 'bat' and h.qux == 'quux') end function gireg.ghash_everything_return() - local R = LuaGObject.Regress - local count = 0 - check(select('#', R.test_ghash_everything_return()) == 1) - local h = R.test_ghash_everything_return() - check(type(h) == 'table') - check(size_htab(h) == 3) - check(h.foo == 'bar' and h.baz == 'bat' and h.qux == 'quux') + local R = LuaGObject.Regress + local count = 0 + check(select('#', R.test_ghash_everything_return()) == 1) + local h = R.test_ghash_everything_return() + check(type(h) == 'table') + check(size_htab(h) == 3) + check(h.foo == 'bar' and h.baz == 'bat' and h.qux == 'quux') end function gireg.ghash_null_in() - local R = LuaGObject.Regress - R.test_ghash_null_in(nil) - R.test_ghash_null_in() - check(not pcall(R.test_ghash_null_in,1)) - check(not pcall(R.test_ghash_null_in,'string')) - check(not pcall(R.test_ghash_null_in,function() end)) + local R = LuaGObject.Regress + R.test_ghash_null_in(nil) + R.test_ghash_null_in() + check(not pcall(R.test_ghash_null_in,1)) + check(not pcall(R.test_ghash_null_in,'string')) + check(not pcall(R.test_ghash_null_in,function() end)) end function gireg.ghash_null_out() - local R = LuaGObject.Regress - check(R.test_ghash_null_out() == nil) + local R = LuaGObject.Regress + check(R.test_ghash_null_out() == nil) end function gireg.ghash_nothing_in() - local R = LuaGObject.Regress - R.test_ghash_nothing_in({ foo = 'bar', baz = 'bat', qux = 'quux' }) - check(not pcall(R.test_ghash_nothing_in)) - check(not pcall(R.test_ghash_nothing_in, 1)) - check(not pcall(R.test_ghash_nothing_in, 'test')) - check(not pcall(R.test_ghash_nothing_in, function() end)) + local R = LuaGObject.Regress + R.test_ghash_nothing_in({ foo = 'bar', baz = 'bat', qux = 'quux' }) + check(not pcall(R.test_ghash_nothing_in)) + check(not pcall(R.test_ghash_nothing_in, 1)) + check(not pcall(R.test_ghash_nothing_in, 'test')) + check(not pcall(R.test_ghash_nothing_in, function() end)) end function gireg.ghash_nested_everything_return() - local R = LuaGObject.Regress - check(select('#', R.test_ghash_nested_everything_return) == 1); - local a = R.test_ghash_nested_everything_return() - check(type(a) == 'table') - check(size_htab(a) == 1) - check(type(a.wibble) == 'table') - check(size_htab(a.wibble) == 3) - check(a.wibble.foo == 'bar' and a.wibble.baz == 'bat' - and a.wibble.qux == 'quux') + local R = LuaGObject.Regress + check(select('#', R.test_ghash_nested_everything_return) == 1); + local a = R.test_ghash_nested_everything_return() + check(type(a) == 'table') + check(size_htab(a) == 1) + check(type(a.wibble) == 'table') + check(size_htab(a.wibble) == 3) + check(a.wibble.foo == 'bar' and a.wibble.baz == 'bat' + and a.wibble.qux == 'quux') end function gireg.enum() - local R = LuaGObject.Regress - check(R.TestEnum.VALUE1 == 0) - check(R.TestEnum.VALUE2 == 1) - check(R.TestEnum.VALUE3 == -1) - check(R.TestEnum[0] == 'VALUE1') - check(R.TestEnum[1] == 'VALUE2') - check(R.TestEnum[-1] == 'VALUE3') - check(R.TestEnum[43] == 43) - check(R.test_enum_param(0) == 'value1') - check(R.test_enum_param(1) == 'value2') - check(R.test_enum_param(-1) == 'value3') - check(R.test_enum_param(nil) == 'value1') - - check(R.TestEnumUnsigned.VALUE1 == 1) - check(R.TestEnumUnsigned.VALUE2 == 0x80000000) - check(R.TestEnumUnsigned[1] == 'VALUE1') - check(R.TestEnumUnsigned[0x80000000] == 'VALUE2') - check(R.TestEnumUnsigned[-1] == -1) + local R = LuaGObject.Regress + check(R.TestEnum.VALUE1 == 0) + check(R.TestEnum.VALUE2 == 1) + check(R.TestEnum.VALUE3 == -1) + check(R.TestEnum[0] == 'VALUE1') + check(R.TestEnum[1] == 'VALUE2') + check(R.TestEnum[-1] == 'VALUE3') + check(R.TestEnum[43] == 43) + check(R.test_enum_param(0) == 'value1') + check(R.test_enum_param(1) == 'value2') + check(R.test_enum_param(-1) == 'value3') + check(R.test_enum_param(nil) == 'value1') + + check(R.TestEnumUnsigned.VALUE1 == 1) + check(R.TestEnumUnsigned.VALUE2 == 0x80000000) + check(R.TestEnumUnsigned[1] == 'VALUE1') + check(R.TestEnumUnsigned[0x80000000] == 'VALUE2') + check(R.TestEnumUnsigned[-1] == -1) end function gireg.flags() - local R = LuaGObject.Regress - check(R.TestFlags.FLAG1 == 1) - check(R.TestFlags.FLAG2 == 2) - check(R.TestFlags.FLAG3 == 4) - check(R.TestFlags[7].FLAG1 == true) - check(R.TestFlags[7].FLAG2 == true) - check(R.TestFlags[7].FLAG3 == true) - check(R.TestFlags[3].FLAG1 == true) - check(R.TestFlags[3].FLAG2 == true) - check(R.TestFlags[3].FLAG3 == nil) - check(R.TestFlags[10].FLAG2 == true) - check(R.TestFlags[10][1] == 8) - checkv(R.TestFlags { 'FLAG1', 'FLAG2' }, 3, 'number') - checkv(R.TestFlags { 1, 2, 'FLAG1', R.TestFlags.FLAG2 }, 3, 'number') - checkv(R.TestFlags { 10, FLAG2 = 2 }, 10, 'number') - checkv(R.TestFlags { 2, 'FLAG2' }, 2, 'number') - checkv(R.TestFlags(nil), 0, 'number') + local R = LuaGObject.Regress + check(R.TestFlags.FLAG1 == 1) + check(R.TestFlags.FLAG2 == 2) + check(R.TestFlags.FLAG3 == 4) + check(R.TestFlags[7].FLAG1 == true) + check(R.TestFlags[7].FLAG2 == true) + check(R.TestFlags[7].FLAG3 == true) + check(R.TestFlags[3].FLAG1 == true) + check(R.TestFlags[3].FLAG2 == true) + check(R.TestFlags[3].FLAG3 == nil) + check(R.TestFlags[10].FLAG2 == true) + check(R.TestFlags[10][1] == 8) + checkv(R.TestFlags { 'FLAG1', 'FLAG2' }, 3, 'number') + checkv(R.TestFlags { 1, 2, 'FLAG1', R.TestFlags.FLAG2 }, 3, 'number') + checkv(R.TestFlags { 10, FLAG2 = 2 }, 10, 'number') + checkv(R.TestFlags { 2, 'FLAG2' }, 2, 'number') + checkv(R.TestFlags(nil), 0, 'number') end function gireg.flags_out() - local R = LuaGObject.Regress - local out = R.global_get_flags_out() - check(type(out) == 'table') - check(out.FLAG1 == true) - check(out.FLAG2 == nil) - check(out.FLAG3 == true) - check(#out == 0) + local R = LuaGObject.Regress + local out = R.global_get_flags_out() + check(type(out) == 'table') + check(out.FLAG1 == true) + check(out.FLAG2 == nil) + check(out.FLAG3 == true) + check(#out == 0) end function gireg.const() - local R = LuaGObject.Regress - checkv(R.INT_CONSTANT, 4422, 'number') - checkv(R.DOUBLE_CONSTANT, 44.22, 'number') - checkv(R.STRING_CONSTANT, 'Some String', 'string') - checkv(R.Mixed_Case_Constant, 4423, 'number') + local R = LuaGObject.Regress + checkv(R.INT_CONSTANT, 4422, 'number') + checkv(R.DOUBLE_CONSTANT, 44.22, 'number') + checkv(R.STRING_CONSTANT, 'Some String', 'string') + checkv(R.Mixed_Case_Constant, 4423, 'number') end function gireg.struct_a() - local R = LuaGObject.Regress - check(select('#', R.TestStructA()) == 1) - local a = R.TestStructA() - check(type(a) == 'userdata') - a.some_int = 42 - check(a.some_int == 42) - a.some_int8 = 12 - check(a.some_int8 == 12) - a.some_double = 3.14 - check(a.some_double == 3.14) - a.some_enum = R.TestEnum.VALUE2 - check(a.some_enum == 'VALUE2') - a = R.TestStructA { some_int = 42, some_int8 = 12, - some_double = 3.14, some_enum = 'VALUE2' } - a.some_int = 43 - a.some_int8 = 13 - check(a.some_int == 43) - check(a.some_int8 == 13) - check(a.some_double == 3.14) - check(a.some_enum == 'VALUE2') - a.some_double = 3.15 - check(a.some_int == 43) - check(a.some_int8 == 13) - check(a.some_double == 3.15) - check(a.some_enum == 'VALUE2') - a.some_enum = R.TestEnum.VALUE3 - check(a.some_int == 43) - check(a.some_int8 == 13) - check(a.some_double == 3.15) - check(a.some_enum == 'VALUE3') - check(not pcall(function() return a.foo end)) - check(not pcall(function() a.foo = 1 end)) - check(select('#', (function() a.some_int = 0 end)()) == 0) - check(select('#', (function() return a.some_int end)()) == 1) - check(select('#', (function() local b = a.some_int end)()) == 0) + local R = LuaGObject.Regress + check(select('#', R.TestStructA()) == 1) + local a = R.TestStructA() + check(type(a) == 'userdata') + a.some_int = 42 + check(a.some_int == 42) + a.some_int8 = 12 + check(a.some_int8 == 12) + a.some_double = 3.14 + check(a.some_double == 3.14) + a.some_enum = R.TestEnum.VALUE2 + check(a.some_enum == 'VALUE2') + a = R.TestStructA { + some_int = 42, + some_int8 = 12, + some_double = 3.14, + some_enum = 'VALUE2', + } + a.some_int = 43 + a.some_int8 = 13 + check(a.some_int == 43) + check(a.some_int8 == 13) + check(a.some_double == 3.14) + check(a.some_enum == 'VALUE2') + a.some_double = 3.15 + check(a.some_int == 43) + check(a.some_int8 == 13) + check(a.some_double == 3.15) + check(a.some_enum == 'VALUE2') + a.some_enum = R.TestEnum.VALUE3 + check(a.some_int == 43) + check(a.some_int8 == 13) + check(a.some_double == 3.15) + check(a.some_enum == 'VALUE3') + check(not pcall(function() return a.foo end)) + check(not pcall(function() a.foo = 1 end)) + check(select('#', (function() a.some_int = 0 end)()) == 0) + check(select('#', (function() return a.some_int end)()) == 1) + check(select('#', (function() local b = a.some_int end)()) == 0) end function gireg.struct_a_clone() - local R = LuaGObject.Regress - local a = R.TestStructA { some_int = 42, some_int8 = 12, some_double = 3.14, - some_enum = R.TestEnum.VALUE2 } - check(a == a) - check(select('#', a:clone()) == 1) - local b = a:clone() - check(type(b) == 'userdata') - check(b ~= a) - check(b == b) - check(b.some_int == 42) - check(b.some_int8 == 12) - check(b.some_double == 3.14) - check(b.some_enum == 'VALUE2') - check(a.some_int == 42) - check(a.some_int8 == 12) - check(a.some_double == 3.14) - check(a.some_enum == 'VALUE2') + local R = LuaGObject.Regress + local a = R.TestStructA { + some_int = 42, + some_int8 = 12, + some_double = 3.14, + some_enum = R.TestEnum.VALUE2, + } + check(a == a) + check(select('#', a:clone()) == 1) + local b = a:clone() + check(type(b) == 'userdata') + check(b ~= a) + check(b == b) + check(b.some_int == 42) + check(b.some_int8 == 12) + check(b.some_double == 3.14) + check(b.some_enum == 'VALUE2') + check(a.some_int == 42) + check(a.some_int8 == 12) + check(a.some_double == 3.14) + check(a.some_enum == 'VALUE2') end function gireg.struct_b() - local R = LuaGObject.Regress - local b = R.TestStructB() - - -- Basic fields assignments. - b.some_int8 = 13 - check(b.some_int8 == 13) - b.nested_a.some_int = -1 - check(b.some_int8 == 13) - check(b.nested_a.some_int == -1) - b.nested_a.some_int8 = -2 - check(b.some_int8 == 13) - check(b.nested_a.some_int == -1) - check(b.nested_a.some_int8 == -2) - - -- Whole nested structure assignment. - b.nested_a = { some_int = 42, some_int8 = 12, - some_double = 3.14, some_enum = R.TestEnum.VALUE2 } - check(b.nested_a.some_int == 42) - check(b.nested_a.some_int8 == 12) - check(b.nested_a.some_double == 3.14) - check(b.nested_a.some_enum == 'VALUE2') - - -- Nested structure construction. - b = R.TestStructB { some_int8 = 21, nested_a = - { some_int = 42, some_int8 = 12, - some_double = 3.14, some_enum = R.TestEnum.VALUE2 } } - check(b.some_int8 == 21) - check(b.nested_a.some_int == 42) - check(b.nested_a.some_int8 == 12) - check(b.nested_a.some_double == 3.14) - check(b.nested_a.some_enum == 'VALUE2') + local R = LuaGObject.Regress + local b = R.TestStructB() + + -- Basic fields assignments. + b.some_int8 = 13 + check(b.some_int8 == 13) + b.nested_a.some_int = -1 + check(b.some_int8 == 13) + check(b.nested_a.some_int == -1) + b.nested_a.some_int8 = -2 + check(b.some_int8 == 13) + check(b.nested_a.some_int == -1) + check(b.nested_a.some_int8 == -2) + + -- Whole nested structure assignment. + b.nested_a = { + some_int = 42, + some_int8 = 12, + some_double = 3.14, + some_enum = R.TestEnum.VALUE2, + } + check(b.nested_a.some_int == 42) + check(b.nested_a.some_int8 == 12) + check(b.nested_a.some_double == 3.14) + check(b.nested_a.some_enum == 'VALUE2') + + -- Nested structure construction. + b = R.TestStructB { + some_int8 = 21, + nested_a = { + some_int = 42, + some_int8 = 12, + some_double = 3.14, + some_enum = R.TestEnum.VALUE2, + }, + } + check(b.some_int8 == 21) + check(b.nested_a.some_int == 42) + check(b.nested_a.some_int8 == 12) + check(b.nested_a.some_double == 3.14) + check(b.nested_a.some_enum == 'VALUE2') end function gireg.struct_b_clone() - local R = LuaGObject.Regress - local b = R.TestStructB { some_int8 = 21, nested_a = - { some_int = 42, some_int8 = 12, - some_double = 3.14, - some_enum = R.TestEnum.VALUE2 } } - check(b == b) - check(select('#', b:clone()) == 1) - local bc = b:clone() - check(type(bc) == 'userdata') - check(bc ~= b) - check(bc == bc) - check(bc.some_int8 == 21) - check(bc.nested_a.some_int == 42) - check(bc.nested_a.some_int8 == 12) - check(bc.nested_a.some_double == 3.14) - check(bc.nested_a.some_enum == 'VALUE2') - check(bc.nested_a.some_int == 42) - check(bc.nested_a.some_int8 == 12) - check(bc.nested_a.some_double == 3.14) - check(bc.nested_a.some_enum == 'VALUE2') - - check(b.some_int8 == 21) - check(b.nested_a.some_int == 42) - check(b.nested_a.some_int8 == 12) - check(b.nested_a.some_double == 3.14) - check(b.nested_a.some_enum == 'VALUE2') - check(b.nested_a.some_int == 42) - check(b.nested_a.some_int8 == 12) - check(b.nested_a.some_double == 3.14) - check(b.nested_a.some_enum == 'VALUE2') + local R = LuaGObject.Regress + local b = R.TestStructB { + some_int8 = 21, + nested_a = { + some_int = 42, + some_int8 = 12, + some_double = 3.14, + some_enum = R.TestEnum.VALUE2, + }, + } + check(b == b) + check(select('#', b:clone()) == 1) + local bc = b:clone() + check(type(bc) == 'userdata') + check(bc ~= b) + check(bc == bc) + check(bc.some_int8 == 21) + check(bc.nested_a.some_int == 42) + check(bc.nested_a.some_int8 == 12) + check(bc.nested_a.some_double == 3.14) + check(bc.nested_a.some_enum == 'VALUE2') + check(bc.nested_a.some_int == 42) + check(bc.nested_a.some_int8 == 12) + check(bc.nested_a.some_double == 3.14) + check(bc.nested_a.some_enum == 'VALUE2') + + check(b.some_int8 == 21) + check(b.nested_a.some_int == 42) + check(b.nested_a.some_int8 == 12) + check(b.nested_a.some_double == 3.14) + check(b.nested_a.some_enum == 'VALUE2') + check(b.nested_a.some_int == 42) + check(b.nested_a.some_int8 == 12) + check(b.nested_a.some_double == 3.14) + check(b.nested_a.some_enum == 'VALUE2') end function gireg.boxed_a_equals() - local R = LuaGObject.Regress - check(R.TestSimpleBoxedA({ some_int = 1, some_int8 = 2, - some_double = 3.14 }):equals( - R.TestSimpleBoxedA({ some_int = 1, some_int8 = 2, - some_double = 3.14 }))) - check(not R.TestSimpleBoxedA({ some_int = 2, some_int8 = 2, - some_double = 3.14 }):equals( - R.TestSimpleBoxedA({ some_int = 1, some_int8 = 2, - some_double = 3.14 }))) - check(R.TestSimpleBoxedA():equals(R.TestSimpleBoxedA())) - check(not pcall(R.TestSimpleBoxedA().equals)) - check(not pcall(R.TestSimpleBoxedA().equals, nil)) - check(not pcall(R.TestSimpleBoxedA().equals, {})) - check(not pcall(R.TestSimpleBoxedA().equals, 1)) - check(not pcall(R.TestSimpleBoxedA().equals, 'string')) - check(not pcall(R.TestSimpleBoxedA().equals, function() end)) + local R = LuaGObject.Regress + check(R.TestSimpleBoxedA({ + some_int = 1, + some_int8 = 2, + some_double = 3.14, + }):equals(R.TestSimpleBoxedA({ + some_int = 1, + some_int8 = 2, + some_double = 3.14, + }))) + check(not R.TestSimpleBoxedA({ + some_int = 2, + some_int8 = 2, + some_double = 3.14, + }):equals(R.TestSimpleBoxedA({ + some_int = 1, + some_int8 = 2, + some_double = 3.14, + }))) + check(R.TestSimpleBoxedA():equals(R.TestSimpleBoxedA())) + check(not pcall(R.TestSimpleBoxedA().equals)) + check(not pcall(R.TestSimpleBoxedA().equals, nil)) + check(not pcall(R.TestSimpleBoxedA().equals, {})) + check(not pcall(R.TestSimpleBoxedA().equals, 1)) + check(not pcall(R.TestSimpleBoxedA().equals, 'string')) + check(not pcall(R.TestSimpleBoxedA().equals, function() end)) end function gireg.boxed_a_const_return() - local R = LuaGObject.Regress - check(select('#', R.test_simple_boxed_a_const_return()) == 1) - local a = R.test_simple_boxed_a_const_return() - check(a.some_int == 5) - check(a.some_int8 == 6) - check(a.some_double == 7) + local R = LuaGObject.Regress + check(select('#', R.test_simple_boxed_a_const_return()) == 1) + local a = R.test_simple_boxed_a_const_return() + check(a.some_int == 5) + check(a.some_int8 == 6) + check(a.some_double == 7) end function gireg.boxed_new() - local R = LuaGObject.Regress - check(select('#', R.TestBoxed.new()) == 1) - local bn = R.TestBoxed.new() - local bac1 = R.TestBoxed.new_alternative_constructor1(1) - check(bac1.some_int8 == 1) - local bac2 = R.TestBoxed.new_alternative_constructor2(1, 2) - check(bac2.some_int8 == 3) - local bac3 = R.TestBoxed.new_alternative_constructor3('25') - check(bac3.some_int8 == 25) + local R = LuaGObject.Regress + check(select('#', R.TestBoxed.new()) == 1) + local bn = R.TestBoxed.new() + local bac1 = R.TestBoxed.new_alternative_constructor1(1) + check(bac1.some_int8 == 1) + local bac2 = R.TestBoxed.new_alternative_constructor2(1, 2) + check(bac2.some_int8 == 3) + local bac3 = R.TestBoxed.new_alternative_constructor3('25') + check(bac3.some_int8 == 25) end function gireg.boxed_copy() - local R = LuaGObject.Regress - local b = R.TestBoxed.new() - b.some_int8 = 1 - b.nested_a = { some_int = 1, some_int8 = 2, some_double = 3.14 } - check(select('#', b:copy()) == 1) - local bc = b:copy() - check(bc ~= b) - check(bc.some_int8 == 1) - check(bc.nested_a.some_int == 1) - check(bc.nested_a.some_int8 == 2) - check(bc.nested_a.some_double == 3.14) + local R = LuaGObject.Regress + local b = R.TestBoxed.new() + b.some_int8 = 1 + b.nested_a = { some_int = 1, some_int8 = 2, some_double = 3.14 } + check(select('#', b:copy()) == 1) + local bc = b:copy() + check(bc ~= b) + check(bc.some_int8 == 1) + check(bc.nested_a.some_int == 1) + check(bc.nested_a.some_int8 == 2) + check(bc.nested_a.some_double == 3.14) end function gireg.boxed_equals() - local R = LuaGObject.Regress - local b1 = R.TestBoxed.new() - b1.some_int8 = 1 - b1.nested_a = { some_int = 1, some_int8 = 2, some_double = 3.14 } - local b2 = R.TestBoxed.new() - b2.some_int8 = 1 - b2.nested_a = { some_int = 1, some_int8 = 2, some_double = 3.14 } - check(b1:equals(b2)) - b1.some_int8 = 2 - check(not b1:equals(b2)) - b1.some_int8 = 1 - b1.nested_a.some_int = 2 - check(not b1:equals(b2)) - b1.nested_a.some_int = 1 - check(b1:equals(b2)) + local R = LuaGObject.Regress + local b1 = R.TestBoxed.new() + b1.some_int8 = 1 + b1.nested_a = { some_int = 1, some_int8 = 2, some_double = 3.14 } + local b2 = R.TestBoxed.new() + b2.some_int8 = 1 + b2.nested_a = { some_int = 1, some_int8 = 2, some_double = 3.14 } + check(b1:equals(b2)) + b1.some_int8 = 2 + check(not b1:equals(b2)) + b1.some_int8 = 1 + b1.nested_a.some_int = 2 + check(not b1:equals(b2)) + b1.nested_a.some_int = 1 + check(b1:equals(b2)) end function gireg.closure_simple() - local R = LuaGObject.Regress - local GObject = LuaGObject.GObject - local closure = GObject.Closure(function(...) - check(select('#', ...) == 0) - return 42 - end) - checkv(R.test_closure(closure, 42), 42, 'number') - local res = GObject.Value('gint') - closure:invoke(res, {}, nil) - check(res.gtype == 'gint' and res.value == 42) + local R = LuaGObject.Regress + local GObject = LuaGObject.GObject + local closure = GObject.Closure(function(...) + check(select('#', ...) == 0) + return 42 + end) + checkv(R.test_closure(closure, 42), 42, 'number') + local res = GObject.Value('gint') + closure:invoke(res, {}, nil) + check(res.gtype == 'gint' and res.value == 42) end function gireg.closure_arg() - local GObject = LuaGObject.GObject - local R = LuaGObject.Regress - local closure = GObject.Closure(function(int, ...) - check(select('#', ...) == 0) - return int - end) - checkv(R.test_closure_one_arg(closure, 43), 43, 'number') - local res = GObject.Value('gint') - closure:invoke(res, { GObject.Value('gint', 43) }, nil) - check(res.gtype == 'gint' and res.value == 43) + local GObject = LuaGObject.GObject + local R = LuaGObject.Regress + local closure = GObject.Closure(function(int, ...) + check(select('#', ...) == 0) + return int + end) + checkv(R.test_closure_one_arg(closure, 43), 43, 'number') + local res = GObject.Value('gint') + closure:invoke(res, { GObject.Value('gint', 43) }, nil) + check(res.gtype == 'gint' and res.value == 43) end function gireg.gvalue_assign() - local GObject = LuaGObject.GObject - local V = GObject.Value - - local v = V() - check(v.gtype == nil) - check(v.value == nil) - v.gtype = 'gchararray' - check(v.gtype == 'gchararray') - check(v.value == nil) - v.value = 'label' - check(v.value == 'label') - v.value = nil - check(v.value == nil) - check(v.gtype == 'gchararray') - v.value = 'label' - v.gtype = nil - check(v.gtype == nil) - check(v.value == nil) - - v.gtype = 'gint' - v.value = 1 - check(v.gtype == 'gint') - check(v.value == 1) - v.gtype = 'gdouble' - check(v.gtype == 'gdouble') - check(v.value == 1) - v.value = 3.14 - v.gtype = 'gint' - check(v.gtype == 'gint') - check(v.value == 3) + local GObject = LuaGObject.GObject + local V = GObject.Value + + local v = V() + check(v.gtype == nil) + check(v.value == nil) + v.gtype = 'gchararray' + check(v.gtype == 'gchararray') + check(v.value == nil) + v.value = 'label' + check(v.value == 'label') + v.value = nil + check(v.value == nil) + check(v.gtype == 'gchararray') + v.value = 'label' + v.gtype = nil + check(v.gtype == nil) + check(v.value == nil) + + v.gtype = 'gint' + v.value = 1 + check(v.gtype == 'gint') + check(v.value == 1) + v.gtype = 'gdouble' + check(v.gtype == 'gdouble') + check(v.value == 1) + v.value = 3.14 + v.gtype = 'gint' + check(v.gtype == 'gint') + check(v.value == 3) end function gireg.gvalue_arg() - local GObject = LuaGObject.GObject - local R = LuaGObject.Regress - checkv(R.test_int_value_arg(GObject.Value('gint', 42)), 42, 'number') + local GObject = LuaGObject.GObject + local R = LuaGObject.Regress + checkv(R.test_int_value_arg(GObject.Value('gint', 42)), 42, 'number') end function gireg.gvalue_return() - local R = LuaGObject.Regress - local v = R.test_value_return(43) - checkv(v.value, 43, 'number') - check(v.gtype == 'gint', 'incorrect value type') + local R = LuaGObject.Regress + local v = R.test_value_return(43) + checkv(v.value, 43, 'number') + check(v.gtype == 'gint', 'incorrect value type') end function gireg.gvalue_date() - local GObject = LuaGObject.GObject - local GLib = LuaGObject.GLib - local R = LuaGObject.Regress - local v - v = R.test_date_in_gvalue() - check(v.gtype == 'GDate') - check(v.value:get_day() == 5) - check(v.value:get_month() == 'DECEMBER') - check(v.value:get_year() == 1984) - local d = GLib.Date() - d:set_dmy(25, 1, 1975) - v = GObject.Value(GLib.Date, d) - check(v.gtype == 'GDate') - check(v.value:get_day() == 25) - check(v.value:get_month() == 'JANUARY') - check(v.value:get_year() == 1975) + local GObject = LuaGObject.GObject + local GLib = LuaGObject.GLib + local R = LuaGObject.Regress + local v + v = R.test_date_in_gvalue() + check(v.gtype == 'GDate') + check(v.value:get_day() == 5) + check(v.value:get_month() == 'DECEMBER') + check(v.value:get_year() == 1984) + local d = GLib.Date() + d:set_dmy(25, 1, 1975) + v = GObject.Value(GLib.Date, d) + check(v.gtype == 'GDate') + check(v.value:get_day() == 25) + check(v.value:get_month() == 'JANUARY') + check(v.value:get_year() == 1975) end function gireg.gvalue_strv() - local GObject = LuaGObject.GObject - local R = LuaGObject.Regress - local v = R.test_strv_in_gvalue() - check(v.gtype == 'GStrv') - check(#v.value == 3) - check(v.value[1] == 'one') - check(v.value[2] == 'two') - check(v.value[3] == 'three') - v = GObject.Value('GStrv', { '1', '2', '3' }) - check(#v.value == 3) - check(v.value[1] == '1') - check(v.value[2] == '2') - check(v.value[3] == '3') + local GObject = LuaGObject.GObject + local R = LuaGObject.Regress + local v = R.test_strv_in_gvalue() + check(v.gtype == 'GStrv') + check(#v.value == 3) + check(v.value[1] == 'one') + check(v.value[2] == 'two') + check(v.value[3] == 'three') + v = GObject.Value('GStrv', { '1', '2', '3' }) + check(#v.value == 3) + check(v.value[1] == '1') + check(v.value[2] == '2') + check(v.value[3] == '3') end function gireg.obj_create() - local R = LuaGObject.Regress - local o = R.TestObj() - check(o) - check(type(o) == 'userdata') - check(select('#', R.TestObj()) == 1) - o = R.TestObj.new_from_file('unused') - check(type(o) == 'userdata') - check(select('#', R.TestObj.new_from_file('unused')) == 1) + local R = LuaGObject.Regress + local o = R.TestObj() + check(o) + check(type(o) == 'userdata') + check(select('#', R.TestObj()) == 1) + o = R.TestObj.new_from_file('unused') + check(type(o) == 'userdata') + check(select('#', R.TestObj.new_from_file('unused')) == 1) end function gireg.obj_methods() - local R = LuaGObject.Regress - local GLib = LuaGObject.GLib - local Gio = LuaGObject.Gio - - if R.TestObj._method.do_matrix then - R.TestObj._method.invoke_matrix = R.TestObj._method.do_matrix - R.TestObj._method.do_matrix = nil - end - - local o = R.TestObj() - check(o:instance_method() == -1) - check(o.static_method(42) == 42) - local y, z, q = o:torture_signature_0(1, 'foo', 2) - check(y == 1) - check(z == 2) - check(q == 5) - local y, z, q = o:torture_signature_1(1, 'foo', 2) - check(y == 1) - check(z == 2) - check(q == 5) - local res, err = o:torture_signature_1(1, 'foo', 3) - check(not res) - check(GLib.Error:is_type_of(err)) - check(err:matches(Gio.IOErrorEnum, 'FAILED')) - check(o:invoke_matrix('unused') == 42) + local R = LuaGObject.Regress + local GLib = LuaGObject.GLib + local Gio = LuaGObject.Gio + + if R.TestObj._method.do_matrix then + R.TestObj._method.invoke_matrix = R.TestObj._method.do_matrix + R.TestObj._method.do_matrix = nil + end + + local o = R.TestObj() + check(o:instance_method() == -1) + check(o.static_method(42) == 42) + local y, z, q = o:torture_signature_0(1, 'foo', 2) + check(y == 1) + check(z == 2) + check(q == 5) + local y, z, q = o:torture_signature_1(1, 'foo', 2) + check(y == 1) + check(z == 2) + check(q == 5) + local res, err = o:torture_signature_1(1, 'foo', 3) + check(not res) + check(GLib.Error:is_type_of(err)) + check(err:matches(Gio.IOErrorEnum, 'FAILED')) + check(o:invoke_matrix('unused') == 42) end function gireg.obj_null_args() - local R = LuaGObject.Regress - R.func_obj_null_in(nil) - R.func_obj_null_in() - check(R.TestObj.null_out() == nil) - check(select('#', R.TestObj.null_out()) == 1) + local R = LuaGObject.Regress + R.func_obj_null_in(nil) + R.func_obj_null_in() + check(R.TestObj.null_out() == nil) + check(select('#', R.TestObj.null_out()) == 1) end function gireg.obj_virtual_methods() - local R = LuaGObject.Regress - local o = R.TestObj() - check(o:do_matrix('unused') == 42) + local R = LuaGObject.Regress + local o = R.TestObj() + check(o:do_matrix('unused') == 42) end function gireg.obj_prop_int() - local R = LuaGObject.Regress - local o = R.TestObj() + local R = LuaGObject.Regress + local o = R.TestObj() - check(o.int == 0) - o.int = 42 - check(o.int == 42) - check(not pcall(function() o.int = {} end)) - check(not pcall(function() o.int = 'LuaGObject' end)) - check(not pcall(function() o.int = nil end)) - check(not pcall(function() o.int = function() end end)) + check(o.int == 0) + o.int = 42 + check(o.int == 42) + check(not pcall(function() o.int = {} end)) + check(not pcall(function() o.int = 'LuaGObject' end)) + check(not pcall(function() o.int = nil end)) + check(not pcall(function() o.int = function() end end)) end function gireg.obj_prop_float() - local R = LuaGObject.Regress - local o = R.TestObj() + local R = LuaGObject.Regress + local o = R.TestObj() - check(o.float == 0) - o.float = 42.1 - checkvf(o.float, 42.1, 0.00001) - check(not pcall(function() o.float = {} end)) - check(not pcall(function() o.float = 'LuaGObject' end)) - check(not pcall(function() o.float = nil end)) - check(not pcall(function() o.float = function() end end)) + check(o.float == 0) + o.float = 42.1 + checkvf(o.float, 42.1, 0.00001) + check(not pcall(function() o.float = {} end)) + check(not pcall(function() o.float = 'LuaGObject' end)) + check(not pcall(function() o.float = nil end)) + check(not pcall(function() o.float = function() end end)) end function gireg.obj_prop_double() - local R = LuaGObject.Regress - local o = R.TestObj() + local R = LuaGObject.Regress + local o = R.TestObj() - check(o.double == 0) - o.double = 42.1 - checkvf(o.double, 42.1, 0.0000000001) - check(not pcall(function() o.double = {} end)) - check(not pcall(function() o.double = 'LuaGObject' end)) - check(not pcall(function() o.double = nil end)) - check(not pcall(function() o.double = function() end end)) + check(o.double == 0) + o.double = 42.1 + checkvf(o.double, 42.1, 0.0000000001) + check(not pcall(function() o.double = {} end)) + check(not pcall(function() o.double = 'LuaGObject' end)) + check(not pcall(function() o.double = nil end)) + check(not pcall(function() o.double = function() end end)) end function gireg.obj_prop_string() - local R = LuaGObject.Regress - local o = R.TestObj() + local R = LuaGObject.Regress + local o = R.TestObj() - check(o.string == nil) - o.string = 'LuaGObject' - check(o.string == 'LuaGObject') - o.string = nil - check(o.string == nil) - check(not pcall(function() o.string = {} end)) - check(not pcall(function() o.string = function() end end)) + check(o.string == nil) + o.string = 'LuaGObject' + check(o.string == 'LuaGObject') + o.string = nil + check(o.string == nil) + check(not pcall(function() o.string = {} end)) + check(not pcall(function() o.string = function() end end)) end function gireg.obj_prop_bare() - local R = LuaGObject.Regress - local o = R.TestObj() - - check(o.bare == nil) - local pv = R.TestObj() - o.bare = pv - check(o.bare == pv) - o.bare = nil - check(o.bare == nil) - o:set_bare(pv) - check(o.bare == pv) - o.bare = nil - check(o.bare == nil) - check(not pcall(function() o.bare = {} end)) - check(not pcall(function() o.bare = 42 end)) - check(not pcall(function() o.bare = 'LuaGObject' end)) - check(not pcall(function() o.bare = function() end end)) - check(not pcall(function() o.bare = R.TestBoxed() end)) + local R = LuaGObject.Regress + local o = R.TestObj() + + check(o.bare == nil) + local pv = R.TestObj() + o.bare = pv + check(o.bare == pv) + o.bare = nil + check(o.bare == nil) + o:set_bare(pv) + check(o.bare == pv) + o.bare = nil + check(o.bare == nil) + check(not pcall(function() o.bare = {} end)) + check(not pcall(function() o.bare = 42 end)) + check(not pcall(function() o.bare = 'LuaGObject' end)) + check(not pcall(function() o.bare = function() end end)) + check(not pcall(function() o.bare = R.TestBoxed() end)) end function gireg.obj_prop_boxed() - local R = LuaGObject.Regress - local o = R.TestObj() - - check(o.boxed == nil) - local pv = R.TestBoxed() - o.boxed = pv - check(o.boxed:equals(pv)) - o.boxed = nil - check(o.boxed == nil) - check(not pcall(function() o.boxed = {} end)) - check(not pcall(function() o.boxed = 42 end)) - check(not pcall(function() o.boxed = 'LuaGObject' end)) - check(not pcall(function() o.boxed = function() end end)) - check(not pcall(function() o.boxed = R.TestObj() end)) + local R = LuaGObject.Regress + local o = R.TestObj() + + check(o.boxed == nil) + local pv = R.TestBoxed() + o.boxed = pv + check(o.boxed:equals(pv)) + o.boxed = nil + check(o.boxed == nil) + check(not pcall(function() o.boxed = {} end)) + check(not pcall(function() o.boxed = 42 end)) + check(not pcall(function() o.boxed = 'LuaGObject' end)) + check(not pcall(function() o.boxed = function() end end)) + check(not pcall(function() o.boxed = R.TestObj() end)) end function gireg.obj_prop_hash() - local R = LuaGObject.Regress - local o = R.TestObj() + local R = LuaGObject.Regress + local o = R.TestObj() - check(o.hash_table == nil) - o.hash_table = { a = 1, b = 2 } - local ov = o.hash_table - check(ov.a == 1 and ov.b == 2) - check(not pcall(function() o.hash_table = 42 end)) - check(not pcall(function() o.hash_table = 'LuaGObject' end)) - check(not pcall(function() o.hash_table = function() end end)) - check(not pcall(function() o.hash_table = R.TestObj() end)) - check(not pcall(function() o.hash_table = R.TestBoxed() end)) + check(o.hash_table == nil) + o.hash_table = { a = 1, b = 2 } + local ov = o.hash_table + check(ov.a == 1 and ov.b == 2) + check(not pcall(function() o.hash_table = 42 end)) + check(not pcall(function() o.hash_table = 'LuaGObject' end)) + check(not pcall(function() o.hash_table = function() end end)) + check(not pcall(function() o.hash_table = R.TestObj() end)) + check(not pcall(function() o.hash_table = R.TestBoxed() end)) end function gireg.obj_prop_list() - local R = LuaGObject.Regress - local o = R.TestObj() + local R = LuaGObject.Regress + local o = R.TestObj() - check(o.hash_table == nil) - o.list = { 'one', 'two', 'three', } - local ov = o.list - check(#ov == 3 and ov[1] == 'one' and ov[2] == 'two' and ov[3] == 'three') - check(not pcall(function() o.list = 42 end)) - check(not pcall(function() o.list = 'LuaGObject' end)) - check(not pcall(function() o.list = function() end end)) - check(not pcall(function() o.list = R.TestObj() end)) - check(not pcall(function() o.list = R.TestBoxed() end)) + check(o.hash_table == nil) + o.list = { 'one', 'two', 'three', } + local ov = o.list + check(#ov == 3 and ov[1] == 'one' and ov[2] == 'two' and ov[3] == 'three') + check(not pcall(function() o.list = 42 end)) + check(not pcall(function() o.list = 'LuaGObject' end)) + check(not pcall(function() o.list = function() end end)) + check(not pcall(function() o.list = R.TestObj() end)) + check(not pcall(function() o.list = R.TestBoxed() end)) end function gireg.obj_prop_dynamic() - local R = LuaGObject.Regress - local o = R.TestObj() + local R = LuaGObject.Regress + local o = R.TestObj() - -- Remove static property information, force LuaGObject to use dynamic - -- GLib property system. - local old_prop = R.TestObj.int - R.TestObj._property.int = nil - R.TestObj._cached = nil - check(R.TestObj.int == nil) + -- Remove static property information, forcing LuaGObject to use GLib's dynamic property system. + local old_prop = R.TestObj.int + R.TestObj._property.int = nil + R.TestObj._cached = nil + check(R.TestObj.int == nil) - check(o.int == 0) - o.int = 3 - check(o.int == 3) - check(not pcall(function() o.int = 'string' end)) - check(not pcall(function() o.int = {} end)) - check(not pcall(function() o.int = true end)) - check(not pcall(function() o.int = function() end end)) + check(o.int == 0) + o.int = 3 + check(o.int == 3) + check(not pcall(function() o.int = 'string' end)) + check(not pcall(function() o.int = {} end)) + check(not pcall(function() o.int = true end)) + check(not pcall(function() o.int = function() end end)) - -- Restore TestObj to work normally. - R.TestObj._property.int = old_prop + -- Restore TestObj to work normally. + R.TestObj._property.int = old_prop end function gireg.obj_subobj() - local R = LuaGObject.Regress - local o = R.TestSubObj() - local pv = R.TestObj() - check(o:instance_method() == 0) - o.bare = pv - check(o.bare == pv) - o:unset_bare() - check(o.bare == nil) - o = R.TestSubObj.new() - o:set_bare(pv) - check(o.bare == pv) - o:unset_bare() - check(o.bare == nil) + local R = LuaGObject.Regress + local o = R.TestSubObj() + local pv = R.TestObj() + check(o:instance_method() == 0) + o.bare = pv + check(o.bare == pv) + o:unset_bare() + check(o.bare == nil) + o = R.TestSubObj.new() + o:set_bare(pv) + check(o.bare == pv) + o:unset_bare() + check(o.bare == nil) end function gireg.obj_naming() - local R = LuaGObject.Regress - local o = R.TestWi8021x() - o:set_testbool(true) - check(o.testbool == true) - o.testbool = false - check(o:get_testbool() == false) + local R = LuaGObject.Regress + local o = R.TestWi8021x() + o:set_testbool(true) + check(o.testbool == true) + o.testbool = false + check(o:get_testbool() == false) end function gireg.obj_floating() - local R = LuaGObject.Regress - local o = R.TestFloating() - check(o) - o = nil - collectgarbage() - collectgarbage() + local R = LuaGObject.Regress + local o = R.TestFloating() + check(o) + o = nil + collectgarbage() + collectgarbage() end function gireg.obj_fundamental() - local R = LuaGObject.Regress - local f = R.TestFundamentalSubObject.new('foo-nda-mental') - check(f) - check(f.data == 'foo-nda-mental') - local v = LuaGObject.GObject.Value(R.TestFundamentalSubObject, f) - check(v.value == f) - f = nil - collectgarbage() + local R = LuaGObject.Regress + local f = R.TestFundamentalSubObject.new('foo-nda-mental') + check(f) + check(f.data == 'foo-nda-mental') + local v = LuaGObject.GObject.Value(R.TestFundamentalSubObject, f) + check(v.value == f) + f = nil + collectgarbage() end function gireg.callback_simple() - local R = LuaGObject.Regress - check(R.test_callback(function() return 42 end) == 42) - check(R.test_callback() == 0) - check(R.test_callback(nil) == 0) - check(not pcall(R.test_callback, 1)) - check(not pcall(R.test_callback, 'foo')) - check(not pcall(R.test_callback, {})) - check(not pcall(R.test_callback, R)) + local R = LuaGObject.Regress + check(R.test_callback(function() return 42 end) == 42) + check(R.test_callback() == 0) + check(R.test_callback(nil) == 0) + check(not pcall(R.test_callback, 1)) + check(not pcall(R.test_callback, 'foo')) + check(not pcall(R.test_callback, {})) + check(not pcall(R.test_callback, R)) - check(R.test_multi_callback(function() return 22 end) == 44) - check(R.test_multi_callback() == 0) + check(R.test_multi_callback(function() return 22 end) == 44) + check(R.test_multi_callback() == 0) end function gireg.callback_data() - local R = LuaGObject.Regress - local called - R.test_simple_callback(function() called = true end) - check(called) - check(R.test_callback_user_data(function() return 42 end) == 42) - - called = nil - R.TestObj.static_method_callback(function() called = true return 42 end) - check(called) - local o = R.TestObj() - called = nil - o.static_method_callback(function() called = true return 42 end) - check(called) - called = nil - o:instance_method_callback(function() called = true return 42 end) - check(called) + local R = LuaGObject.Regress + local called + R.test_simple_callback(function() called = true end) + check(called) + check(R.test_callback_user_data(function() return 42 end) == 42) + + called = nil + R.TestObj.static_method_callback(function() called = true return 42 end) + check(called) + local o = R.TestObj() + called = nil + o.static_method_callback(function() called = true return 42 end) + check(called) + called = nil + o:instance_method_callback(function() called = true return 42 end) + check(called) end function gireg.callback_notified() - local R = LuaGObject.Regress - check(R.test_callback_destroy_notify(function() return 1 end) == 1) - check(R.test_callback_destroy_notify(function() return 2 end) == 2) - check(R.test_callback_destroy_notify(function() return 3 end) == 3) - collectgarbage() - collectgarbage() - check(R.test_callback_thaw_notifications() == 6) + local R = LuaGObject.Regress + check(R.test_callback_destroy_notify(function() return 1 end) == 1) + check(R.test_callback_destroy_notify(function() return 2 end) == 2) + check(R.test_callback_destroy_notify(function() return 3 end) == 3) + collectgarbage() + collectgarbage() + check(R.test_callback_thaw_notifications() == 6) - R.TestObj.new_callback(function() return 1 end) - collectgarbage() - collectgarbage() - check(R.test_callback_thaw_notifications() == 1) + R.TestObj.new_callback(function() return 1 end) + collectgarbage() + collectgarbage() + check(R.test_callback_thaw_notifications() == 1) end function gireg.callback_async() - local R = LuaGObject.Regress - R.test_callback_async(function() return 1 end) - collectgarbage() - collectgarbage() - check(R.test_callback_thaw_async() == 1) + local R = LuaGObject.Regress + R.test_callback_async(function() return 1 end) + collectgarbage() + collectgarbage() + check(R.test_callback_thaw_async() == 1) end