summaryrefslogtreecommitdiff
path: root/gi/pygi-cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'gi/pygi-cache.c')
-rw-r--r--gi/pygi-cache.c1867
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;
}