[pygobject/wip/gio-async-awaitable-return: 1/4] async: Add a new async type that is an awaitable for a _finnish call
- From: Benjamin Berg <bberg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygobject/wip/gio-async-awaitable-return: 1/4] async: Add a new async type that is an awaitable for a _finnish call
- Date: Thu, 12 Nov 2020 23:40:46 +0000 (UTC)
commit a2fa286ffbb35edd3e4fb6861227d07892fc066e
Author: Benjamin Berg <bberg redhat com>
Date: Fri Nov 13 00:19:47 2020 +0100
async: Add a new async type that is an awaitable for a _finnish call
gi/gimodule.c | 3 +
gi/meson.build | 1 +
gi/pygi-async.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gi/pygi-async.h | 60 +++++++++++++++
4 files changed, 289 insertions(+)
---
diff --git a/gi/gimodule.c b/gi/gimodule.c
index 0901e738..8eb5cc35 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -34,6 +34,7 @@
#include "pygi-error.h"
#include "pygi-foreign.h"
#include "pygi-resulttuple.h"
+#include "pygi-async.h"
#include "pygi-source.h"
#include "pygi-ccallback.h"
#include "pygi-closure.h"
@@ -2557,6 +2558,8 @@ PYGI_MODINIT_FUNC PyInit__gi(void) {
return NULL;
if (pygi_resulttuple_register_types (module) < 0)
return NULL;
+ if (pygi_async_register_types (module) < 0)
+ return NULL;
if (pygi_spawn_register_types (module_dict) < 0)
return NULL;
diff --git a/gi/meson.build b/gi/meson.build
index 8edf8328..7eb3311e 100644
--- a/gi/meson.build
+++ b/gi/meson.build
@@ -17,6 +17,7 @@ sources = [
'pygi-source.c',
'pygi-argument.c',
'pygi-resulttuple.c',
+ 'pygi-async.c',
'pygi-type.c',
'pygi-boxed.c',
'pygi-closure.c',
diff --git a/gi/pygi-async.c b/gi/pygi-async.c
new file mode 100644
index 00000000..432ca9c5
--- /dev/null
+++ b/gi/pygi-async.c
@@ -0,0 +1,225 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2015 Christoph Reiter <reiter christoph gmail com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <Python.h>
+#include <structmember.h>
+#include <glib.h>
+#include "pygi-async.h"
+#include "pygi-util.h"
+#include "pygi-info.h"
+
+/* This is never instantiated. */
+PYGI_DEFINE_TYPE ("gi._gi.AsyncBase", PyGIAsyncBase_Type, PyObject)
+
+/**
+ * Async.__repr__() implementation.
+ * Takes the _Async.__repr_format format string and applies the finish function
+ * info to it.
+ */
+static PyObject*
+async_repr(PyObject *self) {
+ PyObject *string;
+
+ string =PyUnicode_FromString ("gi.Async(finish_func=blub)");
+
+ return string;
+}
+
+/**
+ * async_cancel:
+ *
+ * Cancel the asynchronous operation.
+ */
+static PyObject *
+async_cancel(PyGIAsync *self) {
+
+ //g_cancellable_cancel (self);
+
+ Py_INCREF (Py_None);
+ return Py_None;
+}
+
+static int
+async_init(PyGIAsync *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist, NULL))
+ return -1;
+
+ return 0;
+}
+
+static PyMethodDef async_methods[] = {
+ {"cancel", (PyCFunction)async_cancel, METH_NOARGS},
+ {NULL, NULL, 0},
+};
+
+static PyObject *
+async_await (PyObject *self)
+{
+ PyObject *res;
+ PyObject *selfseq = Py_BuildValue ("(O)", self);
+
+ res = PySeqIter_New (selfseq);
+
+ Py_DECREF (selfseq);
+
+ return res;
+}
+
+
+static PyAsyncMethods async_async_methods = {
+ .am_await = async_await,
+};
+
+static void
+async_dealloc(PyGIAsync *self)
+{
+ /* Deallocate the cancellable member? */
+ Py_CLEAR(self->cancellable);
+
+ PyObject_DEL(self);
+}
+
+
+void
+pygi_async_finish_cb (GObject *source_object, gpointer res, PyGIAsync *async)
+{
+ g_print ("async routine finished!\n");
+
+ Py_DECREF(async);
+}
+
+/**
+ * PyGIAsyncType_type.tp_getattro implementation.
+ * Exists solely to return the finish_func of the class.
+ */
+static PyObject*
+asynctype_getattro(PyObject *self, PyObject *name) {
+
+ if (PyUnicode_Check (name) && PyUnicode_CompareWithASCIIString (name, "finish_func") == 0) {
+ PyGIAsyncType *type = (PyGIAsyncType *) PyObject_Type(self);
+
+ Py_INCREF (type->async_finish);
+ return type->async_finish;
+ }
+
+ return PyGIAsyncBase_Type.tp_getattro (self, name);
+}
+
+/**
+ * pygi_async_new_type:
+ * @async_finish: A #GIFunctionInfo to wrap that is used to finish.
+ *
+ * Creates a result type for a pending asynchronous operation of a specific
+ * async function. This works by finding the corresponding finish function,
+ * and checking that it is compatible. If it is, a new type will be returned
+ * that can be cached for future use.
+ *
+ * Returns: A new PyGIAsyncType PyTypeObject of type PyGIAsyncType_Type
+ * or %NULL in case of an error.
+ */
+PyTypeObject*
+pygi_async_new_type(GIFunctionInfo *async_finish) {
+ PyGIAsyncType *new_type;
+ struct PyMemberDef members[] = {
+ {
+ "cancellable",
+ T_OBJECT,
+ offsetof(PyGIAsync, cancellable),
+ READONLY,
+ "The cancellable."
+ },
+ {NULL, }
+ };
+ PyType_Slot slots[] = {
+ { Py_tp_members, members },
+ { Py_tp_getattro, asynctype_getattro },
+ { 0, NULL}
+ };
+ PyType_Spec typespec = {
+ .name = "gi._Async",
+ .basicsize = sizeof(PyGIAsyncType),
+ .itemsize = sizeof(PyGIAsync),
+ .flags = Py_TPFLAGS_DEFAULT, /* We don't allow subclassing */
+ .slots = slots,
+ };
+ PyObject *bases;
+
+ g_assert (async_finish != NULL);
+
+ bases = Py_BuildValue ("(O)", &PyGIAsyncBase_Type);
+ new_type = (PyGIAsyncType*) PyType_FromSpecWithBases (&typespec, bases);
+ Py_DECREF(bases);
+
+ if (!new_type)
+ return NULL;
+
+ new_type->async_finish = _pygi_info_new ((GIBaseInfo *) async_finish);
+
+
+ return (PyTypeObject *) new_type;
+}
+
+
+/**
+ * pygi_async_new:
+ * @subclass: A PyGIAsyncType_Type subclass which will be the type of the
+ * returned instance.
+ *
+ * Return a new async instance.
+ *
+ * Returns: An instance of @subclass or %NULL on error.
+ */
+PyObject *
+pygi_async_new(PyTypeObject *subclass) {
+
+ return subclass->tp_alloc (subclass, 0);
+}
+
+/**
+ * pygi_async_register_types:
+ * @module: A Python modules to which Async gets added to.
+ *
+ * Initializes the Async class and adds it to the passed @module.
+ *
+ * Returns: -1 on error, 0 on success.
+ */
+int pygi_async_register_types(PyObject *module) {
+
+ PyGIAsyncBase_Type.tp_dealloc = (destructor)async_dealloc;
+ PyGIAsyncBase_Type.tp_repr = (reprfunc)async_repr;
+ PyGIAsyncBase_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
+ PyGIAsyncBase_Type.tp_methods = async_methods;
+ PyGIAsyncBase_Type.tp_as_async = &async_async_methods;
+ PyGIAsyncBase_Type.tp_init = (initproc)async_init;
+
+ if (PyType_Ready (&PyGIAsyncBase_Type) < 0)
+ return -1;
+
+ Py_INCREF (&PyGIAsyncBase_Type);
+ if (PyModule_AddObject (module, "AsyncBase",
+ (PyObject *)&PyGIAsyncBase_Type) < 0) {
+ Py_DECREF (&PyGIAsyncBase_Type);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/gi/pygi-async.h b/gi/pygi-async.h
new file mode 100644
index 00000000..d9b0e94e
--- /dev/null
+++ b/gi/pygi-async.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2015 Christoph Reiter <reiter christoph gmail com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PYGI_ASYNC_H__
+#define __PYGI_ASYNC_H__
+
+#include "Python.h"
+
+#include "pygi-cache.h"
+
+typedef struct {
+ PyTypeObject type_object;
+
+ /* All we need to know is how we can call the finish function and
+ * how to cancel the operation.
+ * We keep the async_finish information around solely to provide it as
+ * a read only member.
+ */
+ PyObject *async_finish;
+ PyGIFunctionCache *async_finish_cache;
+} PyGIAsyncType;
+
+typedef struct {
+ PyTypeObject type_object;
+
+ /* Here we only need the cancellable, callbacks, etc.
+ */
+ PyObject *cancellable;
+} PyGIAsync;
+
+
+int
+pygi_async_register_types (PyObject *d);
+
+void
+pygi_async_finish_cb (GObject *source_object, gpointer res, PyGIAsync *async);
+
+PyTypeObject *
+pygi_async_new_type (GIFunctionInfo *async_finish);
+
+PyObject*
+pygi_async_new (PyTypeObject *subclass);
+
+#endif /* __PYGI_ASYNCRESULT_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]