summaryrefslogtreecommitdiff
path: root/dbus_bindings/containers.c
diff options
context:
space:
mode:
Diffstat (limited to 'dbus_bindings/containers.c')
-rw-r--r--dbus_bindings/containers.c825
1 files changed, 825 insertions, 0 deletions
diff --git a/dbus_bindings/containers.c b/dbus_bindings/containers.c
new file mode 100644
index 0000000..e364f98
--- /dev/null
+++ b/dbus_bindings/containers.c
@@ -0,0 +1,825 @@
+/* D-Bus container types: Array, Dict and Struct.
+ *
+ * Copyright (C) 2006-2007 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "dbus_bindings-internal.h"
+
+#include <Python.h>
+#include <structmember.h>
+
+#include "types-internal.h"
+
+/* Array ============================================================ */
+
+PyDoc_STRVAR(Array_tp_doc,
+"An array of similar items, implemented as a subtype of list.\n"
+"\n"
+"As currently implemented, an Array behaves just like a list, but\n"
+"with the addition of a ``signature`` property set by the constructor;\n"
+"conversion of its items to D-Bus types is only done when it's sent in\n"
+"a Message. This might change in future so validation is done earlier.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.Array([iterable][, signature][, variant_level])\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+"``signature`` is the D-Bus signature string for a single element of the\n"
+"array, or None. If not None it must represent a single complete type, the\n"
+"type of a single array item; the signature of the whole Array may be\n"
+"obtained by prepending ``a`` to the given signature.\n"
+"\n"
+"If None (the default), when the Array is sent over\n"
+"D-Bus, the item signature will be guessed from the first element.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing an array, this is represented in Python by an\n"
+" Array with variant_level==2.\n"
+);
+
+static struct PyMemberDef Array_tp_members[] = {
+ {"signature", T_OBJECT, offsetof(DBusPyArray, signature), READONLY,
+ "The D-Bus signature of each element of this Array (a Signature "
+ "instance)"},
+ {"variant_level", T_LONG, offsetof(DBusPyArray, variant_level),
+ READONLY,
+ "The number of nested variants wrapping the real data. "
+ "0 if not in a variant."},
+ {NULL},
+};
+
+static void
+Array_tp_dealloc (DBusPyArray *self)
+{
+ Py_CLEAR(self->signature);
+ (PyList_Type.tp_dealloc)((PyObject *)self);
+}
+
+static PyObject *
+Array_tp_repr(DBusPyArray *self)
+{
+ PyObject *parent_repr = (PyList_Type.tp_repr)((PyObject *)self);
+ PyObject *sig_repr = PyObject_Repr(self->signature);
+ PyObject *my_repr = NULL;
+ long variant_level = self->variant_level;
+
+ if (!parent_repr) goto finally;
+ if (!sig_repr) goto finally;
+ if (variant_level > 0) {
+ my_repr = PyUnicode_FromFormat("%s(%V, signature=%V, "
+ "variant_level=%ld)",
+ Py_TYPE(&self->super)->tp_name,
+ REPRV(parent_repr),
+ REPRV(sig_repr),
+ variant_level);
+ }
+ else {
+ my_repr = PyUnicode_FromFormat("%s(%V, signature=%V)",
+ Py_TYPE(&self->super)->tp_name,
+ REPRV(parent_repr),
+ REPRV(sig_repr));
+ }
+finally:
+ Py_CLEAR(parent_repr);
+ Py_CLEAR(sig_repr);
+ return my_repr;
+}
+
+static PyObject *
+Array_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *variant_level = NULL;
+ DBusPyArray *self = (DBusPyArray *)(PyList_Type.tp_new)(cls, args, kwargs);
+
+ /* variant_level is immutable, so handle it in __new__ rather than
+ __init__ */
+ if (!self) return NULL;
+ Py_INCREF(Py_None);
+ self->signature = Py_None;
+ self->variant_level = 0;
+ if (kwargs) {
+ variant_level = PyDict_GetItem(kwargs, dbus_py_variant_level_const);
+ }
+ if (variant_level) {
+ long new_variant_level = PyLong_AsLong(variant_level);
+ if (new_variant_level == -1 && PyErr_Occurred()) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ self->variant_level = new_variant_level;
+ }
+ return (PyObject *)self;
+}
+
+static int
+Array_tp_init (DBusPyArray *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *obj = dbus_py_empty_tuple;
+ PyObject *signature = NULL;
+ PyObject *tuple;
+ PyObject *variant_level;
+ /* variant_level is accepted but ignored - it's immutable, so
+ * __new__ handles it */
+ static char *argnames[] = {"iterable", "signature", "variant_level", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO:__init__", argnames,
+ &obj, &signature, &variant_level)) {
+ return -1;
+ }
+
+ /* convert signature from a borrowed ref of unknown type to an owned ref
+ of type Signature (or None) */
+ if (!signature) signature = Py_None;
+ if (signature == Py_None
+ || PyObject_IsInstance(signature, (PyObject *)&DBusPySignature_Type)) {
+ Py_INCREF(signature);
+ }
+ else {
+ signature = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
+ "(O)", signature);
+ if (!signature) return -1;
+ }
+
+ if (signature != Py_None) {
+ const char *c_str;
+ PyObject *signature_as_bytes;
+
+ if (
+#ifdef PY3
+ !PyUnicode_Check(signature)
+#else
+ !PyBytes_Check(signature)
+#endif
+ )
+ {
+ PyErr_SetString(PyExc_TypeError, "str expected");
+ Py_CLEAR(signature);
+ return -1;
+ }
+#ifdef PY3
+ if (!(signature_as_bytes = PyUnicode_AsUTF8String(signature))) {
+ Py_CLEAR(signature);
+ return -1;
+ }
+#else
+ signature_as_bytes = signature;
+ Py_INCREF(signature_as_bytes);
+#endif
+
+ c_str = PyBytes_AS_STRING(signature_as_bytes);
+
+ if (!dbus_signature_validate_single(c_str, NULL)) {
+ Py_CLEAR(signature);
+ Py_CLEAR(signature_as_bytes);
+ PyErr_SetString(PyExc_ValueError,
+ "There must be exactly one complete type in "
+ "an Array's signature parameter");
+ return -1;
+ }
+ Py_CLEAR(signature_as_bytes);
+ }
+
+ tuple = Py_BuildValue("(O)", obj);
+ if (!tuple) {
+ Py_CLEAR(signature);
+ return -1;
+ }
+ if ((PyList_Type.tp_init)((PyObject *)self, tuple, NULL) < 0) {
+ Py_CLEAR(tuple);
+ Py_CLEAR(signature);
+ return -1;
+ }
+ Py_CLEAR(tuple);
+
+ Py_CLEAR(self->signature);
+ self->signature = signature;
+ return 0;
+}
+
+PyTypeObject DBusPyArray_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Array",
+ sizeof(DBusPyArray),
+ 0,
+ (destructor)Array_tp_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)Array_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Array_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ Array_tp_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Array_tp_init, /* tp_init */
+ 0, /* tp_alloc */
+ Array_tp_new, /* tp_new */
+};
+
+/* Dict ============================================================= */
+
+PyDoc_STRVAR(Dict_tp_doc,
+"An mapping whose keys are similar and whose values are similar,\n"
+"implemented as a subtype of dict.\n"
+"\n"
+"As currently implemented, a Dictionary behaves just like a dict, but\n"
+"with the addition of a ``signature`` property set by the constructor;\n"
+"conversion of its items to D-Bus types is only done when it's sent in\n"
+"a Message. This may change in future so validation is done earlier.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" Dictionary(mapping_or_iterable=(), signature=None, variant_level=0)\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+"``signature`` is either a string or None. If a string, it must consist\n"
+"of exactly two complete type signatures, representing the 'key' type\n"
+"(which must be a primitive type, i.e. one of \"bdginoqstuxy\")\n"
+"and the 'value' type. The signature of the whole Dictionary will be\n"
+"``a{xx}`` where ``xx`` is replaced by the given signature.\n"
+"\n"
+"If it is None (the default), when the Dictionary is sent over\n"
+"D-Bus, the key and value signatures will be guessed from an arbitrary\n"
+"element of the Dictionary.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing an array of DICT_ENTRY, this is represented in\n"
+" Python by a Dictionary with variant_level==2.\n"
+);
+
+static struct PyMemberDef Dict_tp_members[] = {
+ {"signature", T_OBJECT, offsetof(DBusPyDict, signature), READONLY,
+ "The D-Bus signature of each key in this Dictionary, followed by "
+ "that of each value in this Dictionary, as a Signature instance."},
+ {"variant_level", T_LONG, offsetof(DBusPyDict, variant_level),
+ READONLY,
+ "The number of nested variants wrapping the real data. "
+ "0 if not in a variant."},
+ {NULL},
+};
+
+static void
+Dict_tp_dealloc (DBusPyDict *self)
+{
+ Py_CLEAR(self->signature);
+ (PyDict_Type.tp_dealloc)((PyObject *)self);
+}
+
+static PyObject *
+Dict_tp_repr(DBusPyDict *self)
+{
+ PyObject *parent_repr = (PyDict_Type.tp_repr)((PyObject *)self);
+ PyObject *sig_repr = PyObject_Repr(self->signature);
+ PyObject *my_repr = NULL;
+ long variant_level = self->variant_level;
+
+ if (!parent_repr) goto finally;
+ if (!sig_repr) goto finally;
+ if (variant_level > 0) {
+ my_repr = PyUnicode_FromFormat("%s(%V, signature=%V, "
+ "variant_level=%ld)",
+ Py_TYPE(&self->super)->tp_name,
+ REPRV(parent_repr),
+ REPRV(sig_repr),
+ variant_level);
+ }
+ else {
+ my_repr = PyUnicode_FromFormat("%s(%V, signature=%V)",
+ Py_TYPE(&self->super)->tp_name,
+ REPRV(parent_repr),
+ REPRV(sig_repr));
+ }
+finally:
+ Py_CLEAR(parent_repr);
+ Py_CLEAR(sig_repr);
+ return my_repr;
+}
+
+static PyObject *
+Dict_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ DBusPyDict *self = (DBusPyDict *)(PyDict_Type.tp_new)(cls, args, kwargs);
+ PyObject *variant_level = NULL;
+
+ /* variant_level is immutable, so handle it in __new__ rather than
+ __init__ */
+ if (!self) return NULL;
+ Py_INCREF(Py_None);
+ self->signature = Py_None;
+ self->variant_level = 0;
+ if (kwargs) {
+ variant_level = PyDict_GetItem(kwargs, dbus_py_variant_level_const);
+ }
+ if (variant_level) {
+ long new_variant_level = PyLong_AsLong(variant_level);
+
+ if (new_variant_level == -1 && PyErr_Occurred()) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ self->variant_level = new_variant_level;
+ }
+ return (PyObject *)self;
+}
+
+static int
+Dict_tp_init(DBusPyDict *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *obj = dbus_py_empty_tuple;
+ PyObject *signature = NULL;
+ PyObject *tuple;
+ PyObject *variant_level; /* ignored here - __new__ uses it */
+ static char *argnames[] = {"mapping_or_iterable", "signature",
+ "variant_level", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOO:__init__", argnames,
+ &obj, &signature, &variant_level)) {
+ return -1;
+ }
+
+ /* convert signature from a borrowed ref of unknown type to an owned ref
+ of type Signature (or None) */
+ if (!signature) signature = Py_None;
+ if (signature == Py_None
+ || PyObject_IsInstance(signature, (PyObject *)&DBusPySignature_Type)) {
+ Py_INCREF(signature);
+ }
+ else {
+ signature = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
+ "(O)", signature);
+ if (!signature) return -1;
+ }
+
+ if (signature != Py_None) {
+ const char *c_str;
+ PyObject *signature_as_bytes;
+
+ if (!NATIVESTR_CHECK(signature)) {
+ PyErr_SetString(PyExc_TypeError, "str expected");
+ Py_CLEAR(signature);
+ return -1;
+ }
+#ifdef PY3
+ if (!(signature_as_bytes = PyUnicode_AsUTF8String(signature))) {
+ Py_CLEAR(signature);
+ return -1;
+ }
+#else
+ signature_as_bytes = signature;
+ Py_INCREF(signature_as_bytes);
+#endif
+
+ c_str = PyBytes_AS_STRING(signature_as_bytes);
+ switch (c_str[0]) {
+ case DBUS_TYPE_BYTE:
+ case DBUS_TYPE_BOOLEAN:
+ case DBUS_TYPE_INT16:
+ case DBUS_TYPE_UINT16:
+ case DBUS_TYPE_INT32:
+ case DBUS_TYPE_UINT32:
+ case DBUS_TYPE_INT64:
+ case DBUS_TYPE_UINT64:
+ case DBUS_TYPE_DOUBLE:
+#ifdef WITH_DBUS_FLOAT32
+ case DBUS_TYPE_FLOAT:
+#endif
+#ifdef DBUS_TYPE_UNIX_FD
+ case DBUS_TYPE_UNIX_FD:
+#endif
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_SIGNATURE:
+ break;
+ default:
+ Py_CLEAR(signature);
+ Py_CLEAR(signature_as_bytes);
+ PyErr_SetString(PyExc_ValueError,
+ "The key type in a Dictionary's signature "
+ "must be a primitive type");
+ return -1;
+ }
+
+ if (!dbus_signature_validate_single(c_str + 1, NULL)) {
+ Py_CLEAR(signature);
+ Py_CLEAR(signature_as_bytes);
+ PyErr_SetString(PyExc_ValueError,
+ "There must be exactly two complete types in "
+ "a Dictionary's signature parameter");
+ return -1;
+ }
+ Py_CLEAR(signature_as_bytes);
+ }
+
+ tuple = Py_BuildValue("(O)", obj);
+ if (!tuple) {
+ Py_CLEAR(signature);
+ return -1;
+ }
+
+ if ((PyDict_Type.tp_init((PyObject *)self, tuple, NULL)) < 0) {
+ Py_CLEAR(tuple);
+ Py_CLEAR(signature);
+ return -1;
+ }
+ Py_CLEAR(tuple);
+
+ Py_CLEAR(self->signature);
+ self->signature = signature;
+ return 0;
+}
+
+PyTypeObject DBusPyDict_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Dictionary",
+ sizeof(DBusPyDict),
+ 0,
+ (destructor)Dict_tp_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)Dict_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Dict_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ Dict_tp_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Dict_tp_init, /* tp_init */
+ 0, /* tp_alloc */
+ Dict_tp_new, /* tp_new */
+};
+
+/* Struct =========================================================== */
+
+static PyObject *struct_signatures;
+
+PyDoc_STRVAR(Struct_tp_doc,
+"An structure containing items of possibly distinct types.\n"
+"\n"
+"Constructor::\n"
+"\n"
+" dbus.Struct(iterable, signature=None, variant_level=0) -> Struct\n"
+"\n"
+"D-Bus structs may not be empty, so the iterable argument is required and\n"
+"may not be an empty iterable.\n"
+"\n"
+"``signature`` is either None, or a string representing the contents of the\n"
+"struct as one or more complete type signatures. The overall signature of\n"
+"the struct will be the given signature enclosed in parentheses, ``()``.\n"
+"\n"
+"If the signature is None (default) it will be guessed\n"
+"from the types of the items during construction.\n"
+"\n"
+"``variant_level`` must be non-negative; the default is 0.\n"
+"\n"
+":IVariables:\n"
+" `variant_level` : int\n"
+" Indicates how many nested Variant containers this object\n"
+" is contained in: if a message's wire format has a variant containing a\n"
+" variant containing a struct, this is represented in Python by a\n"
+" Struct with variant_level==2.\n"
+);
+
+static PyObject *
+Struct_tp_repr(PyObject *self)
+{
+ PyObject *parent_repr = (PyTuple_Type.tp_repr)((PyObject *)self);
+ PyObject *sig;
+ PyObject *sig_repr = NULL;
+ PyObject *key;
+ long variant_level;
+ PyObject *my_repr = NULL;
+
+ if (!parent_repr) goto finally;
+ key = PyLong_FromVoidPtr(self);
+ if (!key) goto finally;
+ sig = PyDict_GetItem(struct_signatures, key);
+ Py_CLEAR(key);
+ if (!sig) sig = Py_None;
+ sig_repr = PyObject_Repr(sig);
+ if (!sig_repr) goto finally;
+
+ variant_level = dbus_py_variant_level_get(self);
+ if (variant_level < 0)
+ goto finally;
+
+ if (variant_level > 0) {
+ my_repr = PyUnicode_FromFormat("%s(%V, signature=%V, "
+ "variant_level=%ld)",
+ Py_TYPE(self)->tp_name,
+ REPRV(parent_repr),
+ REPRV(sig_repr),
+ variant_level);
+ }
+ else {
+ my_repr = PyUnicode_FromFormat("%s(%V, signature=%V)",
+ Py_TYPE(self)->tp_name,
+ REPRV(parent_repr),
+ REPRV(sig_repr));
+ }
+
+finally:
+ Py_CLEAR(parent_repr);
+ Py_CLEAR(sig_repr);
+ return my_repr;
+}
+
+static PyObject *
+Struct_tp_new (PyTypeObject *cls, PyObject *args, PyObject *kwargs)
+{
+ PyObject *signature = NULL;
+ long variantness = 0;
+ PyObject *self, *key;
+ static char *argnames[] = {"signature", "variant_level", NULL};
+
+ if (PyTuple_Size(args) != 1) {
+ PyErr_SetString(PyExc_TypeError,
+ "__new__ takes exactly one positional parameter");
+ return NULL;
+ }
+ if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
+ "|Ol:__new__", argnames,
+ &signature, &variantness)) {
+ return NULL;
+ }
+ if (variantness < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "variant_level must be non-negative");
+ return NULL;
+ }
+
+ self = (PyTuple_Type.tp_new)(cls, args, NULL);
+ if (!self)
+ return NULL;
+ if (PyTuple_Size(self) < 1) {
+ PyErr_SetString(PyExc_ValueError, "D-Bus structs may not be empty");
+ Py_CLEAR(self);
+ return NULL;
+ }
+
+ if (!dbus_py_variant_level_set(self, variantness)) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+
+ /* convert signature from a borrowed ref of unknown type to an owned ref
+ of type Signature (or None) */
+ if (!signature) signature = Py_None;
+ if (signature == Py_None
+ || PyObject_IsInstance(signature, (PyObject *)&DBusPySignature_Type)) {
+ Py_INCREF(signature);
+ }
+ else {
+ signature = PyObject_CallFunction((PyObject *)&DBusPySignature_Type,
+ "(O)", signature);
+ if (!signature) {
+ Py_CLEAR(self);
+ return NULL;
+ }
+ }
+
+ key = PyLong_FromVoidPtr(self);
+ if (!key) {
+ Py_CLEAR(self);
+ Py_CLEAR(signature);
+ return NULL;
+ }
+ if (PyDict_SetItem(struct_signatures, key, signature) < 0) {
+ Py_CLEAR(key);
+ Py_CLEAR(self);
+ Py_CLEAR(signature);
+ return NULL;
+ }
+
+ Py_CLEAR(key);
+ Py_CLEAR(signature);
+ return self;
+}
+
+static void
+Struct_tp_dealloc(PyObject *self)
+{
+ PyObject *et, *ev, *etb, *key;
+
+ dbus_py_variant_level_clear(self);
+ PyErr_Fetch(&et, &ev, &etb);
+
+ key = PyLong_FromVoidPtr(self);
+ if (key) {
+ if (PyDict_GetItem(struct_signatures, key)) {
+ if (PyDict_DelItem(struct_signatures, key) < 0) {
+ /* should never happen */
+ PyErr_WriteUnraisable(self);
+ }
+ }
+ Py_CLEAR(key);
+ }
+ else {
+ /* not enough memory to free all the memory... leak the signature,
+ * there's not much else we could do here */
+ PyErr_WriteUnraisable(self);
+ }
+
+ PyErr_Restore(et, ev, etb);
+ (PyTuple_Type.tp_dealloc)(self);
+}
+
+static PyObject *
+Struct_tp_getattro(PyObject *obj, PyObject *name)
+{
+ PyObject *key, *value;
+
+#ifdef PY3
+ if (PyUnicode_CompareWithASCIIString(name, "signature"))
+ return dbus_py_variant_level_getattro(obj, name);
+#else
+ if (PyBytes_Check(name)) {
+ Py_INCREF(name);
+ }
+ else if (PyUnicode_Check(name)) {
+ name = PyUnicode_AsEncodedString(name, NULL, NULL);
+ if (!name) {
+ return NULL;
+ }
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "attribute name must be string");
+ return NULL;
+ }
+
+ if (strcmp(PyBytes_AS_STRING(name), "signature")) {
+ value = dbus_py_variant_level_getattro(obj, name);
+ Py_CLEAR(name);
+ return value;
+ }
+ Py_CLEAR(name);
+#endif /* PY3 */
+
+ key = PyLong_FromVoidPtr(obj);
+
+ if (!key) {
+ return NULL;
+ }
+
+ value = PyDict_GetItem(struct_signatures, key);
+ Py_CLEAR(key);
+
+ if (!value)
+ value = Py_None;
+ Py_INCREF(value);
+ return value;
+}
+
+PyTypeObject DBusPyStruct_Type = {
+ PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
+ "dbus.Struct",
+ 0,
+ 0,
+ Struct_tp_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)Struct_tp_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ Struct_tp_getattro, /* tp_getattro */
+ dbus_py_immutable_setattro, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Struct_tp_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ Struct_tp_new, /* tp_new */
+};
+
+dbus_bool_t
+dbus_py_init_container_types(void)
+{
+ struct_signatures = PyDict_New();
+ if (!struct_signatures) return 0;
+
+ DBusPyArray_Type.tp_base = &PyList_Type;
+ if (PyType_Ready(&DBusPyArray_Type) < 0) return 0;
+ DBusPyArray_Type.tp_print = NULL;
+
+ DBusPyDict_Type.tp_base = &PyDict_Type;
+ if (PyType_Ready(&DBusPyDict_Type) < 0) return 0;
+ DBusPyDict_Type.tp_print = NULL;
+
+ DBusPyStruct_Type.tp_base = &PyTuple_Type;
+ if (PyType_Ready(&DBusPyStruct_Type) < 0) return 0;
+ DBusPyStruct_Type.tp_print = NULL;
+
+ return 1;
+}
+
+dbus_bool_t
+dbus_py_insert_container_types(PyObject *this_module)
+{
+ /* PyModule_AddObject steals a ref */
+ Py_INCREF(&DBusPyArray_Type);
+ if (PyModule_AddObject(this_module, "Array",
+ (PyObject *)&DBusPyArray_Type) < 0) return 0;
+
+ Py_INCREF(&DBusPyDict_Type);
+ if (PyModule_AddObject(this_module, "Dictionary",
+ (PyObject *)&DBusPyDict_Type) < 0) return 0;
+
+ Py_INCREF(&DBusPyStruct_Type);
+ if (PyModule_AddObject(this_module, "Struct",
+ (PyObject *)&DBusPyStruct_Type) < 0) return 0;
+
+ return 1;
+}
+
+/* vim:set ft=c cino< sw=4 sts=4 et: */
+