All of lore.kernel.org
 help / color / mirror / Atom feed
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 v2 2/5] bindings: python: enum: add a piece of common code for using python's enums from C
Date: Tue, 28 Jun 2022 10:42:23 +0200	[thread overview]
Message-ID: <20220628084226.472035-3-brgl@bgdev.pl> (raw)
In-Reply-To: <20220628084226.472035-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


  parent reply	other threads:[~2022-06-28  8:42 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-28  8:42 [libgpiod v2][PATCH v2 0/5] bindings: implement python bindings for libgpiod v2 Bartosz Golaszewski
2022-06-28  8:42 ` [libgpiod v2][PATCH v2 1/5] bindings: python: remove old version Bartosz Golaszewski
2022-06-28  8:42 ` Bartosz Golaszewski [this message]
2022-06-28  8:42 ` [libgpiod v2][PATCH v2 3/5] bindings: python: add examples for v2 API Bartosz Golaszewski
2022-06-28  8:42 ` [libgpiod v2][PATCH v2 4/5] bindings: python: add tests " Bartosz Golaszewski
2022-07-05  2:08   ` Kent Gibson
2022-07-07 10:17     ` Bartosz Golaszewski
2022-07-07 12:22       ` Kent Gibson
2022-06-28  8:42 ` [libgpiod v2][PATCH v2 5/5] bindings: python: add the implementation " Bartosz Golaszewski
2022-06-30  2:25   ` Kent Gibson
2022-06-30  6:54     ` Bartosz Golaszewski
2022-06-30  8:14       ` Kent Gibson
2022-06-30  8:38         ` Kent Gibson
2022-07-01  6:07           ` Kent Gibson
2022-07-01  7:21             ` Bartosz Golaszewski
2022-07-01  7:26               ` Kent Gibson
2022-07-01  7:29                 ` Bartosz Golaszewski
2022-07-01  7:33                   ` Kent Gibson
2022-07-01  8:02                     ` Kent Gibson
2022-07-01  8:18                       ` Bartosz Golaszewski
2022-07-01  8:32                         ` Bartosz Golaszewski
2022-07-01  8:52                           ` Kent Gibson
2022-07-01  9:28                             ` Bartosz Golaszewski
2022-07-01  8:32                         ` Kent Gibson
2022-07-05  2:09   ` Kent Gibson
2022-07-07 12:19     ` Bartosz Golaszewski
2022-07-07 13:09       ` Kent Gibson
2022-07-07 20:09         ` Bartosz Golaszewski
2022-07-08  1:38           ` Kent Gibson
2022-07-08  9:49             ` Bartosz Golaszewski
2022-07-08 10:56               ` Kent Gibson
2022-07-08 11:28                 ` Bartosz Golaszewski
2022-07-08 15:26                   ` Bartosz Golaszewski
2022-07-08 15:58                     ` Kent Gibson
2022-06-28  8:47 ` [libgpiod v2][PATCH v2 0/5] bindings: implement python bindings for libgpiod v2 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=20220628084226.472035-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.