diff options
Diffstat (limited to 'gi/pygi-cache.c')
-rw-r--r-- | gi/pygi-cache.c | 1867 |
1 files changed, 923 insertions, 944 deletions
diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c index 2f807f8..c6630de 100644 --- a/gi/pygi-cache.c +++ b/gi/pygi-cache.c @@ -2,6 +2,7 @@ * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com> + * Copyright (C) 2013 Simon Feltman <sfeltman@gnome.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -14,37 +15,99 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include <Python.h> +#include <girepository.h> + +#include "pygi-type.h" #include "pygi-info.h" #include "pygi-cache.h" -#include "pygi-marshal-to-py.h" -#include "pygi-marshal-from-py.h" #include "pygi-marshal-cleanup.h" #include "pygi-type.h" -#include <girepository.h> +#include "pygi-hashtable.h" +#include "pygi-basictype.h" +#include "pygi-list.h" +#include "pygi-array.h" +#include "pygi-closure.h" +#include "pygi-error.h" +#include "pygi-object.h" +#include "pygi-struct-marshal.h" +#include "pygi-enum-marshal.h" +#include "pygi-resulttuple.h" +#include "pygi-invoke.h" + + +/* _arg_info_default_value + * info: + * arg: (out): GIArgument to fill in with default value. + * + * This is currently a place holder API which only supports "allow-none" pointer args. + * Once defaults are part of the GI API, we can replace this with: g_arg_info_default_value + * https://bugzilla.gnome.org/show_bug.cgi?id=558620 + * + * Returns: TRUE if the given argument supports a default value and was filled in. + */ +static gboolean +_arg_info_default_value (GIArgInfo *info, GIArgument *arg) +{ + if (g_arg_info_may_be_null (info)) { + arg->v_pointer = NULL; + return TRUE; + } + return FALSE; +} -PyGIArgCache * _arg_cache_new (GITypeInfo *type_info, - PyGICallableCache *callable_cache, - GIArgInfo *arg_info, - GITransfer transfer, - PyGIDirection direction, - gssize c_arg_index, - gssize py_arg_index); - -PyGIArgCache * _arg_cache_new_for_interface (GIInterfaceInfo *iface_info, - PyGICallableCache *callable_cache, - GIArgInfo *arg_info, - GITransfer transfer, - PyGIDirection direction, - gssize c_arg_index, - gssize py_arg_index); -/* cleanup */ -static void -_pygi_arg_cache_free (PyGIArgCache *cache) +/* pygi_arg_base_setup: + * arg_cache: argument cache to initialize + * type_info: source for type related attributes to cache + * arg_info: (allow-none): source for argument related attributes to cache + * transfer: transfer mode to store in the argument cache + * direction: marshaling direction to store in the cache + * + * Initializer for PyGIArgCache + * + * Returns: TRUE on success and FALSE on failure + */ +gboolean +pygi_arg_base_setup (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be NULL for return arguments */ + GITransfer transfer, + PyGIDirection direction) +{ + arg_cache->direction = direction; + arg_cache->transfer = transfer; + arg_cache->py_arg_index = -1; + arg_cache->c_arg_index = -1; + + if (type_info != NULL) { + arg_cache->is_pointer = g_type_info_is_pointer (type_info); + arg_cache->type_tag = g_type_info_get_tag (type_info); + g_base_info_ref ( (GIBaseInfo *) type_info); + arg_cache->type_info = type_info; + } + + if (arg_info != NULL) { + if (!arg_cache->has_default) { + /* It is possible has_default was set somewhere else */ + arg_cache->has_default = _arg_info_default_value (arg_info, + &arg_cache->default_value); + } + arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); + arg_cache->allow_none = g_arg_info_may_be_null (arg_info); + + if (arg_cache->type_tag == GI_TYPE_TAG_INTERFACE || arg_cache->type_tag == GI_TYPE_TAG_ARRAY) + arg_cache->is_caller_allocates = g_arg_info_is_caller_allocates (arg_info); + else + arg_cache->is_caller_allocates = FALSE; + } + return TRUE; +} + +void +pygi_arg_cache_free (PyGIArgCache *cache) { if (cache == NULL) return; @@ -57,6 +120,8 @@ _pygi_arg_cache_free (PyGIArgCache *cache) g_slice_free (PyGIArgCache, cache); } +/* PyGIInterfaceCache */ + static void _interface_cache_free_func (PyGIInterfaceCache *cache) { @@ -70,1136 +135,1050 @@ _interface_cache_free_func (PyGIInterfaceCache *cache) } } -static void -_hash_cache_free_func (PyGIHashCache *cache) +/* pygi_arg_interface_setup: + * arg_cache: argument cache to initialize + * type_info: source for type related attributes to cache + * arg_info: (allow-none): source for argument related attributes to cache + * transfer: transfer mode to store in the argument cache + * direction: marshaling direction to store in the cache + * iface_info: interface info to cache + * + * Initializer for PyGIInterfaceCache + * + * Returns: TRUE on success and FALSE on failure + */ +gboolean +pygi_arg_interface_setup (PyGIInterfaceCache *iface_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be NULL for return arguments */ + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info) { - if (cache != NULL) { - _pygi_arg_cache_free (cache->key_cache); - _pygi_arg_cache_free (cache->value_cache); - g_slice_free (PyGIHashCache, cache); + if (!pygi_arg_base_setup ((PyGIArgCache *)iface_cache, + type_info, + arg_info, + transfer, + direction)) { + return FALSE; } -} -static void -_sequence_cache_free_func (PyGISequenceCache *cache) -{ - if (cache != NULL) { - _pygi_arg_cache_free (cache->item_cache); - g_slice_free (PyGISequenceCache, cache); - } -} + ( (PyGIArgCache *)iface_cache)->destroy_notify = (GDestroyNotify)_interface_cache_free_func; -static void -_callback_cache_free_func (PyGICallbackCache *cache) -{ - if (cache != NULL) { - if (cache->interface_info != NULL) - g_base_info_unref ( (GIBaseInfo *)cache->interface_info); + g_base_info_ref ( (GIBaseInfo *)iface_info); + iface_cache->interface_info = iface_info; + iface_cache->arg_cache.type_tag = GI_TYPE_TAG_INTERFACE; + iface_cache->type_name = _pygi_g_base_info_get_fullname (iface_info); + iface_cache->g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *)iface_info); + iface_cache->py_type = pygi_type_import_by_gi_info ( (GIBaseInfo *) iface_info); - g_slice_free (PyGICallbackCache, cache); + if (iface_cache->py_type == NULL) { + return FALSE; } + + return TRUE; } -void -_pygi_callable_cache_free (PyGICallableCache *cache) +PyGIArgCache * +pygi_arg_interface_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be NULL for return arguments */ + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info) { - gssize i; - - if (cache == NULL) - return; - - g_slist_free (cache->to_py_args); - g_slist_free (cache->arg_name_list); - g_hash_table_destroy (cache->arg_name_hash); + PyGIInterfaceCache *ic; - for (i = 0; i < cache->n_args; i++) { - PyGIArgCache *tmp = cache->args_cache[i]; - _pygi_arg_cache_free (tmp); + ic = g_slice_new0 (PyGIInterfaceCache); + if (!pygi_arg_interface_setup (ic, + type_info, + arg_info, + transfer, + direction, + iface_info)) { + pygi_arg_cache_free ((PyGIArgCache *)ic); + return NULL; } - if (cache->return_cache != NULL) - _pygi_arg_cache_free (cache->return_cache); - g_slice_free1 (cache->n_args * sizeof (PyGIArgCache *), cache->args_cache); - g_slice_free (PyGICallableCache, cache); + return (PyGIArgCache *)ic; } -/* cache generation */ +/* PyGISequenceCache */ -static PyGIInterfaceCache * -_interface_cache_new (GIInterfaceInfo *iface_info) +static void +_sequence_cache_free_func (PyGISequenceCache *cache) { - PyGIInterfaceCache *ic; - - ic = g_slice_new0 (PyGIInterfaceCache); - ( (PyGIArgCache *)ic)->destroy_notify = (GDestroyNotify)_interface_cache_free_func; - ic->g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *)iface_info); - ic->py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) iface_info); - - if (ic->py_type == NULL) - return NULL; - - ic->type_name = _pygi_g_base_info_get_fullname (iface_info); - return ic; + if (cache != NULL) { + pygi_arg_cache_free (cache->item_cache); + g_slice_free (PyGISequenceCache, cache); + } } -static PyGISequenceCache * -_sequence_cache_new (GITypeInfo *type_info, - GIDirection direction, - GITransfer transfer, - gssize child_offset) +/* pygi_arg_sequence_setup: + * sc: sequence cache to initialize + * type_info: source for type related attributes to cache + * arg_info: (allow-none): source for argument related attributes to cache + * transfer: transfer mode to store in the argument cache + * direction: marshaling direction to store in the cache + * iface_info: interface info to cache + * + * Initializer for PyGISequenceCache used for holding list and array argument + * caches. + * + * Returns: TRUE on success and FALSE on failure + */ +gboolean +pygi_arg_sequence_setup (PyGISequenceCache *sc, + GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be NULL for return arguments */ + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache) { - PyGISequenceCache *sc; GITypeInfo *item_type_info; GITransfer item_transfer; - sc = g_slice_new0 (PyGISequenceCache); - ( (PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_sequence_cache_free_func; - - sc->is_zero_terminated = g_type_info_is_zero_terminated (type_info); - sc->fixed_size = g_type_info_get_array_fixed_size (type_info); - sc->len_arg_index = g_type_info_get_array_length (type_info); - if (sc->len_arg_index >= 0) - sc->len_arg_index += child_offset; + if (!pygi_arg_base_setup ((PyGIArgCache *)sc, + type_info, + arg_info, + transfer, + direction)) { + return FALSE; + } + sc->arg_cache.destroy_notify = (GDestroyNotify)_sequence_cache_free_func; item_type_info = g_type_info_get_param_type (type_info, 0); - item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; - sc->item_cache = _arg_cache_new (item_type_info, - NULL, - NULL, - item_transfer, - direction, - 0, 0); + sc->item_cache = pygi_arg_cache_new (item_type_info, + NULL, + item_transfer, + direction, + callable_cache, + 0, 0); - if (sc->item_cache == NULL) { - _pygi_arg_cache_free ( (PyGIArgCache *)sc); - return NULL; - } - - sc->item_size = _pygi_g_type_info_size (item_type_info); g_base_info_unref ( (GIBaseInfo *)item_type_info); - return sc; -} -static PyGIHashCache * -_hash_cache_new (GITypeInfo *type_info, - GIDirection direction, - GITransfer transfer) -{ - PyGIHashCache *hc; - GITypeInfo *key_type_info; - GITypeInfo *value_type_info; - GITransfer item_transfer; - - hc = g_slice_new0 (PyGIHashCache); - ( (PyGIArgCache *)hc)->destroy_notify = (GDestroyNotify)_hash_cache_free_func; - key_type_info = g_type_info_get_param_type (type_info, 0); - value_type_info = g_type_info_get_param_type (type_info, 1); - - item_transfer = - transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; - - hc->key_cache = _arg_cache_new (key_type_info, - NULL, - NULL, - item_transfer, - direction, - 0, 0); - - if (hc->key_cache == NULL) { - _pygi_arg_cache_free ( (PyGIArgCache *)hc); - return NULL; - } - - hc->value_cache = _arg_cache_new (value_type_info, - NULL, - NULL, - item_transfer, - direction, - 0, 0); - - if (hc->value_cache == NULL) { - _pygi_arg_cache_free ( (PyGIArgCache *)hc); - return NULL; + if (sc->item_cache == NULL) { + return FALSE; } - g_base_info_unref( (GIBaseInfo *)key_type_info); - g_base_info_unref( (GIBaseInfo *)value_type_info); - - return hc; + return TRUE; } -static PyGICallbackCache * -_callback_cache_new (GIArgInfo *arg_info, - GIInterfaceInfo *iface_info, - gssize child_offset) +PyGIArgCache * +pygi_arg_cache_alloc (void) { - PyGICallbackCache *cc; - - cc = g_slice_new0 (PyGICallbackCache); - ( (PyGIArgCache *)cc)->destroy_notify = (GDestroyNotify)_callback_cache_free_func; - - cc->user_data_index = g_arg_info_get_closure (arg_info); - if (cc->user_data_index != -1) - cc->user_data_index += child_offset; - cc->destroy_notify_index = g_arg_info_get_destroy (arg_info); - if (cc->destroy_notify_index != -1) - cc->destroy_notify_index += child_offset; - cc->scope = g_arg_info_get_scope (arg_info); - g_base_info_ref( (GIBaseInfo *)iface_info); - cc->interface_info = iface_info; - return cc; + return g_slice_new0 (PyGIArgCache); } static PyGIArgCache * -_arg_cache_alloc (void) +_arg_cache_new_for_interface (GIInterfaceInfo *iface_info, + GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache) { - return g_slice_new0 (PyGIArgCache); -} + GIInfoType info_type; -static void -_arg_cache_from_py_basic_type_setup (PyGIArgCache *arg_cache) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_basic_type_cache_adapter; -} + info_type = g_base_info_get_type ( (GIBaseInfo *)iface_info); -static void -_arg_cache_to_py_basic_type_setup (PyGIArgCache *arg_cache) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_basic_type_cache_adapter; -} + switch (info_type) { + case GI_INFO_TYPE_CALLBACK: + return pygi_arg_callback_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info, + callable_cache); + case GI_INFO_TYPE_OBJECT: + case GI_INFO_TYPE_INTERFACE: + return pygi_arg_gobject_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info, + callable_cache); + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_STRUCT: + case GI_INFO_TYPE_UNION: + return pygi_arg_struct_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info); + case GI_INFO_TYPE_ENUM: + return pygi_arg_enum_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info); + case GI_INFO_TYPE_FLAGS: + return pygi_arg_flags_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info); + default: + g_assert_not_reached (); + } -static void -_arg_cache_from_py_void_setup (PyGIArgCache *arg_cache) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_void; + return NULL; } -static void -_arg_cache_to_py_void_setup (PyGIArgCache *arg_cache) +PyGIArgCache * +pygi_arg_cache_new (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache, + gssize c_arg_index, + gssize py_arg_index) { - arg_cache->to_py_marshaller = _pygi_marshal_to_py_void; -} + PyGIArgCache *arg_cache = NULL; + GITypeTag type_tag; -static void -_arg_cache_from_py_utf8_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_basic_type_cache_adapter; - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_utf8; -} + type_tag = g_type_info_get_tag (type_info); -static void -_arg_cache_to_py_utf8_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_basic_type_cache_adapter; - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_utf8; -} + switch (type_tag) { + case GI_TYPE_TAG_VOID: + case GI_TYPE_TAG_BOOLEAN: + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + case GI_TYPE_TAG_UNICHAR: + case GI_TYPE_TAG_GTYPE: + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + arg_cache = pygi_arg_basic_type_new_from_info (type_info, + arg_info, + transfer, + direction); + break; -static gboolean -_arg_cache_from_py_array_setup (PyGIArgCache *arg_cache, - PyGICallableCache *callable_cache, - GITypeInfo *type_info, - GITransfer transfer, - PyGIDirection direction, - gssize arg_index) -{ - PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; - seq_cache->array_type = g_type_info_get_array_type (type_info); + case GI_TYPE_TAG_ARRAY: + { + arg_cache = pygi_arg_garray_new_from_info (type_info, + arg_info, + transfer, + direction, + callable_cache); + if (arg_cache == NULL) + return NULL; + + pygi_arg_garray_len_arg_setup (arg_cache, + type_info, + callable_cache, + direction, + c_arg_index, + &py_arg_index); + } + break; - arg_cache->from_py_marshaller = _pygi_marshal_from_py_array; + case GI_TYPE_TAG_GLIST: + arg_cache = pygi_arg_glist_new_from_info (type_info, + arg_info, + transfer, + direction, + callable_cache); + break; - if (seq_cache->len_arg_index >= 0) { - PyGIArgCache *child_cache = - callable_cache->args_cache[seq_cache->len_arg_index]; + case GI_TYPE_TAG_GSLIST: + arg_cache = pygi_arg_gslist_new_from_info (type_info, + arg_info, + transfer, + direction, + callable_cache); + break; - if (child_cache == NULL) { - child_cache = _arg_cache_alloc (); - } else if (child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD || - child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE) { - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array; - return TRUE; - } + case GI_TYPE_TAG_GHASH: + arg_cache = pygi_arg_hash_table_new_from_info (type_info, + arg_info, + transfer, + direction, + callable_cache); + break; - if (seq_cache->len_arg_index < arg_index) - child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE; - else - child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; + case GI_TYPE_TAG_INTERFACE: + { + GIInterfaceInfo *interface_info = g_type_info_get_interface (type_info); + arg_cache = _arg_cache_new_for_interface (interface_info, + type_info, + arg_info, + transfer, + direction, + callable_cache); - child_cache->direction = direction; - child_cache->to_py_marshaller = NULL; - child_cache->from_py_marshaller = NULL; + g_base_info_unref ( (GIBaseInfo *)interface_info); + } + break; - callable_cache->args_cache[seq_cache->len_arg_index] = child_cache; + case GI_TYPE_TAG_ERROR: + arg_cache = pygi_arg_gerror_new_from_info (type_info, + arg_info, + transfer, + direction); + break; + default: + break; } - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array; - - return TRUE; -} - -static gboolean -_arg_cache_to_py_array_setup (PyGIArgCache *arg_cache, - PyGICallableCache *callable_cache, - GITypeInfo *type_info, - GITransfer transfer, - PyGIDirection direction, - gssize arg_index) -{ - PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; - arg_cache->to_py_marshaller = _pygi_marshal_to_py_array; - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_array; - - seq_cache->array_type = g_type_info_get_array_type (type_info); - - if (seq_cache->len_arg_index >= 0) { - PyGIArgCache *child_cache = callable_cache->args_cache[seq_cache->len_arg_index]; - if (seq_cache->len_arg_index < arg_index) - callable_cache->n_to_py_child_args++; - - if (child_cache != NULL) { - callable_cache->to_py_args = - g_slist_remove (callable_cache->to_py_args, child_cache); - - if (child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD || - child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE) - return TRUE; - } else { - child_cache = _arg_cache_alloc (); - } - - child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; - child_cache->direction = direction; - child_cache->to_py_marshaller = NULL; - child_cache->from_py_marshaller = NULL; - - callable_cache->args_cache[seq_cache->len_arg_index] = child_cache; + if (arg_cache != NULL) { + arg_cache->py_arg_index = py_arg_index; + arg_cache->c_arg_index = c_arg_index; } - return TRUE; + return arg_cache; } -static void -_arg_cache_from_py_glist_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_glist; - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist; -} +/* PyGICallableCache */ -static void -_arg_cache_to_py_glist_setup (PyGIArgCache *arg_cache, - GITransfer transfer) +static PyGIDirection +_pygi_get_direction (PyGICallableCache *callable_cache, GIDirection gi_direction) { - arg_cache->to_py_marshaller = _pygi_marshal_to_py_glist; - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist; + /* For vfuncs and callbacks our marshalling directions are reversed */ + if (gi_direction == GI_DIRECTION_INOUT) { + return PYGI_DIRECTION_BIDIRECTIONAL; + } else if (gi_direction == GI_DIRECTION_IN) { + if (callable_cache->calling_context != PYGI_CALLING_CONTEXT_IS_FROM_PY) + return PYGI_DIRECTION_TO_PYTHON; + return PYGI_DIRECTION_FROM_PYTHON; + } else { + if (callable_cache->calling_context != PYGI_CALLING_CONTEXT_IS_FROM_PY) + return PYGI_DIRECTION_FROM_PYTHON; + return PYGI_DIRECTION_TO_PYTHON; + } } -static void -_arg_cache_from_py_gslist_setup (PyGIArgCache *arg_cache, - GITransfer transfer) +/* Generate the cache for the callable's arguments */ +static gboolean +_callable_cache_generate_args_cache_real (PyGICallableCache *callable_cache, + GICallableInfo *callable_info) { - arg_cache->from_py_marshaller = _pygi_marshal_from_py_gslist; - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist; -} + gint i; + guint arg_index; + GITypeInfo *return_info; + GITransfer return_transfer; + PyGIArgCache *return_cache; + PyGIDirection return_direction; + gssize last_explicit_arg_index; + PyObject *tuple_names; + GSList *arg_cache_item; + PyTypeObject* resulttuple_type; -static void -_arg_cache_to_py_gslist_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_gslist; - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist; -} + /* Return arguments are always considered out */ + return_direction = _pygi_get_direction (callable_cache, GI_DIRECTION_OUT); -static void -_arg_cache_from_py_ghash_setup (PyGIArgCache *arg_cache) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_ghash; - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_ghash; -} + /* cache the return arg */ + return_info = + g_callable_info_get_return_type (callable_info); + return_transfer = + g_callable_info_get_caller_owns (callable_info); + return_cache = + pygi_arg_cache_new (return_info, + NULL, + return_transfer, + return_direction, + callable_cache, + -1, + -1); + if (return_cache == NULL) + return FALSE; -static void -_arg_cache_to_py_ghash_setup (PyGIArgCache *arg_cache) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_ghash; - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_ghash; -} + return_cache->is_skipped = g_callable_info_skip_return (callable_info); + callable_cache->return_cache = return_cache; + g_base_info_unref (return_info); -static void -_arg_cache_from_py_gerror_setup (PyGIArgCache *arg_cache) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_gerror; - arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; -} + callable_cache->user_data_index = -1; -static void -_arg_cache_to_py_gerror_setup (PyGIArgCache *arg_cache) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_gerror; - arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; -} + for (i = 0, arg_index = (guint)callable_cache->args_offset; + arg_index < _pygi_callable_cache_args_len (callable_cache); + i++, arg_index++) { + PyGIArgCache *arg_cache = NULL; + GIArgInfo *arg_info; + PyGIDirection direction; -static void -_arg_cache_from_py_interface_union_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_struct_cache_adapter; -} + arg_info = g_callable_info_get_arg (callable_info, i); -static void -_arg_cache_to_py_interface_union_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_struct_cache_adapter; -} + /* This only happens when dealing with callbacks */ + if (g_arg_info_get_closure (arg_info) == i) { + callable_cache->user_data_index = i; -static void -_arg_cache_from_py_interface_struct_setup (PyGIArgCache *arg_cache, - GIInterfaceInfo *iface_info, - GITransfer transfer) -{ - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info); - arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_struct_cache_adapter; - - if (iface_cache->g_type == G_TYPE_VALUE) - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_gvalue; - else if (iface_cache->is_foreign) - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_foreign; -} + arg_cache = pygi_arg_cache_alloc (); + _pygi_callable_cache_set_arg (callable_cache, arg_index, arg_cache); -static void -_arg_cache_to_py_interface_struct_setup (PyGIArgCache *arg_cache, - GIInterfaceInfo *iface_info, - GITransfer transfer) -{ - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info); - arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_struct_cache_adapter; + direction = _pygi_get_direction (callable_cache, GI_DIRECTION_IN); + arg_cache->direction = direction; + arg_cache->meta_type = PYGI_META_ARG_TYPE_CLOSURE; + arg_cache->c_arg_index = i; + arg_cache->is_pointer = TRUE; - if (iface_cache->is_foreign) - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_struct_foreign; -} + } else { + GITypeInfo *type_info; + + direction = _pygi_get_direction (callable_cache, + g_arg_info_get_direction (arg_info)); + type_info = g_arg_info_get_type (arg_info); + + /* must be an child arg filled in by its owner + * and continue + * fill in it's c_arg_index, add to the in count + */ + arg_cache = _pygi_callable_cache_get_arg (callable_cache, arg_index); + if (arg_cache != NULL) { + /* ensure c_arg_index always aligns with callable_cache->args_cache + * and all of the various PyGIInvokeState arrays. */ + arg_cache->c_arg_index = arg_index; + + if (arg_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_WITH_PYARG) { + arg_cache->py_arg_index = callable_cache->n_py_args; + callable_cache->n_py_args++; + } -static void -_arg_cache_from_py_interface_object_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_object; - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_object; -} + if (direction & PYGI_DIRECTION_TO_PYTHON) { + callable_cache->n_to_py_args++; + } -static void -_arg_cache_to_py_interface_object_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_object_cache_adapter; - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_object; -} + arg_cache->type_tag = g_type_info_get_tag (type_info); -static void -_arg_cache_from_py_interface_callback_setup (PyGIArgCache *arg_cache, - PyGICallableCache *callable_cache) -{ - PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache; - if (callback_cache->user_data_index >= 0) { - PyGIArgCache *user_data_arg_cache = _arg_cache_alloc (); - user_data_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_WITH_PYARG; - user_data_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON; - callable_cache->args_cache[callback_cache->user_data_index] = user_data_arg_cache; - } + } else { + GITransfer transfer; + gssize py_arg_index = -1; - if (callback_cache->destroy_notify_index >= 0) { - PyGIArgCache *destroy_arg_cache = _arg_cache_alloc (); - destroy_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; - destroy_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON; - callable_cache->args_cache[callback_cache->destroy_notify_index] = destroy_arg_cache; - } - arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_callback; - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_callback; -} + transfer = g_arg_info_get_ownership_transfer (arg_info); -static void -_arg_cache_to_py_interface_callback_setup (void) -{ - PyErr_Format(PyExc_NotImplementedError, - "Callback returns are not supported"); -} + if (direction & PYGI_DIRECTION_FROM_PYTHON) { + py_arg_index = callable_cache->n_py_args; + callable_cache->n_py_args++; + } -static void -_arg_cache_from_py_interface_enum_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_enum; -} + arg_cache = + pygi_arg_cache_new (type_info, + arg_info, + transfer, + direction, + callable_cache, + arg_index, + py_arg_index); + + if (arg_cache == NULL) { + g_base_info_unref( (GIBaseInfo *)type_info); + g_base_info_unref( (GIBaseInfo *)arg_info); + return FALSE; + } -static void -_arg_cache_to_py_interface_enum_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_enum; -} -static void -_arg_cache_from_py_interface_flags_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_flags; -} + if (direction & PYGI_DIRECTION_TO_PYTHON) { + callable_cache->n_to_py_args++; -static void -_arg_cache_to_py_interface_flags_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_flags; -} + callable_cache->to_py_args = + g_slist_append (callable_cache->to_py_args, arg_cache); + } -PyGIArgCache * -_arg_cache_new_for_interface (GIInterfaceInfo *iface_info, - PyGICallableCache *callable_cache, - GIArgInfo *arg_info, - GITransfer transfer, - PyGIDirection direction, - gssize c_arg_index, - gssize py_arg_index) -{ - PyGIInterfaceCache *iface_cache = NULL; - PyGIArgCache *arg_cache = NULL; - gssize child_offset = 0; - GIInfoType info_type; + _pygi_callable_cache_set_arg (callable_cache, arg_index, arg_cache); + } - if (callable_cache != NULL) - child_offset = - (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD || - callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0; + g_base_info_unref (type_info); + } - info_type = g_base_info_get_type ( (GIBaseInfo *)iface_info); + /* Ensure arguments always have a name when available */ + arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); - /* Callbacks are special cased */ - if (info_type != GI_INFO_TYPE_CALLBACK) { - iface_cache = _interface_cache_new (iface_info); + g_base_info_unref ( (GIBaseInfo *)arg_info); - arg_cache = (PyGIArgCache *)iface_cache; - if (arg_cache == NULL) - return NULL; } - switch (info_type) { - case GI_INFO_TYPE_UNION: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_interface_union_setup (arg_cache, transfer); - - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_interface_union_setup (arg_cache, transfer); - - break; - case GI_INFO_TYPE_BOXED: - case GI_INFO_TYPE_STRUCT: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_interface_struct_setup (arg_cache, - iface_info, - transfer); - - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_interface_struct_setup (arg_cache, - iface_info, - transfer); - break; - case GI_INFO_TYPE_OBJECT: - case GI_INFO_TYPE_INTERFACE: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_interface_object_setup (arg_cache, transfer); - - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_interface_object_setup (arg_cache, transfer); - - break; - case GI_INFO_TYPE_CALLBACK: - { - PyGICallbackCache *callback_cache; + if (callable_cache->arg_name_hash == NULL) { + callable_cache->arg_name_hash = g_hash_table_new (g_str_hash, g_str_equal); + } else { + g_hash_table_remove_all (callable_cache->arg_name_hash); + } + callable_cache->n_py_required_args = 0; + callable_cache->user_data_varargs_index = -1; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - _arg_cache_to_py_interface_callback_setup (); - return NULL; - } + last_explicit_arg_index = -1; - callback_cache = - _callback_cache_new (arg_info, - iface_info, - child_offset); + /* Reverse loop through all the arguments to setup arg_name_list/hash + * and find the number of required arguments */ + for (i=(_pygi_callable_cache_args_len (callable_cache))-1; i >= 0; i--) { + PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (callable_cache, i); - arg_cache = (PyGIArgCache *)callback_cache; - if (arg_cache == NULL) - return NULL; + if (arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD && + arg_cache->meta_type != PYGI_META_ARG_TYPE_CLOSURE && + arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) { - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_interface_callback_setup (arg_cache, callable_cache); + /* Setup arg_name_list and arg_name_hash */ + gpointer arg_name = (gpointer)arg_cache->arg_name; + callable_cache->arg_name_list = g_slist_prepend (callable_cache->arg_name_list, + arg_name); + if (arg_name != NULL) { + g_hash_table_insert (callable_cache->arg_name_hash, + arg_name, + GINT_TO_POINTER(i)); + } - break; + /* The first tail argument without a default will force all the preceding + * argument defaults off. This limits support of default args to the + * tail of an args list. + */ + if (callable_cache->n_py_required_args > 0) { + arg_cache->has_default = FALSE; + callable_cache->n_py_required_args += 1; + } else if (!arg_cache->has_default) { + callable_cache->n_py_required_args += 1; } - case GI_INFO_TYPE_ENUM: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_interface_enum_setup (arg_cache, transfer); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_interface_enum_setup (arg_cache, transfer); + if (last_explicit_arg_index == -1) { + last_explicit_arg_index = i; - break; - case GI_INFO_TYPE_FLAGS: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_interface_flags_setup (arg_cache, transfer); + /* If the last "from python" argument in the args list is a child + * with pyarg (currently only callback user_data). Set it to eat + * variable args in the callable cache. + */ + if (arg_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_WITH_PYARG) + callable_cache->user_data_varargs_index = i; + } + } + } - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_interface_flags_setup (arg_cache, transfer); + if (!return_cache->is_skipped && return_cache->type_tag != GI_TYPE_TAG_VOID) { + callable_cache->has_return = TRUE; + } - break; - default: - g_assert_not_reached (); + tuple_names = PyList_New (0); + if (callable_cache->has_return) { + PyList_Append (tuple_names, Py_None); } - if (arg_cache != NULL) { - arg_cache->direction = direction; - arg_cache->transfer = transfer; - arg_cache->type_tag = GI_TYPE_TAG_INTERFACE; - arg_cache->py_arg_index = py_arg_index; - arg_cache->c_arg_index = c_arg_index; + arg_cache_item = callable_cache->to_py_args; + while (arg_cache_item) { + const gchar *arg_name = ((PyGIArgCache *)arg_cache_item->data)->arg_name; + PyObject *arg_string = PyUnicode_FromString (arg_name); + PyList_Append (tuple_names, arg_string); + Py_DECREF (arg_string); + arg_cache_item = arg_cache_item->next; + } - if (iface_cache != NULL) { - g_base_info_ref ( (GIBaseInfo *)iface_info); - iface_cache->interface_info = iface_info; + /* No need to create a tuple type if there aren't multiple values */ + if (PyList_Size (tuple_names) > 1) { + resulttuple_type = pygi_resulttuple_new_type (tuple_names); + if (resulttuple_type == NULL) { + Py_DECREF (tuple_names); + return FALSE; + } else { + callable_cache->resulttuple_type = resulttuple_type; } } + Py_DECREF (tuple_names); - return arg_cache; + return TRUE; } -PyGIArgCache * -_arg_cache_new (GITypeInfo *type_info, - PyGICallableCache *callable_cache, - GIArgInfo *arg_info, - GITransfer transfer, - PyGIDirection direction, - gssize c_arg_index, - gssize py_arg_index) +static void +_callable_cache_deinit_real (PyGICallableCache *cache) { - PyGIArgCache *arg_cache = NULL; - gssize child_offset = 0; - GITypeTag type_tag; + g_clear_pointer (&cache->to_py_args, g_slist_free); + g_clear_pointer (&cache->arg_name_list, g_slist_free); + g_clear_pointer (&cache->arg_name_hash, g_hash_table_unref); + g_clear_pointer (&cache->args_cache, g_ptr_array_unref); + Py_CLEAR (cache->resulttuple_type); - type_tag = g_type_info_get_tag (type_info); + g_clear_pointer (&cache->return_cache, pygi_arg_cache_free); +} - if (callable_cache != NULL) - child_offset = - (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD || - callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0; +static gboolean +_callable_cache_init (PyGICallableCache *cache, + GICallableInfo *callable_info) +{ + gint n_args; + GIBaseInfo *container; + + if (cache->deinit == NULL) + cache->deinit = _callable_cache_deinit_real; + + if (cache->generate_args_cache == NULL) + cache->generate_args_cache = _callable_cache_generate_args_cache_real; + + cache->name = g_base_info_get_name ((GIBaseInfo *) callable_info); + cache->namespace = g_base_info_get_namespace ((GIBaseInfo *) callable_info); + container = g_base_info_get_container ((GIBaseInfo *) callable_info); + cache->container_name = NULL; + /* https://bugzilla.gnome.org/show_bug.cgi?id=709456 */ + if (container != NULL && g_base_info_get_type (container) != GI_INFO_TYPE_TYPE) { + cache->container_name = g_base_info_get_name (container); + } + cache->throws = g_callable_info_can_throw_gerror ((GIBaseInfo *) callable_info); - switch (type_tag) { - case GI_TYPE_TAG_VOID: - arg_cache = _arg_cache_alloc (); - if (arg_cache == NULL) - break; + if (g_base_info_is_deprecated (callable_info)) { + const gchar *deprecated = g_base_info_get_attribute (callable_info, "deprecated"); + gchar *warning; + gchar *full_name = pygi_callable_cache_get_full_name (cache); + if (deprecated != NULL) + warning = g_strdup_printf ("%s is deprecated: %s", + full_name, + deprecated); + else + warning = g_strdup_printf ("%s is deprecated", + full_name); + g_free (full_name); + PyErr_WarnEx (PyExc_DeprecationWarning, warning, 0); + g_free (warning); + } - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_void_setup (arg_cache); + n_args = (gint)cache->args_offset + g_callable_info_get_n_args (callable_info); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_void_setup (arg_cache); + if (n_args >= 0) { + cache->args_cache = g_ptr_array_new_full (n_args, (GDestroyNotify) pygi_arg_cache_free); + g_ptr_array_set_size (cache->args_cache, n_args); + } - break; - case GI_TYPE_TAG_BOOLEAN: - case GI_TYPE_TAG_INT8: - case GI_TYPE_TAG_UINT8: - case GI_TYPE_TAG_INT16: - case GI_TYPE_TAG_UINT16: - case GI_TYPE_TAG_INT32: - case GI_TYPE_TAG_UINT32: - case GI_TYPE_TAG_INT64: - case GI_TYPE_TAG_UINT64: - case GI_TYPE_TAG_FLOAT: - case GI_TYPE_TAG_DOUBLE: - case GI_TYPE_TAG_UNICHAR: - case GI_TYPE_TAG_GTYPE: - arg_cache = _arg_cache_alloc (); - if (arg_cache == NULL) - break; + if (!cache->generate_args_cache (cache, callable_info)) { + _callable_cache_deinit_real (cache); + return FALSE; + } - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_basic_type_setup (arg_cache); + return TRUE; +} - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_basic_type_setup (arg_cache); +gchar * +pygi_callable_cache_get_full_name (PyGICallableCache *cache) +{ + if (cache->container_name != NULL) { + return g_strjoin (".", + cache->namespace, + cache->container_name, + cache->name, + NULL); + } else { + return g_strjoin (".", + cache->namespace, + cache->name, + NULL); + } +} - break; - case GI_TYPE_TAG_UTF8: - case GI_TYPE_TAG_FILENAME: - arg_cache = _arg_cache_alloc (); - if (arg_cache == NULL) - break; +void +pygi_callable_cache_free (PyGICallableCache *cache) +{ + cache->deinit (cache); + g_free (cache); +} - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_utf8_setup (arg_cache, transfer); +/* PyGIFunctionCache */ - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_utf8_setup (arg_cache, transfer); +static PyObject * +_function_cache_invoke_real (PyGIFunctionCache *function_cache, + PyGIInvokeState *state, + PyObject *py_args, + PyObject *py_kwargs) +{ + return pygi_invoke_c_callable (function_cache, state, + py_args, py_kwargs); +} - break; - case GI_TYPE_TAG_ARRAY: - { - PyGISequenceCache *seq_cache = - _sequence_cache_new (type_info, - direction, - transfer, - child_offset); +static void +_function_cache_deinit_real (PyGICallableCache *callable_cache) +{ + g_function_invoker_destroy (&((PyGIFunctionCache *) callable_cache)->invoker); - arg_cache = (PyGIArgCache *)seq_cache; - if (arg_cache == NULL) - break; + _callable_cache_deinit_real (callable_cache); +} - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_array_setup (arg_cache, - callable_cache, - type_info, - transfer, - direction, - c_arg_index); +static gboolean +_function_cache_init (PyGIFunctionCache *function_cache, + GICallableInfo *callable_info) +{ + PyGICallableCache *callable_cache = (PyGICallableCache *) function_cache; + GIFunctionInvoker *invoker = &function_cache->invoker; + GError *error = NULL; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_array_setup (arg_cache, - callable_cache, - type_info, - transfer, - direction, - c_arg_index); - - /* ugly edge case code: - * - * length can come before the array parameter which means we - * need to update indexes if this happens - */ - if (seq_cache->len_arg_index > -1 && - callable_cache->args_cache[seq_cache->len_arg_index]->meta_type == PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE) { - gssize i; - PyGIArgCache *child_cache = - callable_cache->args_cache[seq_cache->len_arg_index]; - - child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; - py_arg_index -= 1; - callable_cache->n_py_args -= 1; - - for (i = seq_cache->len_arg_index + 1; - i < callable_cache->n_args; - i++) { - PyGIArgCache *update_cache = callable_cache->args_cache[i]; - if (update_cache == NULL) - break; - - update_cache->py_arg_index -= 1; - } - } - - break; - } - case GI_TYPE_TAG_GLIST: - { - PyGISequenceCache *seq_cache = - _sequence_cache_new (type_info, - direction, - transfer, - child_offset); + callable_cache->calling_context = PYGI_CALLING_CONTEXT_IS_FROM_PY; - arg_cache = (PyGIArgCache *)seq_cache; - if (arg_cache == NULL) - break; + if (callable_cache->deinit == NULL) + callable_cache->deinit = _function_cache_deinit_real; - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_glist_setup (arg_cache, transfer); + if (function_cache->invoke == NULL) + function_cache->invoke = _function_cache_invoke_real; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_glist_setup (arg_cache, transfer); + if (!_callable_cache_init (callable_cache, callable_info)) + return FALSE; + /* Set by PyGICCallbackCache and PyGIVFuncCache */ + if (invoker->native_address == NULL) { + if (g_function_info_prep_invoker ((GIFunctionInfo *) callable_info, + invoker, + &error)) { + return TRUE; + } + } else { + if (g_function_invoker_new_for_address (invoker->native_address, + (GIFunctionInfo *) callable_info, + invoker, + &error)) { + return TRUE; + } + } - break; - } - case GI_TYPE_TAG_GSLIST: - { - PyGISequenceCache *seq_cache = - _sequence_cache_new (type_info, - direction, - transfer, - child_offset); + if (!pygi_error_check (&error)) { + PyErr_Format (PyExc_RuntimeError, + "unknown error creating invoker for %s", + g_base_info_get_name ((GIBaseInfo *) callable_info)); + } - arg_cache = (PyGIArgCache *)seq_cache; - if (arg_cache == NULL) - break; + _callable_cache_deinit_real (callable_cache); + return FALSE; +} - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_gslist_setup (arg_cache, transfer); +PyGIFunctionCache * +pygi_function_cache_new (GICallableInfo *info) +{ + PyGIFunctionCache *function_cache; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_gslist_setup (arg_cache, transfer); + function_cache = g_new0 (PyGIFunctionCache, 1); - break; - } - case GI_TYPE_TAG_GHASH: - arg_cache = - (PyGIArgCache *)_hash_cache_new (type_info, - direction, - transfer); + if (!_function_cache_init (function_cache, info)) { + g_free (function_cache); + return NULL; + } - if (arg_cache == NULL) - break; + return function_cache; +} - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_ghash_setup (arg_cache); +PyObject * +pygi_function_cache_invoke (PyGIFunctionCache *function_cache, + PyObject *py_args, + PyObject *py_kwargs) +{ + PyGIInvokeState state = { 0, }; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - _arg_cache_to_py_ghash_setup (arg_cache); - } + return function_cache->invoke (function_cache, &state, + py_args, py_kwargs); +} - break; - case GI_TYPE_TAG_INTERFACE: - { - GIInterfaceInfo *interface_info = g_type_info_get_interface (type_info); - arg_cache = _arg_cache_new_for_interface (interface_info, - callable_cache, - arg_info, - transfer, - direction, - c_arg_index, - py_arg_index); +/* PyGICCallbackCache */ - g_base_info_unref ( (GIBaseInfo *)interface_info); - break; - } - case GI_TYPE_TAG_ERROR: - arg_cache = _arg_cache_alloc (); - if (arg_cache == NULL) - break; +PyGIFunctionCache * +pygi_ccallback_cache_new (GICallableInfo *info, + GCallback function_ptr) +{ + PyGICCallbackCache *ccallback_cache; + PyGIFunctionCache *function_cache; - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_gerror_setup (arg_cache); + ccallback_cache = g_new0 (PyGICCallbackCache, 1); + function_cache = (PyGIFunctionCache *) ccallback_cache; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_gerror_setup (arg_cache); + function_cache->invoker.native_address = function_ptr; - break; - } + if (!_function_cache_init (function_cache, info)) { + g_free (ccallback_cache); + return NULL; + } - if (arg_cache != NULL) { - arg_cache->direction = direction; - arg_cache->transfer = transfer; - arg_cache->type_tag = type_tag; - arg_cache->py_arg_index = py_arg_index; - arg_cache->c_arg_index = c_arg_index; - arg_cache->is_pointer = g_type_info_is_pointer (type_info); - g_base_info_ref ( (GIBaseInfo *) type_info); - arg_cache->type_info = type_info; - } + return function_cache; +} - return arg_cache; +PyObject * +pygi_ccallback_cache_invoke (PyGICCallbackCache *ccallback_cache, + PyObject *py_args, + PyObject *py_kwargs, + gpointer user_data) +{ + PyGIFunctionCache *function_cache = (PyGIFunctionCache *) ccallback_cache; + PyGIInvokeState state = { 0, }; + + state.user_data = user_data; + + return function_cache->invoke (function_cache, &state, + py_args, py_kwargs); } -static void -_arg_name_list_generate (PyGICallableCache *callable_cache) +/* PyGIConstructorCache */ + +static PyObject * +_constructor_cache_invoke_real (PyGIFunctionCache *function_cache, + PyGIInvokeState *state, + PyObject *py_args, + PyObject *py_kwargs) { - GSList * arg_name_list = NULL; - int i; + PyGICallableCache *cache = (PyGICallableCache *) function_cache; + PyObject *constructor_class; + PyObject *ret; + + constructor_class = PyTuple_GetItem (py_args, 0); + if (constructor_class == NULL) { + gchar *full_name = pygi_callable_cache_get_full_name (cache); + PyErr_Clear (); + PyErr_Format (PyExc_TypeError, + "Constructors require the class to be passed in as an argument, " + "No arguments passed to the %s constructor.", + full_name); + g_free (full_name); - if (callable_cache->arg_name_hash == NULL) { - callable_cache->arg_name_hash = g_hash_table_new (g_str_hash, g_str_equal); - } else { - g_hash_table_remove_all (callable_cache->arg_name_hash); + return FALSE; } - for (i=0; i < callable_cache->n_args; i++) { - PyGIArgCache *arg_cache = NULL; + py_args = PyTuple_GetSlice (py_args, 1, PyTuple_Size (py_args)); + ret = _function_cache_invoke_real (function_cache, state, + py_args, py_kwargs); + Py_DECREF (py_args); - arg_cache = callable_cache->args_cache[i]; + if (ret == NULL || cache->return_cache->is_skipped) + return ret; - if (arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD && - arg_cache->meta_type != PYGI_META_ARG_TYPE_CLOSURE && - (arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON || - arg_cache->direction == PYGI_DIRECTION_BIDIRECTIONAL)) { - - gpointer arg_name = (gpointer)arg_cache->arg_name; + if (ret != Py_None) { + if (!PyTuple_Check (ret)) + return ret; - arg_name_list = g_slist_prepend (arg_name_list, arg_name); - if (arg_name != NULL) { - g_hash_table_insert (callable_cache->arg_name_hash, arg_name, arg_name); - } - } + if (PyTuple_GET_ITEM (ret, 0) != Py_None) + return ret; } - callable_cache->arg_name_list = g_slist_reverse (arg_name_list); + PyErr_SetString (PyExc_TypeError, "constructor returned NULL"); + + Py_DECREF (ret); + return NULL; } -/* Generate the cache for the callable's arguments */ -static gboolean -_args_cache_generate (GICallableInfo *callable_info, - PyGICallableCache *callable_cache) +PyGIFunctionCache * +pygi_constructor_cache_new (GICallableInfo *info) { - gssize arg_index = 0; - gssize i; - GITypeInfo *return_info; - GITransfer return_transfer; - PyGIArgCache *return_cache; - PyGIDirection return_direction; - - /* determine if we are marshalling the return to or from python */ - if (callable_cache->function_type == PYGI_FUNCTION_TYPE_CALLBACK) - return_direction = PYGI_DIRECTION_FROM_PYTHON; - else - return_direction = PYGI_DIRECTION_TO_PYTHON; + PyGIConstructorCache *constructor_cache; + PyGIFunctionCache *function_cache; - /* cache the return arg */ - return_info = - g_callable_info_get_return_type (callable_info); - return_transfer = - g_callable_info_get_caller_owns (callable_info); - return_cache = - _arg_cache_new (return_info, - callable_cache, - NULL, - return_transfer, - return_direction, - -1, - -1); - if (return_cache == NULL) - return FALSE; + constructor_cache = g_new0 (PyGIConstructorCache, 1); + function_cache = (PyGIFunctionCache *) constructor_cache; - return_cache->is_skipped = g_callable_info_skip_return (callable_info); - callable_cache->return_cache = return_cache; - g_base_info_unref (return_info); + function_cache->invoke = _constructor_cache_invoke_real; - /* first arg is the instance */ - if (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD || - callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) { - GIInterfaceInfo *interface_info; - PyGIArgCache *instance_cache; - PyGIDirection instance_direction; + if (!_function_cache_init (function_cache, info)) { + g_free (constructor_cache); + return NULL; + } - instance_direction = PYGI_DIRECTION_FROM_PYTHON; + return function_cache; +} +/* PyGIFunctionWithInstanceCache */ - interface_info = g_base_info_get_container ( (GIBaseInfo *)callable_info); +static gboolean +_function_with_instance_cache_generate_args_cache_real (PyGICallableCache *callable_cache, + GICallableInfo *callable_info) +{ + GIInterfaceInfo *interface_info; + PyGIArgCache *instance_cache; + GITransfer transfer; - instance_cache = - _arg_cache_new_for_interface (interface_info, - callable_cache, - NULL, - GI_TRANSFER_NOTHING, - instance_direction, - arg_index, - 0); + interface_info = g_base_info_get_container ((GIBaseInfo *) callable_info); + transfer = g_callable_info_get_instance_ownership_transfer (callable_info); - /* FIXME: marshal interfaces from_py */ - instance_cache->from_py_marshaller = _pygi_marshal_from_py_interface_instance; - g_base_info_unref ( (GIBaseInfo *)interface_info); + instance_cache = + _arg_cache_new_for_interface (interface_info, + NULL, + NULL, + transfer, + PYGI_DIRECTION_FROM_PYTHON, + callable_cache); - if (instance_cache == NULL) - return FALSE; + if (instance_cache == NULL) + return FALSE; - callable_cache->args_cache[arg_index] = instance_cache; + /* Because we are not supplied a GITypeInfo for instance arguments, + * assume some defaults. */ + instance_cache->is_pointer = TRUE; + instance_cache->py_arg_index = 0; + instance_cache->c_arg_index = 0; - arg_index++; - callable_cache->n_from_py_args++; - callable_cache->n_py_args++; - } + _pygi_callable_cache_set_arg (callable_cache, 0, instance_cache); + callable_cache->n_py_args++; - for (i=0; arg_index < callable_cache->n_args; arg_index++, i++) { - PyGIArgCache *arg_cache = NULL; - GIArgInfo *arg_info; - GITypeInfo *type_info; - GIDirection gi_direction; - PyGIDirection direction; - GITransfer transfer; - GITypeTag type_tag; - gboolean is_caller_allocates = FALSE; - gssize py_arg_index = -1; + return _callable_cache_generate_args_cache_real (callable_cache, + callable_info); +} - arg_info = g_callable_info_get_arg (callable_info, i); +static gboolean +_function_with_instance_cache_init (PyGIFunctionWithInstanceCache *fwi_cache, + GICallableInfo *info) +{ + PyGICallableCache *callable_cache = (PyGICallableCache *) fwi_cache; - if (g_arg_info_get_closure (arg_info) == i) { + callable_cache->args_offset += 1; + callable_cache->generate_args_cache = _function_with_instance_cache_generate_args_cache_real; - arg_cache = _arg_cache_alloc (); - callable_cache->args_cache[arg_index] = arg_cache; + return _function_cache_init ((PyGIFunctionCache *) fwi_cache, info); +} - arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); - arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON; - arg_cache->meta_type = PYGI_META_ARG_TYPE_CLOSURE; - arg_cache->c_arg_index = i; +/* PyGIMethodCache */ - callable_cache->n_from_py_args++; +PyGIFunctionCache * +pygi_method_cache_new (GICallableInfo *info) +{ + PyGIMethodCache *method_cache; + PyGIFunctionWithInstanceCache *fwi_cache; - g_base_info_unref ( (GIBaseInfo *)arg_info); + method_cache = g_new0 (PyGIMethodCache, 1); + fwi_cache = (PyGIFunctionWithInstanceCache *) method_cache; - continue; - } + if (!_function_with_instance_cache_init (fwi_cache, info)) { + g_free (method_cache); + return NULL; + } - /* For vfuncs and callbacks our marshalling directions - are reversed */ - gi_direction = g_arg_info_get_direction (arg_info); - if (gi_direction == GI_DIRECTION_INOUT) { - direction = PYGI_DIRECTION_BIDIRECTIONAL; - } else if (gi_direction == GI_DIRECTION_IN) { - direction = PYGI_DIRECTION_FROM_PYTHON; - if (callable_cache->function_type == PYGI_FUNCTION_TYPE_CALLBACK) - direction = PYGI_DIRECTION_TO_PYTHON; - } else { - direction = PYGI_DIRECTION_TO_PYTHON; - if (callable_cache->function_type == PYGI_FUNCTION_TYPE_CALLBACK) - direction = PYGI_DIRECTION_FROM_PYTHON; - } + return (PyGIFunctionCache *) method_cache; +} - transfer = g_arg_info_get_ownership_transfer (arg_info); - type_info = g_arg_info_get_type (arg_info); - type_tag = g_type_info_get_tag (type_info); - - if (type_tag == GI_TYPE_TAG_INTERFACE || type_tag == GI_TYPE_TAG_ARRAY) - is_caller_allocates = g_arg_info_is_caller_allocates (arg_info); - - /* must be an child arg filled in by its owner - * and continue - * fill in it's c_arg_index, add to the in count - */ - if (callable_cache->args_cache[arg_index] != NULL) { - arg_cache = callable_cache->args_cache[arg_index]; - if (arg_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_WITH_PYARG) { - arg_cache->py_arg_index = callable_cache->n_py_args; - callable_cache->n_py_args++; - } +/* PyGIVFuncCache */ - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - arg_cache->c_arg_index = callable_cache->n_from_py_args; - callable_cache->n_from_py_args++; - } +static PyObject * +_vfunc_cache_invoke_real (PyGIFunctionCache *function_cache, + PyGIInvokeState *state, + PyObject *py_args, + PyObject *py_kwargs) +{ + PyGIVFuncCache *vfunc_cache = (PyGIVFuncCache *) function_cache; + PyObject *py_gtype; + GType implementor_gtype; + GError *error = NULL; + PyObject *ret; + + py_gtype = PyTuple_GetItem (py_args, 0); + if (py_gtype == NULL) { + PyErr_SetString (PyExc_TypeError, + "need the GType of the implementor class"); + return FALSE; + } - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - callable_cache->n_to_py_args++; - callable_cache->n_to_py_child_args++; - } + implementor_gtype = pyg_type_from_object (py_gtype); + if (implementor_gtype == G_TYPE_INVALID) + return FALSE; - arg_cache->type_tag = g_type_info_get_tag (type_info); + /* vfunc addresses are pulled into the state at call time and cannot be + * cached because the call site can specify a different portion of the + * class hierarchy. e.g. Object.do_func vs. SubObject.do_func might + * retrieve a different vfunc address but GI gives us the same vfunc info. + */ + state->function_ptr = g_vfunc_info_get_address ((GIVFuncInfo *) vfunc_cache->info, + implementor_gtype, + &error); + if (pygi_error_check (&error)) { + return FALSE; + } - g_base_info_unref (type_info); - g_base_info_unref ( (GIBaseInfo *)arg_info); - continue; - } + py_args = PyTuple_GetSlice (py_args, 1, PyTuple_Size (py_args)); + ret = _function_cache_invoke_real (function_cache, state, + py_args, py_kwargs); + Py_DECREF (py_args); - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - py_arg_index = callable_cache->n_py_args; - callable_cache->n_from_py_args++; - callable_cache->n_py_args++; - } + return ret; +} - arg_cache = - _arg_cache_new (type_info, - callable_cache, - arg_info, - transfer, - direction, - arg_index, - py_arg_index); +static void +_vfunc_cache_deinit_real (PyGICallableCache *callable_cache) +{ + g_base_info_unref (((PyGIVFuncCache *) callable_cache)->info); - if (arg_cache == NULL) - goto arg_err; + _function_cache_deinit_real (callable_cache); +} - arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); - arg_cache->allow_none = g_arg_info_may_be_null(arg_info); - arg_cache->is_caller_allocates = is_caller_allocates; +PyGIFunctionCache * +pygi_vfunc_cache_new (GICallableInfo *info) +{ + PyGIVFuncCache *vfunc_cache; + PyGIFunctionCache *function_cache; + PyGIFunctionWithInstanceCache *fwi_cache; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - callable_cache->n_to_py_args++; + vfunc_cache = g_new0 (PyGIVFuncCache, 1); + function_cache = (PyGIFunctionCache *) vfunc_cache; + fwi_cache = (PyGIFunctionWithInstanceCache *) vfunc_cache; - if (arg_cache == NULL) - goto arg_err; + ((PyGICallableCache *) vfunc_cache)->deinit = _vfunc_cache_deinit_real; - callable_cache->to_py_args = - g_slist_append (callable_cache->to_py_args, arg_cache); - } + /* This must be non-NULL for _function_cache_init() to create the + * invoker, the real address will be set in _vfunc_cache_invoke_real(). + */ + function_cache->invoker.native_address = (gpointer) 0xdeadbeef; - callable_cache->args_cache[arg_index] = arg_cache; - g_base_info_unref( (GIBaseInfo *)type_info); - g_base_info_unref( (GIBaseInfo *)arg_info); + function_cache->invoke = _vfunc_cache_invoke_real; - continue; -arg_err: - g_base_info_unref( (GIBaseInfo *)type_info); - g_base_info_unref( (GIBaseInfo *)arg_info); - return FALSE; + if (!_function_with_instance_cache_init (fwi_cache, info)) { + g_free (vfunc_cache); + return NULL; } - _arg_name_list_generate (callable_cache); + /* Required by _vfunc_cache_invoke_real() */ + vfunc_cache->info = g_base_info_ref ((GIBaseInfo *) info); - return TRUE; + return function_cache; } -PyGICallableCache * -_pygi_callable_cache_new (GICallableInfo *callable_info, gboolean is_ccallback) -{ - PyGICallableCache *cache; - GIInfoType type = g_base_info_get_type ( (GIBaseInfo *)callable_info); +/* PyGIClosureCache */ - cache = g_slice_new0 (PyGICallableCache); +PyGIClosureCache * +pygi_closure_cache_new (GICallableInfo *info) +{ + gssize i; + PyGIClosureCache *closure_cache; + PyGICallableCache *callable_cache; - if (cache == NULL) - return NULL; + closure_cache = g_new0 (PyGIClosureCache, 1); + callable_cache = (PyGICallableCache *) closure_cache; - cache->name = g_base_info_get_name ((GIBaseInfo *)callable_info); + callable_cache->calling_context = PYGI_CALLING_CONTEXT_IS_FROM_C; - if (g_base_info_is_deprecated (callable_info)) { - const gchar *deprecated = g_base_info_get_attribute (callable_info, "deprecated"); - gchar *warning; - if (deprecated != NULL) - warning = g_strdup_printf ("%s.%s is deprecated: %s", - g_base_info_get_namespace (callable_info), cache->name, - deprecated); - else - warning = g_strdup_printf ("%s.%s is deprecated", - g_base_info_get_namespace (callable_info), cache->name); - PyErr_WarnEx(PyExc_DeprecationWarning, warning, 0); - g_free (warning); + if (!_callable_cache_init (callable_cache, info)) { + g_free (closure_cache); + return NULL; } - if (type == GI_INFO_TYPE_FUNCTION) { - GIFunctionInfoFlags flags; + /* For backwards compatibility closures include the array's length. + * + * See: https://bugzilla.gnome.org/show_bug.cgi?id=652115 + */ + for (i = 0; (gsize)i < _pygi_callable_cache_args_len (callable_cache); i++) { + PyGIArgCache *arg_cache; + PyGIArgGArray *garray_cache; + PyGIArgCache *len_arg_cache; + + arg_cache = g_ptr_array_index (callable_cache->args_cache, i); + if (arg_cache->type_tag != GI_TYPE_TAG_ARRAY) + continue; - flags = g_function_info_get_flags ( (GIFunctionInfo *)callable_info); + garray_cache = (PyGIArgGArray *) arg_cache; + if (garray_cache->len_arg_index == -1) + continue; - if (flags & GI_FUNCTION_IS_CONSTRUCTOR) - cache->function_type = PYGI_FUNCTION_TYPE_CONSTRUCTOR; - else if (flags & GI_FUNCTION_IS_METHOD) - cache->function_type = PYGI_FUNCTION_TYPE_METHOD; - } else if (type == GI_INFO_TYPE_VFUNC) { - cache->function_type = PYGI_FUNCTION_TYPE_VFUNC; - } else if (type == GI_INFO_TYPE_CALLBACK) { - if (is_ccallback) - cache->function_type = PYGI_FUNCTION_TYPE_CCALLBACK; - else - cache->function_type = PYGI_FUNCTION_TYPE_CALLBACK; - } else { - cache->function_type = PYGI_FUNCTION_TYPE_METHOD; + len_arg_cache = g_ptr_array_index (callable_cache->args_cache, + garray_cache->len_arg_index); + len_arg_cache->meta_type = PYGI_META_ARG_TYPE_PARENT; } - cache->n_args = g_callable_info_get_n_args (callable_info); + /* Prevent guessing multiple user data arguments. + * This is required because some versions of GI + * do not recognize user_data/data arguments correctly. + */ + if (callable_cache->user_data_index == -1) { + for (i = 0; (gsize)i < _pygi_callable_cache_args_len (callable_cache); i++) { + PyGIArgCache *arg_cache; - /* if we are a method or vfunc make sure the instance parameter is counted */ - if (cache->function_type == PYGI_FUNCTION_TYPE_METHOD || - cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) - cache->n_args++; + arg_cache = g_ptr_array_index (callable_cache->args_cache, i); - if (cache->n_args > 0) - cache->args_cache = g_slice_alloc0 (cache->n_args * sizeof (PyGIArgCache *)); + if (arg_cache->direction == PYGI_DIRECTION_TO_PYTHON && + arg_cache->type_tag == GI_TYPE_TAG_VOID && + arg_cache->is_pointer) { - if (!_args_cache_generate (callable_info, cache)) - goto err; + callable_cache->user_data_index = i; + break; + } + } + } - return cache; -err: - _pygi_callable_cache_free (cache); - return NULL; + return closure_cache; } |