diff options
author | Benjamin Berg <bberg@redhat.com> | 2020-11-13 00:26:53 +0100 |
---|---|---|
committer | Benjamin Berg <bberg@redhat.com> | 2021-07-13 01:06:43 +0200 |
commit | 7edb9032bb0898e921559e43630c8ea8b9ac14ac (patch) | |
tree | d6cb74e50140e4b6235a6a5722f65ae16d724b8a | |
parent | 8883c69b1afc66e03e311a2fa61d49271cae3950 (diff) | |
download | pygobject-wip/gio-async-awaitable-return.tar.gz |
invoke: Create async helper when needed and marshal it for callbackswip/gio-async-awaitable-return
Note that a cancellable will implicitly be created so that the awaitable
can be cancelled. If a cancellable is given, then this cancellable will
be used instead.
-rw-r--r-- | gi/pygi-invoke.c | 51 |
1 files changed, 48 insertions, 3 deletions
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c index 4239f255..e4570469 100644 --- a/gi/pygi-invoke.c +++ b/gi/pygi-invoke.c @@ -409,10 +409,28 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGIFunctionCache *function_cac return FALSE; } + if (function_cache->async_finish && function_cache->async_callback && + function_cache->async_callback->py_arg_index < state->n_py_in_args && + PyTuple_GET_ITEM (state->py_in_args, function_cache->async_callback->py_arg_index) == _PyGIDefaultArgPlaceholder) { + + /* We are dealing with an async call that returns an awaitable */ + PyObject *cancellable = NULL; + + /* Try to resolve any passed GCancellable. */ + if (function_cache->async_cancellable && function_cache->async_cancellable->py_arg_index < state->n_py_in_args) + cancellable = PyTuple_GET_ITEM (state->py_in_args, function_cache->async_cancellable->py_arg_index); + + if (cancellable == _PyGIDefaultArgPlaceholder) + cancellable = NULL; + + state->py_async = pygi_async_new (function_cache->async_finish, cancellable); + } + for (i = 0; (gsize)i < _pygi_callable_cache_args_len (cache); i++) { GIArgument *c_arg = &state->args[i].arg_value; PyGIArgCache *arg_cache = g_ptr_array_index (cache->args_cache, i); PyObject *py_arg = NULL; + gboolean marshal = TRUE; switch (arg_cache->direction) { case PYGI_DIRECTION_FROM_PYTHON: @@ -512,9 +530,25 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGIFunctionCache *function_cac } if (py_arg == _PyGIDefaultArgPlaceholder) { - *c_arg = arg_cache->default_value; - } else if (arg_cache->from_py_marshaller != NULL && - arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD) { + /* If this is the cancellable, then we may override it later if we + * detect an async call. + */ + marshal = FALSE; + + if (state->py_async && arg_cache->async_context == PYGI_ASYNC_CONTEXT_CANCELLABLE) { + marshal = TRUE; + py_arg = ((PyGIAsync*) state->py_async)->cancellable; + } else if (state->py_async && arg_cache->async_context == PYGI_ASYNC_CONTEXT_CALLBACK) { + marshal = TRUE; + } else { + *c_arg = arg_cache->default_value; + } + } + + if (marshal && + arg_cache->from_py_marshaller != NULL && + arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD) { + gboolean success; gpointer cleanup_data = NULL; @@ -587,6 +621,17 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGIFunctionCache *function_ca } } + /* Return the async future if we have one. */ + if (state->py_async) { + /* We must have no return value */ + g_assert (n_out_args == 0); + g_assert (cache->return_cache->is_skipped || cache->return_cache->type_tag == GI_TYPE_TAG_VOID); + + Py_DECREF(py_return); + Py_INCREF(state->py_async); + return state->py_async; + } + if (n_out_args == 0) { if (cache->return_cache->is_skipped && state->error == NULL) { /* we skip the return value and have no (out) arguments to return, |