diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-07-12 08:46:30 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-07-12 08:46:33 +0900 |
commit | dca4e6423c560689ee831785473ad3ab48e7548a (patch) | |
tree | 048ddb6edb0826be8ff180c027d45acb6dac67db /gi/pygi-cache.c | |
parent | 392945d666d2cfb31a844826a72b1eb65a52546f (diff) | |
download | pygobject2-dca4e6423c560689ee831785473ad3ab48e7548a.tar.gz pygobject2-dca4e6423c560689ee831785473ad3ab48e7548a.tar.bz2 pygobject2-dca4e6423c560689ee831785473ad3ab48e7548a.zip |
Imported Upstream version 3.3.1
Change-Id: I7e59d7cf82217b545ec40115122a83ebf79763cb
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'gi/pygi-cache.c')
-rw-r--r-- | gi/pygi-cache.c | 2120 |
1 files changed, 1218 insertions, 902 deletions
diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c index 82a6182..610e35b 100644 --- a/gi/pygi-cache.c +++ b/gi/pygi-cache.c @@ -2,7 +2,6 @@ * 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 @@ -15,100 +14,37 @@ * 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, see <http://www.gnu.org/licenses/>. + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA */ -#include <Python.h> -#include <girepository.h> - -#include "pyglib.h" -#include "pygtype.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 "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; -} - -/* 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; -} +#include <girepository.h> +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 */ void -pygi_arg_cache_free (PyGIArgCache *cache) +_pygi_arg_cache_free (PyGIArgCache *cache) { if (cache == NULL) return; @@ -121,8 +57,6 @@ pygi_arg_cache_free (PyGIArgCache *cache) g_slice_free (PyGIArgCache, cache); } -/* PyGIInterfaceCache */ - static void _interface_cache_free_func (PyGIInterfaceCache *cache) { @@ -136,1050 +70,1432 @@ _interface_cache_free_func (PyGIInterfaceCache *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 (!pygi_arg_base_setup ((PyGIArgCache *)iface_cache, - type_info, - arg_info, - transfer, - direction)) { - return FALSE; +static void +_hash_cache_free_func (PyGIHashCache *cache) +{ + if (cache != NULL) { + _pygi_arg_cache_free (cache->key_cache); + _pygi_arg_cache_free (cache->value_cache); + g_slice_free (PyGIHashCache, cache); } +} - ( (PyGIArgCache *)iface_cache)->destroy_notify = (GDestroyNotify)_interface_cache_free_func; +static void +_sequence_cache_free_func (PyGISequenceCache *cache) +{ + if (cache != NULL) { + _pygi_arg_cache_free (cache->item_cache); + g_slice_free (PyGISequenceCache, cache); + } +} - 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); +static void +_callback_cache_free_func (PyGICallbackCache *cache) +{ + if (cache != NULL) { + if (cache->interface_info != NULL) + g_base_info_unref ( (GIBaseInfo *)cache->interface_info); - if (iface_cache->py_type == NULL) { - return FALSE; + g_slice_free (PyGICallbackCache, cache); } - - return TRUE; } -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) +void +_pygi_callable_cache_free (PyGICallableCache *cache) { - PyGIInterfaceCache *ic; + gssize i; - 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 == NULL) + return; + + g_slist_free (cache->to_py_args); + g_slist_free (cache->arg_name_list); + g_hash_table_destroy (cache->arg_name_hash); + + for (i = 0; i < cache->n_args; i++) { + PyGIArgCache *tmp = cache->args_cache[i]; + _pygi_arg_cache_free (tmp); } + if (cache->return_cache != NULL) + _pygi_arg_cache_free (cache->return_cache); - return (PyGIArgCache *)ic; + g_slice_free1 (cache->n_args * sizeof (PyGIArgCache *), cache->args_cache); + g_slice_free (PyGICallableCache, cache); } -/* PyGISequenceCache */ +/* cache generation */ -static void -_sequence_cache_free_func (PyGISequenceCache *cache) +static PyGIInterfaceCache * +_interface_cache_new (GIInterfaceInfo *iface_info) { - if (cache != NULL) { - pygi_arg_cache_free (cache->item_cache); - g_slice_free (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; } -/* 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) +static PyGISequenceCache * +_sequence_cache_new (GITypeInfo *type_info, + GIDirection direction, + GITransfer transfer, + gssize child_offset) { + PyGISequenceCache *sc; GITypeInfo *item_type_info; GITransfer item_transfer; - if (!pygi_arg_base_setup ((PyGIArgCache *)sc, - type_info, - arg_info, - transfer, - direction)) { - return FALSE; + sc = g_slice_new0 (PyGISequenceCache); + ( (PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_sequence_cache_free_func; + + sc->fixed_size = -1; + sc->len_arg_index = -1; + sc->is_zero_terminated = g_type_info_is_zero_terminated (type_info); + if (!sc->is_zero_terminated) { + sc->fixed_size = g_type_info_get_array_fixed_size (type_info); + if (sc->fixed_size < 0) + sc->len_arg_index = g_type_info_get_array_length (type_info); + if (sc->len_arg_index >= 0) + sc->len_arg_index += child_offset; } - 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 = pygi_arg_cache_new (item_type_info, - NULL, - item_transfer, - direction, - callable_cache, - 0, 0); + sc->item_cache = _arg_cache_new (item_type_info, + NULL, + NULL, + item_transfer, + direction, + 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); - if (sc->item_cache == NULL) { - return FALSE; + 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; } - return TRUE; + 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; + } + + g_base_info_unref( (GIBaseInfo *)key_type_info); + g_base_info_unref( (GIBaseInfo *)value_type_info); + + return hc; } -PyGIArgCache * -pygi_arg_cache_alloc (void) +static PyGICallbackCache * +_callback_cache_new (GIArgInfo *arg_info, + GIInterfaceInfo *iface_info, + gssize child_offset) { - return g_slice_new0 (PyGIArgCache); + 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; } static PyGIArgCache * -_arg_cache_new_for_interface (GIInterfaceInfo *iface_info, - GITypeInfo *type_info, - GIArgInfo *arg_info, - GITransfer transfer, - PyGIDirection direction, - PyGICallableCache *callable_cache) +_arg_cache_alloc (void) { - GIInfoType info_type; - - info_type = g_base_info_get_type ( (GIBaseInfo *)iface_info); - - 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 (); - } - - return NULL; + return g_slice_new0 (PyGIArgCache); } -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) +static void +_arg_cache_from_py_void_setup (PyGIArgCache *arg_cache) { - PyGIArgCache *arg_cache = NULL; - GITypeTag type_tag; + arg_cache->from_py_marshaller = _pygi_marshal_from_py_void; +} - type_tag = g_type_info_get_tag (type_info); +static void +_arg_cache_to_py_void_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_void; +} - 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 void +_arg_cache_from_py_boolean_setup (PyGIArgCache *arg_cache) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_boolean; +} - 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; +static void +_arg_cache_to_py_boolean_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_boolean; +} - case GI_TYPE_TAG_GLIST: - arg_cache = pygi_arg_glist_new_from_info (type_info, - arg_info, - transfer, - direction, - callable_cache); - break; +static void +_arg_cache_from_py_int8_setup (PyGIArgCache *arg_cache) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_int8; +} - case GI_TYPE_TAG_GSLIST: - arg_cache = pygi_arg_gslist_new_from_info (type_info, - arg_info, - transfer, - direction, - callable_cache); - break; +static void +_arg_cache_to_py_int8_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_int8; +} - case GI_TYPE_TAG_GHASH: - arg_cache = pygi_arg_hash_table_new_from_info (type_info, - arg_info, - transfer, - direction, - callable_cache); - break; +static void +_arg_cache_from_py_uint8_setup (PyGIArgCache *arg_cache) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_uint8; +} - 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); +static void +_arg_cache_to_py_uint8_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_uint8; +} - g_base_info_unref ( (GIBaseInfo *)interface_info); - } - break; +static void +_arg_cache_from_py_int16_setup (PyGIArgCache *arg_cache) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_int16; +} - case GI_TYPE_TAG_ERROR: - arg_cache = pygi_arg_gerror_new_from_info (type_info, - arg_info, - transfer, - direction); - break; - default: - break; - } +static void +_arg_cache_to_py_int16_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_int16; +} - if (arg_cache != NULL) { - arg_cache->py_arg_index = py_arg_index; - arg_cache->c_arg_index = c_arg_index; - } +static void +_arg_cache_from_py_uint16_setup (PyGIArgCache *arg_cache) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_uint16; +} - return arg_cache; +static void +_arg_cache_to_py_uint16_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_uint16; } -/* PyGICallableCache */ +static void +_arg_cache_from_py_int32_setup (PyGIArgCache *arg_cache) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_int32; +} -static PyGIDirection -_pygi_get_direction (PyGICallableCache *callable_cache, GIDirection gi_direction) +static void +_arg_cache_to_py_int32_setup (PyGIArgCache *arg_cache) { - /* 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; - } + arg_cache->to_py_marshaller = _pygi_marshal_to_py_int32; } -/* Generate the cache for the callable's arguments */ -static gboolean -_callable_cache_generate_args_cache_real (PyGICallableCache *callable_cache, - GICallableInfo *callable_info) +static void +_arg_cache_from_py_uint32_setup (PyGIArgCache *arg_cache) { - gssize i; - gssize 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; + arg_cache->from_py_marshaller = _pygi_marshal_from_py_uint32; +} - /* Return arguments are always considered out */ - return_direction = _pygi_get_direction (callable_cache, GI_DIRECTION_OUT); +static void +_arg_cache_to_py_uint32_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_uint32; +} - /* 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_from_py_int64_setup (PyGIArgCache *arg_cache) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_int64; +} - 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_to_py_int64_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_int64; +} - callable_cache->user_data_index = -1; +static void +_arg_cache_from_py_uint64_setup (PyGIArgCache *arg_cache) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_uint64; +} - for (i = 0, arg_index = callable_cache->args_offset; - (gsize)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_to_py_uint64_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_uint64; +} - arg_info = g_callable_info_get_arg (callable_info, i); +static void +_arg_cache_from_py_float_setup (PyGIArgCache *arg_cache) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_float; +} - /* 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_to_py_float_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_float; +} - arg_cache = pygi_arg_cache_alloc (); - _pygi_callable_cache_set_arg (callable_cache, arg_index, arg_cache); +static void +_arg_cache_from_py_double_setup (PyGIArgCache *arg_cache) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_double; +} - 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; +static void +_arg_cache_to_py_double_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_double; +} - } 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_unichar_setup (PyGIArgCache *arg_cache) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_unichar; +} - if (direction & PYGI_DIRECTION_TO_PYTHON) { - callable_cache->n_to_py_args++; - } +static void +_arg_cache_to_py_unichar_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_unichar; +} - arg_cache->type_tag = g_type_info_get_tag (type_info); +static void +_arg_cache_from_py_gtype_setup (PyGIArgCache *arg_cache) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_gtype; +} - } else { - GITransfer transfer; - gssize py_arg_index = -1; +static void +_arg_cache_to_py_gtype_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_gtype; +} - transfer = g_arg_info_get_ownership_transfer (arg_info); +static void +_arg_cache_from_py_utf8_setup (PyGIArgCache *arg_cache, + GITransfer transfer) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_utf8; + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_utf8; +} - if (direction & PYGI_DIRECTION_FROM_PYTHON) { - py_arg_index = callable_cache->n_py_args; - callable_cache->n_py_args++; - } +static void +_arg_cache_to_py_utf8_setup (PyGIArgCache *arg_cache, + GITransfer transfer) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_utf8; + arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_utf8; +} - 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_from_py_filename_setup (PyGIArgCache *arg_cache, + GITransfer transfer) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_filename; + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_utf8; +} +static void +_arg_cache_to_py_filename_setup (PyGIArgCache *arg_cache, + GITransfer transfer) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_filename; + arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_utf8; +} - if (direction & PYGI_DIRECTION_TO_PYTHON) { - callable_cache->n_to_py_args++; +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); - callable_cache->to_py_args = - g_slist_append (callable_cache->to_py_args, arg_cache); - } + arg_cache->from_py_marshaller = _pygi_marshal_from_py_array; - _pygi_callable_cache_set_arg (callable_cache, arg_index, arg_cache); - } + if (seq_cache->len_arg_index >= 0) { + PyGIArgCache *child_cache = + callable_cache->args_cache[seq_cache->len_arg_index]; - g_base_info_unref (type_info); + 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) { + return TRUE; } - /* Ensure arguments always have a name when available */ - arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); - - g_base_info_unref ( (GIBaseInfo *)arg_info); + 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; - } + child_cache->direction = direction; + child_cache->to_py_marshaller = NULL; + child_cache->from_py_marshaller = NULL; - 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->args_cache[seq_cache->len_arg_index] = child_cache; } - callable_cache->n_py_required_args = 0; - callable_cache->user_data_varargs_index = -1; - last_explicit_arg_index = -1; + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array; - /* Reverse loop through all the arguments to setup arg_name_list/hash - * and find the number of required arguments */ - for (i=((gssize)_pygi_callable_cache_args_len (callable_cache))-1; i >= 0; i--) { - PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (callable_cache, i); + return TRUE; +} - 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) { +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; - /* 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)); - } + seq_cache->array_type = g_type_info_get_array_type (type_info); - /* 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; - } + 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 (last_explicit_arg_index == -1) { - last_explicit_arg_index = i; + if (child_cache != NULL) { + callable_cache->to_py_args = + g_slist_remove (callable_cache->to_py_args, child_cache); - /* 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 (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 (); } - } - if (!return_cache->is_skipped && return_cache->type_tag != GI_TYPE_TAG_VOID) { - callable_cache->has_return = TRUE; - } + 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; - tuple_names = PyList_New (0); - if (callable_cache->has_return) { - PyList_Append (tuple_names, Py_None); + callable_cache->args_cache[seq_cache->len_arg_index] = child_cache; } - 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 = PYGLIB_PyUnicode_FromString (arg_name); - PyList_Append (tuple_names, arg_string); - Py_DECREF (arg_string); - arg_cache_item = arg_cache_item->next; - } + return TRUE; +} - /* 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); +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; +} - return TRUE; +static void +_arg_cache_to_py_glist_setup (PyGIArgCache *arg_cache, + GITransfer transfer) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_glist; + arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist; } static void -_callable_cache_deinit_real (PyGICallableCache *cache) +_arg_cache_from_py_gslist_setup (PyGIArgCache *arg_cache, + GITransfer transfer) { - 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); + arg_cache->from_py_marshaller = _pygi_marshal_from_py_gslist; + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist; +} - g_clear_pointer (&cache->return_cache, pygi_arg_cache_free); +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; } -static gboolean -_callable_cache_init (PyGICallableCache *cache, - GICallableInfo *callable_info) +static void +_arg_cache_from_py_ghash_setup (PyGIArgCache *arg_cache) { - gint n_args; - GIBaseInfo *container; + arg_cache->from_py_marshaller = _pygi_marshal_from_py_ghash; + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_ghash; +} - if (cache->deinit == NULL) - cache->deinit = _callable_cache_deinit_real; +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; +} - if (cache->generate_args_cache == NULL) - cache->generate_args_cache = _callable_cache_generate_args_cache_real; +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; +} - 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); - - 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); - } +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; +} - n_args = cache->args_offset + g_callable_info_get_n_args (callable_info); +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; +} - 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); - } +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; +} - if (!cache->generate_args_cache (cache, callable_info)) { - _callable_cache_deinit_real (cache); - return FALSE; - } +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; + + 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; +} - return TRUE; +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; + + if (iface_cache->is_foreign) + arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_struct_foreign; } -gchar * -pygi_callable_cache_get_full_name (PyGICallableCache *cache) +static void +_arg_cache_from_py_interface_object_setup (PyGIArgCache *arg_cache, + GITransfer transfer) { - 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); + arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_object; + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_object; +} + +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; + arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_object; +} + +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; + } + + 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; } -void -pygi_callable_cache_free (PyGICallableCache *cache) +static void +_arg_cache_to_py_interface_callback_setup (void) { - cache->deinit (cache); - g_free (cache); + PyErr_Format(PyExc_NotImplementedError, + "Callback returns are not supported"); } -/* PyGIFunctionCache */ +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; +} -static PyObject * -_function_cache_invoke_real (PyGIFunctionCache *function_cache, - PyGIInvokeState *state, - PyObject *py_args, - PyObject *py_kwargs) +static void +_arg_cache_to_py_interface_enum_setup (PyGIArgCache *arg_cache, + GITransfer transfer) { - return pygi_invoke_c_callable (function_cache, state, - py_args, py_kwargs); + arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_enum; } static void -_function_cache_deinit_real (PyGICallableCache *callable_cache) +_arg_cache_from_py_interface_flags_setup (PyGIArgCache *arg_cache, + GITransfer transfer) { - g_function_invoker_destroy (&((PyGIFunctionCache *) callable_cache)->invoker); + arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_flags; +} - _callable_cache_deinit_real (callable_cache); +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; } -static gboolean -_function_cache_init (PyGIFunctionCache *function_cache, - GICallableInfo *callable_info) +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) { - PyGICallableCache *callable_cache = (PyGICallableCache *) function_cache; - GIFunctionInvoker *invoker = &function_cache->invoker; - GError *error = NULL; + PyGIInterfaceCache *iface_cache = NULL; + PyGIArgCache *arg_cache = NULL; + gssize child_offset = 0; + GIInfoType info_type; - callable_cache->calling_context = PYGI_CALLING_CONTEXT_IS_FROM_PY; + if (callable_cache != NULL) + child_offset = + (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD || + callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0; - if (callable_cache->deinit == NULL) - callable_cache->deinit = _function_cache_deinit_real; + info_type = g_base_info_get_type ( (GIBaseInfo *)iface_info); - if (function_cache->invoke == NULL) - function_cache->invoke = _function_cache_invoke_real; + /* Callbacks are special cased */ + if (info_type != GI_INFO_TYPE_CALLBACK) { + iface_cache = _interface_cache_new (iface_info); - if (!_callable_cache_init (callable_cache, callable_info)) - return FALSE; + arg_cache = (PyGIArgCache *)iface_cache; + if (arg_cache == NULL) + return NULL; + } - /* 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; - } + 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_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_BOXED: + 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_CALLBACK: + { + PyGICallbackCache *callback_cache; + + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { + _arg_cache_to_py_interface_callback_setup (); + return NULL; + } + + callback_cache = + _callback_cache_new (arg_info, + iface_info, + child_offset); + + arg_cache = (PyGIArgCache *)callback_cache; + if (arg_cache == NULL) + return NULL; + + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_interface_callback_setup (arg_cache, callable_cache); + + break; + } + 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); + + 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 (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_interface_flags_setup (arg_cache, transfer); + + break; + default: + g_assert_not_reached (); } - if (!pygi_error_check (&error)) { - PyErr_Format (PyExc_RuntimeError, - "unknown error creating invoker for %s", - g_base_info_get_name ((GIBaseInfo *) callable_info)); + 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; + + if (iface_cache != NULL) { + g_base_info_ref ( (GIBaseInfo *)iface_info); + iface_cache->interface_info = iface_info; + } } - _callable_cache_deinit_real (callable_cache); - return FALSE; + return arg_cache; } -PyGIFunctionCache * -pygi_function_cache_new (GICallableInfo *info) +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) { - PyGIFunctionCache *function_cache; + PyGIArgCache *arg_cache = NULL; + gssize child_offset = 0; + GITypeTag type_tag; - function_cache = g_new0 (PyGIFunctionCache, 1); + type_tag = g_type_info_get_tag (type_info); - if (!_function_cache_init (function_cache, info)) { - g_free (function_cache); - return NULL; - } + if (callable_cache != NULL) + child_offset = + (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD || + callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0; - return function_cache; -} + switch (type_tag) { + case GI_TYPE_TAG_VOID: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; -PyObject * -pygi_function_cache_invoke (PyGIFunctionCache *function_cache, - PyObject *py_args, - PyObject *py_kwargs) -{ - PyGIInvokeState state = { 0, }; + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_void_setup (arg_cache); - return function_cache->invoke (function_cache, &state, - py_args, py_kwargs); -} + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_void_setup (arg_cache); -/* PyGICCallbackCache */ + break; + case GI_TYPE_TAG_BOOLEAN: + 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_boolean_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_boolean_setup (arg_cache); - function_cache->invoker.native_address = function_ptr; + break; + case GI_TYPE_TAG_INT8: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; - if (!_function_cache_init (function_cache, info)) { - g_free (ccallback_cache); - return NULL; - } + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_int8_setup (arg_cache); - return function_cache; -} + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_int8_setup (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, }; + break; + case GI_TYPE_TAG_UINT8: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; - state.user_data = user_data; + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_uint8_setup (arg_cache); - return function_cache->invoke (function_cache, &state, - py_args, py_kwargs); -} + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_uint8_setup (arg_cache); -/* PyGIConstructorCache */ + break; + case GI_TYPE_TAG_INT16: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; -static PyObject * -_constructor_cache_invoke_real (PyGIFunctionCache *function_cache, - PyGIInvokeState *state, - PyObject *py_args, - PyObject *py_kwargs) -{ - PyGICallableCache *cache = (PyGICallableCache *) function_cache; - PyObject *constructor_class; - PyObject *ret; + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_int16_setup (arg_cache); - 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 (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_int16_setup (arg_cache); - return FALSE; - } + break; + case GI_TYPE_TAG_UINT16: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; - 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) + _arg_cache_from_py_uint16_setup (arg_cache); - if (ret == NULL || cache->return_cache->is_skipped) - return ret; + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_uint16_setup (arg_cache); + break; + case GI_TYPE_TAG_INT32: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; - if (ret != Py_None) { - if (!PyTuple_Check (ret)) - return ret; + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_int32_setup (arg_cache); - if (PyTuple_GET_ITEM (ret, 0) != Py_None) - return ret; - } + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_int32_setup (arg_cache); - PyErr_SetString (PyExc_TypeError, "constructor returned NULL"); + break; + case GI_TYPE_TAG_UINT32: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; - Py_DECREF (ret); - return NULL; -} + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_uint32_setup (arg_cache); -PyGIFunctionCache * -pygi_constructor_cache_new (GICallableInfo *info) -{ - PyGIConstructorCache *constructor_cache; - PyGIFunctionCache *function_cache; + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_uint32_setup (arg_cache); - constructor_cache = g_new0 (PyGIConstructorCache, 1); - function_cache = (PyGIFunctionCache *) constructor_cache; + break; + case GI_TYPE_TAG_INT64: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; - function_cache->invoke = _constructor_cache_invoke_real; + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_int64_setup (arg_cache); - if (!_function_cache_init (function_cache, info)) { - g_free (constructor_cache); - return NULL; - } + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_int64_setup (arg_cache); - return function_cache; -} + break; + case GI_TYPE_TAG_UINT64: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; -/* PyGIFunctionWithInstanceCache */ + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_uint64_setup (arg_cache); -static gboolean -_function_with_instance_cache_generate_args_cache_real (PyGICallableCache *callable_cache, - GICallableInfo *callable_info) -{ - GIInterfaceInfo *interface_info; - PyGIArgCache *instance_cache; - GITransfer transfer; + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_uint64_setup (arg_cache); - interface_info = g_base_info_get_container ((GIBaseInfo *) callable_info); - transfer = g_callable_info_get_instance_ownership_transfer (callable_info); + break; + case GI_TYPE_TAG_FLOAT: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; - instance_cache = - _arg_cache_new_for_interface (interface_info, - NULL, - NULL, - transfer, - PYGI_DIRECTION_FROM_PYTHON, - callable_cache); + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_float_setup (arg_cache); - if (instance_cache == NULL) - return FALSE; + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_float_setup (arg_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; + break; + case GI_TYPE_TAG_DOUBLE: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; - _pygi_callable_cache_set_arg (callable_cache, 0, instance_cache); + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_double_setup (arg_cache); - callable_cache->n_py_args++; + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_double_setup (arg_cache); - return _callable_cache_generate_args_cache_real (callable_cache, - callable_info); -} + break; + case GI_TYPE_TAG_UNICHAR: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; -static gboolean -_function_with_instance_cache_init (PyGIFunctionWithInstanceCache *fwi_cache, - GICallableInfo *info) -{ - PyGICallableCache *callable_cache = (PyGICallableCache *) fwi_cache; + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_unichar_setup (arg_cache); - callable_cache->args_offset += 1; - callable_cache->generate_args_cache = _function_with_instance_cache_generate_args_cache_real; + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_unichar_setup (arg_cache); - return _function_cache_init ((PyGIFunctionCache *) fwi_cache, info); -} + break; + case GI_TYPE_TAG_GTYPE: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; -/* PyGIMethodCache */ + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_gtype_setup (arg_cache); -PyGIFunctionCache * -pygi_method_cache_new (GICallableInfo *info) -{ - PyGIMethodCache *method_cache; - PyGIFunctionWithInstanceCache *fwi_cache; + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_gtype_setup (arg_cache); - method_cache = g_new0 (PyGIMethodCache, 1); - fwi_cache = (PyGIFunctionWithInstanceCache *) method_cache; + break; + case GI_TYPE_TAG_UTF8: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; - if (!_function_with_instance_cache_init (fwi_cache, info)) { - g_free (method_cache); - return NULL; - } + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_utf8_setup (arg_cache, transfer); - return (PyGIFunctionCache *) method_cache; -} + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_utf8_setup (arg_cache, transfer); -/* PyGIVFuncCache */ + break; + case GI_TYPE_TAG_FILENAME: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; -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; + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_filename_setup (arg_cache, transfer); - 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) + _arg_cache_to_py_filename_setup (arg_cache, transfer); - implementor_gtype = pyg_type_from_object (py_gtype); - if (implementor_gtype == G_TYPE_INVALID) - return FALSE; + break; + case GI_TYPE_TAG_ARRAY: + { + PyGISequenceCache *seq_cache = + _sequence_cache_new (type_info, + direction, + transfer, + child_offset); - /* 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; + arg_cache = (PyGIArgCache *)seq_cache; + if (arg_cache == NULL) + break; + + 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); + + 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); + + arg_cache = (PyGIArgCache *)seq_cache; + if (arg_cache == NULL) + break; + + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_glist_setup (arg_cache, transfer); + + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_glist_setup (arg_cache, transfer); + + + break; + } + case GI_TYPE_TAG_GSLIST: + { + PyGISequenceCache *seq_cache = + _sequence_cache_new (type_info, + direction, + transfer, + child_offset); + + arg_cache = (PyGIArgCache *)seq_cache; + if (arg_cache == NULL) + break; + + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_gslist_setup (arg_cache, transfer); + + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_gslist_setup (arg_cache, transfer); + + break; + } + case GI_TYPE_TAG_GHASH: + arg_cache = + (PyGIArgCache *)_hash_cache_new (type_info, + direction, + transfer); + + if (arg_cache == NULL) + break; + + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_ghash_setup (arg_cache); + + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { + _arg_cache_to_py_ghash_setup (arg_cache); + } + + 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); + + g_base_info_unref ( (GIBaseInfo *)interface_info); + break; + } + case GI_TYPE_TAG_ERROR: + arg_cache = _arg_cache_alloc (); + if (arg_cache == NULL) + break; + + if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_from_py_gerror_setup (arg_cache); + + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) + _arg_cache_to_py_gerror_setup (arg_cache); + + break; } - 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 (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 ret; + return arg_cache; } static void -_vfunc_cache_deinit_real (PyGICallableCache *callable_cache) +_arg_name_list_generate (PyGICallableCache *callable_cache) { - g_base_info_unref (((PyGIVFuncCache *) callable_cache)->info); + GSList * arg_name_list = NULL; + int i; + + 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); + } + + for (i=0; i < callable_cache->n_args; i++) { + PyGIArgCache *arg_cache = NULL; + + arg_cache = callable_cache->args_cache[i]; + + 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; + + 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); + } + } + } - _function_cache_deinit_real (callable_cache); + callable_cache->arg_name_list = g_slist_reverse (arg_name_list); } -PyGIFunctionCache * -pygi_vfunc_cache_new (GICallableInfo *info) +/* Generate the cache for the callable's arguments */ +static gboolean +_args_cache_generate (GICallableInfo *callable_info, + PyGICallableCache *callable_cache) { - PyGIVFuncCache *vfunc_cache; - PyGIFunctionCache *function_cache; - PyGIFunctionWithInstanceCache *fwi_cache; + gssize arg_index = 0; + gssize i; + GITypeInfo *return_info; + GITransfer return_transfer; + PyGIArgCache *return_cache; + PyGIDirection return_direction; - vfunc_cache = g_new0 (PyGIVFuncCache, 1); - function_cache = (PyGIFunctionCache *) vfunc_cache; - fwi_cache = (PyGIFunctionWithInstanceCache *) vfunc_cache; + /* 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; - ((PyGICallableCache *) vfunc_cache)->deinit = _vfunc_cache_deinit_real; + /* 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); - /* 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; + 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 = _vfunc_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_with_instance_cache_init (fwi_cache, info)) { - g_free (vfunc_cache); - return NULL; - } + instance_direction = PYGI_DIRECTION_FROM_PYTHON; - /* Required by _vfunc_cache_invoke_real() */ - vfunc_cache->info = g_base_info_ref ((GIBaseInfo *) info); - return function_cache; -} + interface_info = g_base_info_get_container ( (GIBaseInfo *)callable_info); -/* PyGIClosureCache */ + instance_cache = + _arg_cache_new_for_interface (interface_info, + callable_cache, + NULL, + GI_TRANSFER_NOTHING, + instance_direction, + arg_index, + 0); -PyGIClosureCache * -pygi_closure_cache_new (GICallableInfo *info) -{ - gssize i; - PyGIClosureCache *closure_cache; - PyGICallableCache *callable_cache; + /* FIXME: marshal interfaces from_py */ + instance_cache->from_py_marshaller = _pygi_marshal_from_py_interface_instance; + g_base_info_unref ( (GIBaseInfo *)interface_info); - closure_cache = g_new0 (PyGIClosureCache, 1); - callable_cache = (PyGICallableCache *) closure_cache; + if (instance_cache == NULL) + return FALSE; - callable_cache->calling_context = PYGI_CALLING_CONTEXT_IS_FROM_C; + callable_cache->args_cache[arg_index] = instance_cache; - if (!_callable_cache_init (callable_cache, info)) { - g_free (closure_cache); - return NULL; + arg_index++; + callable_cache->n_from_py_args++; + callable_cache->n_py_args++; } - /* 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) + + 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; + + arg_info = g_callable_info_get_arg (callable_info, i); + + if (g_arg_info_get_closure (arg_info) == i) { + + arg_cache = _arg_cache_alloc (); + callable_cache->args_cache[arg_index] = arg_cache; + + 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; + + callable_cache->n_from_py_args++; + + g_base_info_unref ( (GIBaseInfo *)arg_info); + continue; + } - garray_cache = (PyGIArgGArray *) arg_cache; - if (garray_cache->len_arg_index == -1) + /* 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; + } + + 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) + 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++; + } + + 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++; + } + + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { + callable_cache->n_to_py_args++; + callable_cache->n_to_py_child_args++; + } + + g_base_info_unref ( (GIBaseInfo *)arg_info); continue; + } - 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; - } + 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++; + } - /* 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; + arg_cache = + _arg_cache_new (type_info, + callable_cache, + arg_info, + transfer, + direction, + arg_index, + py_arg_index); - arg_cache = g_ptr_array_index (callable_cache->args_cache, i); + if (arg_cache == NULL) + goto arg_err; - if (arg_cache->direction == PYGI_DIRECTION_TO_PYTHON && - arg_cache->type_tag == GI_TYPE_TAG_VOID && - arg_cache->is_pointer) { + 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; - callable_cache->user_data_index = i; - break; - } + if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { + callable_cache->n_to_py_args++; + + if (arg_cache == NULL) + goto arg_err; + + callable_cache->to_py_args = + g_slist_append (callable_cache->to_py_args, arg_cache); } + + callable_cache->args_cache[arg_index] = arg_cache; + g_base_info_unref( (GIBaseInfo *)type_info); + g_base_info_unref( (GIBaseInfo *)arg_info); + + continue; +arg_err: + g_base_info_unref( (GIBaseInfo *)type_info); + g_base_info_unref( (GIBaseInfo *)arg_info); + return FALSE; + } + + _arg_name_list_generate (callable_cache); + + return TRUE; +} + +PyGICallableCache * +_pygi_callable_cache_new (GICallableInfo *callable_info, gboolean is_ccallback) +{ + PyGICallableCache *cache; + GIInfoType type = g_base_info_get_type ( (GIBaseInfo *)callable_info); + + cache = g_slice_new0 (PyGICallableCache); + + if (cache == NULL) + return NULL; + + cache->name = g_base_info_get_name ((GIBaseInfo *)callable_info); + + if (type == GI_INFO_TYPE_FUNCTION) { + GIFunctionInfoFlags flags; + + flags = g_function_info_get_flags ( (GIFunctionInfo *)callable_info); + + 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; } - return closure_cache; + cache->n_args = g_callable_info_get_n_args (callable_info); + + /* 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++; + + if (cache->n_args > 0) + cache->args_cache = g_slice_alloc0 (cache->n_args * sizeof (PyGIArgCache *)); + + if (!_args_cache_generate (callable_info, cache)) + goto err; + + return cache; +err: + _pygi_callable_cache_free (cache); + return NULL; } |