From: Bartosz Golaszewski <brgl@bgdev.pl>
To: Kent Gibson <warthog618@gmail.com>,
Linus Walleij <linus.walleij@linaro.org>,
Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
Darrien <darrien@freenet.de>,
Viresh Kumar <viresh.kumar@linaro.org>, Jiri Benc <jbenc@upir.cz>,
Joel Savitz <joelsavitz@gmail.com>
Cc: linux-gpio@vger.kernel.org, Bartosz Golaszewski <brgl@bgdev.pl>
Subject: [libgpiod v2][PATCH 2/5] bindings: python: enum: add a piece of common code for using python's enums from C
Date: Wed, 25 May 2022 16:07:01 +0200 [thread overview]
Message-ID: <20220525140704.94983-3-brgl@bgdev.pl> (raw)
In-Reply-To: <20220525140704.94983-1-brgl@bgdev.pl>
This adds a small library of code that will be used both by the test
module as well as the main gpiod module for creating enum types in C
Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
---
bindings/python/enum/Makefile.am | 9 ++
bindings/python/enum/enum.c | 208 +++++++++++++++++++++++++++++++
bindings/python/enum/enum.h | 24 ++++
3 files changed, 241 insertions(+)
create mode 100644 bindings/python/enum/Makefile.am
create mode 100644 bindings/python/enum/enum.c
create mode 100644 bindings/python/enum/enum.h
diff --git a/bindings/python/enum/Makefile.am b/bindings/python/enum/Makefile.am
new file mode 100644
index 0000000..7dd4a12
--- /dev/null
+++ b/bindings/python/enum/Makefile.am
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+
+noinst_LTLIBRARIES = libpycenum.la
+libpycenum_la_SOURCES = enum.c enum.h
+
+libpycenum_la_CFLAGS = -Wall -Wextra -g -std=gnu89 $(PYTHON_CPPFLAGS)
+libpycenum_la_LDFLAGS = -module -avoid-version
+libpycenum_la_LIBADD = $(PYTHON_LIBS)
diff --git a/bindings/python/enum/enum.c b/bindings/python/enum/enum.c
new file mode 100644
index 0000000..22a384a
--- /dev/null
+++ b/bindings/python/enum/enum.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl>
+
+/* Code allowing to inherit from enum.Enum in a C extension. */
+
+#include "enum.h"
+
+static PyObject *make_enum_args(const PyCEnum_EnumDef *enum_def)
+{
+ PyObject *dict, *args, *key, *val, *name;
+ const PyCEnum_EnumVal *item;
+ int ret;
+
+ dict = PyDict_New();
+ if (!dict)
+ return NULL;
+
+ for (item = enum_def->values; item->name; item++) {
+ key = PyUnicode_FromString(item->name);
+ if (!key) {
+ Py_DECREF(dict);
+ return NULL;
+ }
+
+ val = PyLong_FromLong(item->value);
+ if (!val) {
+ Py_DECREF(key);
+ Py_DECREF(dict);
+ return NULL;
+ }
+
+ ret = PyDict_SetItem(dict, key, val);
+ Py_DECREF(key);
+ Py_DECREF(val);
+ if (ret) {
+ Py_DECREF(dict);
+ return NULL;
+ }
+ }
+
+ name = PyUnicode_FromString(enum_def->name);
+ if (!name) {
+ Py_DECREF(dict);
+ return NULL;
+ }
+
+ args = PyTuple_Pack(2, name, dict);
+ Py_DECREF(name);
+ Py_DECREF(dict);
+ return args;
+}
+
+static PyObject *make_enum_type(const PyCEnum_EnumDef *enum_def)
+{
+ PyObject *new_type, *args, *enum_mod, *enum_type;
+
+ args = make_enum_args(enum_def);
+ if (!args)
+ return NULL;
+
+ enum_mod = PyImport_ImportModule("enum");
+ if (!enum_mod) {
+ Py_DECREF(args);
+ return NULL;
+ }
+
+ enum_type = PyObject_GetAttrString(enum_mod, "Enum");
+ if (!enum_type) {
+ Py_DECREF(enum_mod);
+ Py_DECREF(args);
+ return NULL;
+ }
+
+ new_type = PyObject_Call(enum_type, args, NULL);
+ Py_DECREF(enum_type);
+ Py_DECREF(enum_mod);
+ Py_DECREF(args);
+ return new_type;
+}
+
+int PyCEnum_AddEnumsToType(const PyCEnum_EnumDef *defs, PyTypeObject *type)
+{
+ const PyCEnum_EnumDef *enum_def;
+ PyObject *enum_type;
+ int ret;
+
+ for (enum_def = defs; enum_def->name; enum_def++) {
+ enum_type = make_enum_type(enum_def);
+ if (!enum_type)
+ return -1;
+
+ ret = PyDict_SetItemString(type->tp_dict,
+ enum_def->name, enum_type);
+ if (ret) {
+ Py_DECREF(enum_type);
+ return -1;
+ }
+ }
+
+ PyType_Modified(type);
+ return 0;
+}
+
+static PyObject *map_c_to_python(PyObject *iter, int value)
+{
+ PyObject *next, *val;
+ long num;
+
+ for (;;) {
+ next = PyIter_Next(iter);
+ if (!next)
+ break;
+
+ val = PyObject_GetAttrString(next, "value");
+ if (!val) {
+ Py_DECREF(next);
+ return NULL;
+ }
+
+ num = PyLong_AsLong(val);
+ Py_DECREF(val);
+
+ if (value == num)
+ return next;
+
+ Py_DECREF(next);
+ }
+
+ PyErr_SetString(PyExc_NotImplementedError,
+ "enum value does not exist");
+ return NULL;
+}
+
+PyObject *PyCEnum_MapCToPy(PyObject *parent, const char *enum_name, int value)
+{
+ PyObject *enum_type, *iter, *ret;
+
+ enum_type = PyObject_GetAttrString(parent, enum_name);
+ if (!enum_type)
+ return NULL;
+
+ iter = PyObject_GetIter(enum_type);
+ if (!iter) {
+ Py_DECREF(enum_type);
+ return NULL;
+ }
+
+ ret = map_c_to_python(iter, value);
+ Py_DECREF(iter);
+ Py_DECREF(enum_type);
+ Py_INCREF(ret);
+ return ret;
+}
+
+static int map_python_to_c(PyObject *iter, int value)
+{
+ PyObject *next, *val;
+ long num;
+
+ for (;;) {
+ next = PyIter_Next(iter);
+ if (!next)
+ break;
+
+ val = PyObject_GetAttrString(next, "value");
+ if (!val) {
+ Py_DECREF(next);
+ return -1;
+ }
+
+ num = PyLong_AsLong(val);
+ Py_DECREF(val);
+
+ if (value == num)
+ return value;
+
+ Py_DECREF(next);
+ }
+
+ PyErr_SetString(PyExc_NotImplementedError,
+ "enum value does not exist");
+ return -1;
+}
+
+int PyCEnum_MapPyToC(PyObject *parent, const char *enum_name, PyObject *value)
+{
+ PyObject *enum_type, *iter, *val;
+ int ret;
+
+ enum_type = PyObject_GetAttrString(parent, enum_name);
+ if (!enum_type)
+ return -1;
+
+ iter = PyObject_GetIter(enum_type);
+ if (!iter) {
+ Py_DECREF(enum_type);
+ return -1;
+ }
+
+ val = PyObject_GetAttrString(value, "value");
+ if (!val)
+ return -1;
+
+ ret = map_python_to_c(iter, PyLong_AsLong(val));
+ Py_DECREF(iter);
+ Py_DECREF(enum_type);
+ return ret;
+}
diff --git a/bindings/python/enum/enum.h b/bindings/python/enum/enum.h
new file mode 100644
index 0000000..28ddcaf
--- /dev/null
+++ b/bindings/python/enum/enum.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/* SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+#ifndef __LIBGPIOD_PYTHON_ENUM_H__
+#define __LIBGPIOD_PYTHON_ENUM_H__
+
+#include <Python.h>
+
+typedef struct {
+ const char *name;
+ long value;
+} PyCEnum_EnumVal;
+
+typedef struct {
+ const char *name;
+ const PyCEnum_EnumVal *values;
+} PyCEnum_EnumDef;
+
+int PyCEnum_AddEnumsToType(const PyCEnum_EnumDef *defs, PyTypeObject *type);
+
+PyObject *PyCEnum_MapCToPy(PyObject *parent, const char *enum_name, int value);
+int PyCEnum_MapPyToC(PyObject *parent, const char *enum_name, PyObject *value);
+
+#endif /* __LIBGPIOD_PYTHON_ENUM_H__ */
--
2.34.1
next prev parent reply other threads:[~2022-05-25 14:08 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-05-25 14:06 [libgpiod v2][PATCH 0/5] bindings: implement python bindings for libgpiod v2 Bartosz Golaszewski
2022-05-25 14:07 ` [libgpiod v2][PATCH 1/5] bindings: python: remove old version Bartosz Golaszewski
2022-05-25 14:07 ` Bartosz Golaszewski [this message]
2022-05-25 14:07 ` [libgpiod v2][PATCH 3/5] bindings: python: add examples for v2 API Bartosz Golaszewski
2022-06-03 12:46 ` Kent Gibson
2022-06-04 2:41 ` Kent Gibson
2022-06-06 10:14 ` Andy Shevchenko
2022-06-07 1:52 ` Kent Gibson
2022-06-07 10:43 ` Andy Shevchenko
2022-06-08 15:39 ` Bartosz Golaszewski
2022-06-09 4:49 ` Kent Gibson
2022-06-09 8:42 ` Bartosz Golaszewski
2022-06-09 13:21 ` Jiri Benc
2022-06-09 16:06 ` Bartosz Golaszewski
2022-06-10 4:23 ` Kent Gibson
2022-06-10 6:57 ` Bartosz Golaszewski
2022-05-25 14:07 ` [libgpiod v2][PATCH 4/5] bindings: python: add tests " Bartosz Golaszewski
2022-05-25 14:07 ` [libgpiod v2][PATCH 5/5] bindings: python: add the implementation " Bartosz Golaszewski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220525140704.94983-3-brgl@bgdev.pl \
--to=brgl@bgdev.pl \
--cc=andriy.shevchenko@linux.intel.com \
--cc=darrien@freenet.de \
--cc=jbenc@upir.cz \
--cc=joelsavitz@gmail.com \
--cc=linus.walleij@linaro.org \
--cc=linux-gpio@vger.kernel.org \
--cc=viresh.kumar@linaro.org \
--cc=warthog618@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).