/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri * Copyright (C) 2013 Simon Feltman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 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 . */ #include #include #include "pygi-type.h" #include "pygi-info.h" #include "pygi-cache.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; } void pygi_arg_cache_free (PyGIArgCache *cache) { if (cache == NULL) return; if (cache->type_info != NULL) g_base_info_unref ( (GIBaseInfo *)cache->type_info); if (cache->destroy_notify) cache->destroy_notify (cache); else g_slice_free (PyGIArgCache, cache); } /* PyGIInterfaceCache */ static void _interface_cache_free_func (PyGIInterfaceCache *cache) { if (cache != NULL) { Py_XDECREF (cache->py_type); if (cache->type_name != NULL) g_free (cache->type_name); if (cache->interface_info != NULL) g_base_info_unref ( (GIBaseInfo *)cache->interface_info); g_slice_free (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; } ( (PyGIArgCache *)iface_cache)->destroy_notify = (GDestroyNotify)_interface_cache_free_func; 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); if (iface_cache->py_type == NULL) { return FALSE; } 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) { PyGIInterfaceCache *ic; 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; } return (PyGIArgCache *)ic; } /* PyGISequenceCache */ static void _sequence_cache_free_func (PyGISequenceCache *cache) { if (cache != NULL) { pygi_arg_cache_free (cache->item_cache); g_slice_free (PyGISequenceCache, cache); } } /* 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) { GITypeInfo *item_type_info; GITransfer item_transfer; 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 = pygi_arg_cache_new (item_type_info, NULL, item_transfer, direction, callable_cache, 0, 0); g_base_info_unref ( (GIBaseInfo *)item_type_info); if (sc->item_cache == NULL) { return FALSE; } return TRUE; } PyGIArgCache * pygi_arg_cache_alloc (void) { return g_slice_new0 (PyGIArgCache); } static PyGIArgCache * _arg_cache_new_for_interface (GIInterfaceInfo *iface_info, GITypeInfo *type_info, GIArgInfo *arg_info, GITransfer transfer, PyGIDirection direction, PyGICallableCache *callable_cache) { 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; } 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) { PyGIArgCache *arg_cache = NULL; GITypeTag type_tag; type_tag = g_type_info_get_tag (type_info); 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; 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; case GI_TYPE_TAG_GLIST: arg_cache = pygi_arg_glist_new_from_info (type_info, arg_info, transfer, direction, callable_cache); break; case GI_TYPE_TAG_GSLIST: arg_cache = pygi_arg_gslist_new_from_info (type_info, arg_info, transfer, direction, callable_cache); break; case GI_TYPE_TAG_GHASH: arg_cache = pygi_arg_hash_table_new_from_info (type_info, arg_info, transfer, direction, callable_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, type_info, arg_info, transfer, direction, callable_cache); g_base_info_unref ( (GIBaseInfo *)interface_info); } break; case GI_TYPE_TAG_ERROR: arg_cache = pygi_arg_gerror_new_from_info (type_info, arg_info, transfer, direction); break; default: break; } if (arg_cache != NULL) { arg_cache->py_arg_index = py_arg_index; arg_cache->c_arg_index = c_arg_index; } return arg_cache; } /* PyGICallableCache */ static PyGIDirection _pygi_get_direction (PyGICallableCache *callable_cache, GIDirection gi_direction) { /* 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; } } /* Generate the cache for the callable's arguments */ static gboolean _callable_cache_generate_args_cache_real (PyGICallableCache *callable_cache, GICallableInfo *callable_info) { 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; /* Return arguments are always considered out */ return_direction = _pygi_get_direction (callable_cache, GI_DIRECTION_OUT); /* 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; return_cache->is_skipped = g_callable_info_skip_return (callable_info); callable_cache->return_cache = return_cache; g_base_info_unref (return_info); callable_cache->user_data_index = -1; 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; arg_info = g_callable_info_get_arg (callable_info, i); /* This only happens when dealing with callbacks */ if (g_arg_info_get_closure (arg_info) == i) { callable_cache->user_data_index = i; arg_cache = pygi_arg_cache_alloc (); _pygi_callable_cache_set_arg (callable_cache, arg_index, arg_cache); 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; } 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++; } if (direction & PYGI_DIRECTION_TO_PYTHON) { callable_cache->n_to_py_args++; } arg_cache->type_tag = g_type_info_get_tag (type_info); } else { GITransfer transfer; gssize py_arg_index = -1; transfer = g_arg_info_get_ownership_transfer (arg_info); if (direction & PYGI_DIRECTION_FROM_PYTHON) { py_arg_index = callable_cache->n_py_args; callable_cache->n_py_args++; } 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; } if (direction & PYGI_DIRECTION_TO_PYTHON) { callable_cache->n_to_py_args++; callable_cache->to_py_args = g_slist_append (callable_cache->to_py_args, arg_cache); } _pygi_callable_cache_set_arg (callable_cache, arg_index, arg_cache); } g_base_info_unref (type_info); } /* 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 (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; last_explicit_arg_index = -1; /* 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); 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) { /* 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)); } /* 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 (last_explicit_arg_index == -1) { last_explicit_arg_index = i; /* 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 (!return_cache->is_skipped && return_cache->type_tag != GI_TYPE_TAG_VOID) { callable_cache->has_return = TRUE; } tuple_names = PyList_New (0); if (callable_cache->has_return) { PyList_Append (tuple_names, Py_None); } 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; } /* 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 TRUE; } static void _callable_cache_deinit_real (PyGICallableCache *cache) { 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); g_clear_pointer (&cache->return_cache, pygi_arg_cache_free); } 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); 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); } n_args = (gint)cache->args_offset + g_callable_info_get_n_args (callable_info); 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); } if (!cache->generate_args_cache (cache, callable_info)) { _callable_cache_deinit_real (cache); return FALSE; } return TRUE; } 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); } } void pygi_callable_cache_free (PyGICallableCache *cache) { cache->deinit (cache); g_free (cache); } /* PyGIFunctionCache */ 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); } static void _function_cache_deinit_real (PyGICallableCache *callable_cache) { g_function_invoker_destroy (&((PyGIFunctionCache *) callable_cache)->invoker); _callable_cache_deinit_real (callable_cache); } 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; callable_cache->calling_context = PYGI_CALLING_CONTEXT_IS_FROM_PY; if (callable_cache->deinit == NULL) callable_cache->deinit = _function_cache_deinit_real; if (function_cache->invoke == NULL) function_cache->invoke = _function_cache_invoke_real; 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; } } if (!pygi_error_check (&error)) { PyErr_Format (PyExc_RuntimeError, "unknown error creating invoker for %s", g_base_info_get_name ((GIBaseInfo *) callable_info)); } _callable_cache_deinit_real (callable_cache); return FALSE; } PyGIFunctionCache * pygi_function_cache_new (GICallableInfo *info) { PyGIFunctionCache *function_cache; function_cache = g_new0 (PyGIFunctionCache, 1); if (!_function_cache_init (function_cache, info)) { g_free (function_cache); return NULL; } return function_cache; } PyObject * pygi_function_cache_invoke (PyGIFunctionCache *function_cache, PyObject *py_args, PyObject *py_kwargs) { PyGIInvokeState state = { 0, }; return function_cache->invoke (function_cache, &state, py_args, py_kwargs); } /* PyGICCallbackCache */ PyGIFunctionCache * pygi_ccallback_cache_new (GICallableInfo *info, GCallback function_ptr) { PyGICCallbackCache *ccallback_cache; PyGIFunctionCache *function_cache; ccallback_cache = g_new0 (PyGICCallbackCache, 1); function_cache = (PyGIFunctionCache *) ccallback_cache; function_cache->invoker.native_address = function_ptr; if (!_function_cache_init (function_cache, info)) { g_free (ccallback_cache); return NULL; } return function_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); } /* PyGIConstructorCache */ 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; 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); return FALSE; } 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 (ret == NULL || cache->return_cache->is_skipped) return ret; if (ret != Py_None) { if (!PyTuple_Check (ret)) return ret; if (PyTuple_GET_ITEM (ret, 0) != Py_None) return ret; } PyErr_SetString (PyExc_TypeError, "constructor returned NULL"); Py_DECREF (ret); return NULL; } PyGIFunctionCache * pygi_constructor_cache_new (GICallableInfo *info) { PyGIConstructorCache *constructor_cache; PyGIFunctionCache *function_cache; constructor_cache = g_new0 (PyGIConstructorCache, 1); function_cache = (PyGIFunctionCache *) constructor_cache; function_cache->invoke = _constructor_cache_invoke_real; if (!_function_cache_init (function_cache, info)) { g_free (constructor_cache); return NULL; } return function_cache; } /* PyGIFunctionWithInstanceCache */ static gboolean _function_with_instance_cache_generate_args_cache_real (PyGICallableCache *callable_cache, GICallableInfo *callable_info) { GIInterfaceInfo *interface_info; PyGIArgCache *instance_cache; GITransfer transfer; interface_info = g_base_info_get_container ((GIBaseInfo *) callable_info); transfer = g_callable_info_get_instance_ownership_transfer (callable_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; /* 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; _pygi_callable_cache_set_arg (callable_cache, 0, instance_cache); callable_cache->n_py_args++; return _callable_cache_generate_args_cache_real (callable_cache, callable_info); } static gboolean _function_with_instance_cache_init (PyGIFunctionWithInstanceCache *fwi_cache, GICallableInfo *info) { PyGICallableCache *callable_cache = (PyGICallableCache *) fwi_cache; callable_cache->args_offset += 1; callable_cache->generate_args_cache = _function_with_instance_cache_generate_args_cache_real; return _function_cache_init ((PyGIFunctionCache *) fwi_cache, info); } /* PyGIMethodCache */ PyGIFunctionCache * pygi_method_cache_new (GICallableInfo *info) { PyGIMethodCache *method_cache; PyGIFunctionWithInstanceCache *fwi_cache; method_cache = g_new0 (PyGIMethodCache, 1); fwi_cache = (PyGIFunctionWithInstanceCache *) method_cache; if (!_function_with_instance_cache_init (fwi_cache, info)) { g_free (method_cache); return NULL; } return (PyGIFunctionCache *) method_cache; } /* PyGIVFuncCache */ 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; } implementor_gtype = pyg_type_from_object (py_gtype); if (implementor_gtype == G_TYPE_INVALID) return FALSE; /* 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; } 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); return ret; } static void _vfunc_cache_deinit_real (PyGICallableCache *callable_cache) { g_base_info_unref (((PyGIVFuncCache *) callable_cache)->info); _function_cache_deinit_real (callable_cache); } PyGIFunctionCache * pygi_vfunc_cache_new (GICallableInfo *info) { PyGIVFuncCache *vfunc_cache; PyGIFunctionCache *function_cache; PyGIFunctionWithInstanceCache *fwi_cache; vfunc_cache = g_new0 (PyGIVFuncCache, 1); function_cache = (PyGIFunctionCache *) vfunc_cache; fwi_cache = (PyGIFunctionWithInstanceCache *) vfunc_cache; ((PyGICallableCache *) vfunc_cache)->deinit = _vfunc_cache_deinit_real; /* 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; function_cache->invoke = _vfunc_cache_invoke_real; if (!_function_with_instance_cache_init (fwi_cache, info)) { g_free (vfunc_cache); return NULL; } /* Required by _vfunc_cache_invoke_real() */ vfunc_cache->info = g_base_info_ref ((GIBaseInfo *) info); return function_cache; } /* PyGIClosureCache */ PyGIClosureCache * pygi_closure_cache_new (GICallableInfo *info) { gssize i; PyGIClosureCache *closure_cache; PyGICallableCache *callable_cache; closure_cache = g_new0 (PyGIClosureCache, 1); callable_cache = (PyGICallableCache *) closure_cache; callable_cache->calling_context = PYGI_CALLING_CONTEXT_IS_FROM_C; if (!_callable_cache_init (callable_cache, info)) { g_free (closure_cache); return NULL; } /* 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; garray_cache = (PyGIArgGArray *) arg_cache; if (garray_cache->len_arg_index == -1) 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; } /* 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 = g_ptr_array_index (callable_cache->args_cache, i); if (arg_cache->direction == PYGI_DIRECTION_TO_PYTHON && arg_cache->type_tag == GI_TYPE_TAG_VOID && arg_cache->is_pointer) { callable_cache->user_data_index = i; break; } } } return closure_cache; }