1 /* D-Bus container types: Array, Dict and Struct.
3 * Copyright (C) 2006, 2007 Collabora Ltd.
5 * Licensed under the Academic Free License version 2.1
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include <structmember.h>
28 #include "dbus_bindings-internal.h"
29 #include "types-internal.h"
31 /* Array ============================================================ */
33 PyDoc_STRVAR(Array_tp_doc
,
34 "An array of similar items, implemented as a subtype of list.\n"
36 "As currently implemented, an Array behaves just like a list, but\n"
37 "with the addition of a ``signature`` property set by the constructor;\n"
38 "conversion of its items to D-Bus types is only done when it's sent in\n"
39 "a Message. This might change in future so validation is done earlier.\n"
43 " dbus.Array([iterable][, signature][, variant_level])\n"
45 "``variant_level`` must be non-negative; the default is 0.\n"
47 "``signature`` is the D-Bus signature string for a single element of the\n"
48 "array, or None. If not None it must represent a single complete type, the\n"
49 "type of a single array item; the signature of the whole Array may be\n"
50 "obtained by prepending ``a`` to the given signature.\n"
52 "If None (the default), when the Array is sent over\n"
53 "D-Bus, the item signature will be guessed from the first element.\n"
56 " `variant_level` : int\n"
57 " Indicates how many nested Variant containers this object\n"
58 " is contained in: if a message's wire format has a variant containing a\n"
59 " variant containing an array, this is represented in Python by an\n"
60 " Array with variant_level==2.\n"
63 static struct PyMemberDef Array_tp_members
[] = {
64 {"signature", T_OBJECT
, offsetof(DBusPyArray
, signature
), READONLY
,
65 "The D-Bus signature of each element of this Array (a Signature "
67 {"variant_level", T_LONG
, offsetof(DBusPyArray
, variant_level
),
69 "The number of nested variants wrapping the real data. "
70 "0 if not in a variant."},
75 Array_tp_dealloc (DBusPyArray
*self
)
77 Py_XDECREF(self
->signature
);
78 self
->signature
= NULL
;
79 (PyList_Type
.tp_dealloc
)((PyObject
*)self
);
83 Array_tp_repr(DBusPyArray
*self
)
85 PyObject
*parent_repr
= (PyList_Type
.tp_repr
)((PyObject
*)self
);
86 PyObject
*sig_repr
= PyObject_Repr(self
->signature
);
87 PyObject
*my_repr
= NULL
;
88 long variant_level
= self
->variant_level
;
90 if (!parent_repr
) goto finally
;
91 if (!sig_repr
) goto finally
;
92 if (variant_level
> 0) {
93 my_repr
= PyString_FromFormat("%s(%s, signature=%s, "
95 self
->super
.ob_type
->tp_name
,
96 PyString_AS_STRING(parent_repr
),
97 PyString_AS_STRING(sig_repr
),
101 my_repr
= PyString_FromFormat("%s(%s, signature=%s)",
102 self
->super
.ob_type
->tp_name
,
103 PyString_AS_STRING(parent_repr
),
104 PyString_AS_STRING(sig_repr
));
107 Py_XDECREF(parent_repr
);
108 Py_XDECREF(sig_repr
);
113 Array_tp_new (PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
115 PyObject
*variant_level
= NULL
;
116 DBusPyArray
*self
= (DBusPyArray
*)(PyList_Type
.tp_new
)(cls
, args
, kwargs
);
118 /* variant_level is immutable, so handle it in __new__ rather than
120 if (!self
) return NULL
;
122 self
->signature
= Py_None
;
123 self
->variant_level
= 0;
125 variant_level
= PyDict_GetItem(kwargs
, dbus_py_variant_level_const
);
128 self
->variant_level
= PyInt_AsLong(variant_level
);
129 if (PyErr_Occurred()) {
130 Py_DECREF((PyObject
*)self
);
134 return (PyObject
*)self
;
138 Array_tp_init (DBusPyArray
*self
, PyObject
*args
, PyObject
*kwargs
)
140 PyObject
*obj
= dbus_py_empty_tuple
;
141 PyObject
*signature
= NULL
;
143 PyObject
*variant_level
;
144 /* variant_level is accepted but ignored - it's immutable, so
145 * __new__ handles it */
146 static char *argnames
[] = {"iterable", "signature", "variant_level", NULL
};
148 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|OOO:__init__", argnames
,
149 &obj
, &signature
, &variant_level
)) {
153 /* convert signature from a borrowed ref of unknown type to an owned ref
154 of type Signature (or None) */
155 if (!signature
) signature
= Py_None
;
156 if (signature
== Py_None
157 || PyObject_IsInstance(signature
, (PyObject
*)&DBusPySignature_Type
)) {
158 Py_INCREF(signature
);
161 signature
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
163 if (!signature
) return -1;
166 if (signature
!= Py_None
) {
167 const char *c_str
= PyString_AS_STRING(signature
);
169 if (!dbus_signature_validate_single(c_str
, NULL
)) {
170 Py_DECREF(signature
);
171 PyErr_SetString(PyExc_ValueError
,
172 "There must be exactly one complete type in "
173 "an Array's signature parameter");
178 tuple
= Py_BuildValue("(O)", obj
);
180 Py_DECREF(signature
);
183 if ((PyList_Type
.tp_init
)((PyObject
*)self
, tuple
, NULL
) < 0) {
185 Py_DECREF(signature
);
190 Py_XDECREF(self
->signature
);
191 self
->signature
= signature
;
195 PyTypeObject DBusPyArray_Type
= {
196 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
201 (destructor
)Array_tp_dealloc
, /* tp_dealloc */
206 (reprfunc
)Array_tp_repr
, /* tp_repr */
207 0, /* tp_as_number */
208 0, /* tp_as_sequence */
209 0, /* tp_as_mapping */
215 0, /* tp_as_buffer */
216 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
217 Array_tp_doc
, /* tp_doc */
220 0, /* tp_richcompare */
221 0, /* tp_weaklistoffset */
225 Array_tp_members
, /* tp_members */
229 0, /* tp_descr_get */
230 0, /* tp_descr_set */
231 0, /* tp_dictoffset */
232 (initproc
)Array_tp_init
, /* tp_init */
234 Array_tp_new
, /* tp_new */
237 /* Dict ============================================================= */
239 PyDoc_STRVAR(Dict_tp_doc
,
240 "An mapping whose keys are similar and whose values are similar,\n"
241 "implemented as a subtype of dict.\n"
243 "As currently implemented, a Dictionary behaves just like a dict, but\n"
244 "with the addition of a ``signature`` property set by the constructor;\n"
245 "conversion of its items to D-Bus types is only done when it's sent in\n"
246 "a Message. This may change in future so validation is done earlier.\n"
250 " Dictionary(mapping_or_iterable=(), signature=None, variant_level=0)\n"
252 "``variant_level`` must be non-negative; the default is 0.\n"
254 "``signature`` is either a string or None. If a string, it must consist\n"
255 "of exactly two complete type signatures, representing the 'key' type\n"
256 "(which must be a primitive type, i.e. one of \"bdginoqstuxy\")\n"
257 "and the 'value' type. The signature of the whole Dictionary will be\n"
258 "``a{xx}`` where ``xx`` is replaced by the given signature.\n"
260 "If it is None (the default), when the Dictionary is sent over\n"
261 "D-Bus, the key and value signatures will be guessed from an arbitrary\n"
262 "element of the Dictionary.\n"
265 " `variant_level` : int\n"
266 " Indicates how many nested Variant containers this object\n"
267 " is contained in: if a message's wire format has a variant containing a\n"
268 " variant containing an array of DICT_ENTRY, this is represented in\n"
269 " Python by a Dictionary with variant_level==2.\n"
272 static struct PyMemberDef Dict_tp_members
[] = {
273 {"signature", T_OBJECT
, offsetof(DBusPyDict
, signature
), READONLY
,
274 "The D-Bus signature of each key in this Dictionary, followed by "
275 "that of each value in this Dictionary, as a Signature instance."},
276 {"variant_level", T_LONG
, offsetof(DBusPyDict
, variant_level
),
278 "The number of nested variants wrapping the real data. "
279 "0 if not in a variant."},
284 Dict_tp_dealloc (DBusPyDict
*self
)
286 Py_XDECREF(self
->signature
);
287 self
->signature
= NULL
;
288 (PyDict_Type
.tp_dealloc
)((PyObject
*)self
);
292 Dict_tp_repr(DBusPyDict
*self
)
294 PyObject
*parent_repr
= (PyDict_Type
.tp_repr
)((PyObject
*)self
);
295 PyObject
*sig_repr
= PyObject_Repr(self
->signature
);
296 PyObject
*my_repr
= NULL
;
297 long variant_level
= self
->variant_level
;
299 if (!parent_repr
) goto finally
;
300 if (!sig_repr
) goto finally
;
301 if (variant_level
> 0) {
302 my_repr
= PyString_FromFormat("%s(%s, signature=%s, "
303 "variant_level=%ld)",
304 self
->super
.ob_type
->tp_name
,
305 PyString_AS_STRING(parent_repr
),
306 PyString_AS_STRING(sig_repr
),
310 my_repr
= PyString_FromFormat("%s(%s, signature=%s)",
311 self
->super
.ob_type
->tp_name
,
312 PyString_AS_STRING(parent_repr
),
313 PyString_AS_STRING(sig_repr
));
316 Py_XDECREF(parent_repr
);
317 Py_XDECREF(sig_repr
);
322 Dict_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
324 DBusPyDict
*self
= (DBusPyDict
*)(PyDict_Type
.tp_new
)(cls
, args
, kwargs
);
325 PyObject
*variant_level
= NULL
;
327 /* variant_level is immutable, so handle it in __new__ rather than
329 if (!self
) return NULL
;
331 self
->signature
= Py_None
;
332 self
->variant_level
= 0;
334 variant_level
= PyDict_GetItem(kwargs
, dbus_py_variant_level_const
);
337 self
->variant_level
= PyInt_AsLong(variant_level
);
338 if (PyErr_Occurred()) {
339 Py_DECREF((PyObject
*)self
);
343 return (PyObject
*)self
;
347 Dict_tp_init(DBusPyDict
*self
, PyObject
*args
, PyObject
*kwargs
)
349 PyObject
*obj
= dbus_py_empty_tuple
;
350 PyObject
*signature
= NULL
;
352 PyObject
*variant_level
; /* ignored here - __new__ uses it */
353 static char *argnames
[] = {"mapping_or_iterable", "signature",
354 "variant_level", NULL
};
356 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|OOO:__init__", argnames
,
357 &obj
, &signature
, &variant_level
)) {
361 /* convert signature from a borrowed ref of unknown type to an owned ref
362 of type Signature (or None) */
363 if (!signature
) signature
= Py_None
;
364 if (signature
== Py_None
365 || PyObject_IsInstance(signature
, (PyObject
*)&DBusPySignature_Type
)) {
366 Py_INCREF(signature
);
369 signature
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
371 if (!signature
) return -1;
374 if (signature
!= Py_None
) {
375 const char *c_str
= PyString_AS_STRING(signature
);
379 case DBUS_TYPE_BOOLEAN
:
380 case DBUS_TYPE_INT16
:
381 case DBUS_TYPE_UINT16
:
382 case DBUS_TYPE_INT32
:
383 case DBUS_TYPE_UINT32
:
384 case DBUS_TYPE_INT64
:
385 case DBUS_TYPE_UINT64
:
386 case DBUS_TYPE_DOUBLE
:
387 #ifdef WITH_DBUS_FLOAT32
388 case DBUS_TYPE_FLOAT
:
390 case DBUS_TYPE_STRING
:
391 case DBUS_TYPE_OBJECT_PATH
:
392 case DBUS_TYPE_SIGNATURE
:
395 Py_DECREF(signature
);
396 PyErr_SetString(PyExc_ValueError
,
397 "The key type in a Dictionary's signature "
398 "must be a primitive type");
402 if (!dbus_signature_validate_single(c_str
+ 1, NULL
)) {
403 Py_DECREF(signature
);
404 PyErr_SetString(PyExc_ValueError
,
405 "There must be exactly two complete types in "
406 "a Dictionary's signature parameter");
411 tuple
= Py_BuildValue("(O)", obj
);
413 Py_DECREF(signature
);
417 if ((PyDict_Type
.tp_init((PyObject
*)self
, tuple
, NULL
)) < 0) {
419 Py_DECREF(signature
);
424 Py_XDECREF(self
->signature
);
425 self
->signature
= signature
;
429 PyTypeObject DBusPyDict_Type
= {
430 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
435 (destructor
)Dict_tp_dealloc
, /* tp_dealloc */
440 (reprfunc
)Dict_tp_repr
, /* tp_repr */
441 0, /* tp_as_number */
442 0, /* tp_as_sequence */
443 0, /* tp_as_mapping */
449 0, /* tp_as_buffer */
450 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
451 Dict_tp_doc
, /* tp_doc */
454 0, /* tp_richcompare */
455 0, /* tp_weaklistoffset */
459 Dict_tp_members
, /* tp_members */
463 0, /* tp_descr_get */
464 0, /* tp_descr_set */
465 0, /* tp_dictoffset */
466 (initproc
)Dict_tp_init
, /* tp_init */
468 Dict_tp_new
, /* tp_new */
471 /* Struct =========================================================== */
473 static PyObject
*struct_signatures
;
475 PyDoc_STRVAR(Struct_tp_doc
,
476 "An structure containing items of possibly distinct types.\n"
480 " dbus.Struct(iterable, signature=None, variant_level=0) -> Struct\n"
482 "D-Bus structs may not be empty, so the iterable argument is required and\n"
483 "may not be an empty iterable.\n"
485 "``signature`` is either None, or a string representing the contents of the\n"
486 "struct as one or more complete type signatures. The overall signature of\n"
487 "the struct will be the given signature enclosed in parentheses, ``()``.\n"
489 "If the signature is None (default) it will be guessed\n"
490 "from the types of the items during construction.\n"
492 "``variant_level`` must be non-negative; the default is 0.\n"
495 " `variant_level` : int\n"
496 " Indicates how many nested Variant containers this object\n"
497 " is contained in: if a message's wire format has a variant containing a\n"
498 " variant containing a struct, this is represented in Python by a\n"
499 " Struct with variant_level==2.\n"
503 Struct_tp_repr(PyObject
*self
)
505 PyObject
*parent_repr
= (PyTuple_Type
.tp_repr
)((PyObject
*)self
);
507 PyObject
*sig_repr
= NULL
;
510 PyObject
*my_repr
= NULL
;
512 if (!parent_repr
) goto finally
;
513 key
= PyLong_FromVoidPtr(self
);
514 if (!key
) goto finally
;
515 sig
= PyDict_GetItem(struct_signatures
, key
);
517 if (!sig
) sig
= Py_None
;
518 sig_repr
= PyObject_Repr(sig
);
519 if (!sig_repr
) goto finally
;
520 variant_level
= dbus_py_variant_level_get(self
);
521 if (variant_level
> 0) {
522 my_repr
= PyString_FromFormat("%s(%s, signature=%s, "
523 "variant_level=%ld)",
524 self
->ob_type
->tp_name
,
525 PyString_AS_STRING(parent_repr
),
526 PyString_AS_STRING(sig_repr
),
530 my_repr
= PyString_FromFormat("%s(%s, signature=%s)",
531 self
->ob_type
->tp_name
,
532 PyString_AS_STRING(parent_repr
),
533 PyString_AS_STRING(sig_repr
));
537 Py_XDECREF(parent_repr
);
538 Py_XDECREF(sig_repr
);
543 Struct_tp_new (PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
545 PyObject
*signature
= NULL
;
546 long variantness
= 0;
547 PyObject
*self
, *key
;
548 static char *argnames
[] = {"signature", "variant_level", NULL
};
550 if (PyTuple_Size(args
) != 1) {
551 PyErr_SetString(PyExc_TypeError
,
552 "__new__ takes exactly one positional parameter");
555 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple
, kwargs
,
556 "|Ol:__new__", argnames
,
557 &signature
, &variantness
)) {
560 if (variantness
< 0) {
561 PyErr_SetString(PyExc_ValueError
,
562 "variant_level must be non-negative");
566 self
= (PyTuple_Type
.tp_new
)(cls
, args
, NULL
);
569 if (PyTuple_Size(self
) < 1) {
570 PyErr_SetString(PyExc_ValueError
, "D-Bus structs may not be empty");
575 if (!dbus_py_variant_level_set(self
, variantness
)) {
580 /* convert signature from a borrowed ref of unknown type to an owned ref
581 of type Signature (or None) */
582 if (!signature
) signature
= Py_None
;
583 if (signature
== Py_None
584 || PyObject_IsInstance(signature
, (PyObject
*)&DBusPySignature_Type
)) {
585 Py_INCREF(signature
);
588 signature
= PyObject_CallFunction((PyObject
*)&DBusPySignature_Type
,
596 key
= PyLong_FromVoidPtr(self
);
599 Py_DECREF(signature
);
602 if (PyDict_SetItem(struct_signatures
, key
, signature
) < 0) {
605 Py_DECREF(signature
);
610 Py_DECREF(signature
);
615 Struct_tp_dealloc(PyObject
*self
)
617 PyObject
*et
, *ev
, *etb
, *key
;
619 dbus_py_variant_level_clear(self
);
620 PyErr_Fetch(&et
, &ev
, &etb
);
622 key
= PyLong_FromVoidPtr(self
);
624 if (PyDict_GetItem(struct_signatures
, key
)) {
625 if (PyDict_DelItem(struct_signatures
, key
) < 0) {
626 /* should never happen */
627 PyErr_WriteUnraisable(self
);
633 /* not enough memory to free all the memory... leak the signature,
634 * there's not much else we could do here */
635 PyErr_WriteUnraisable(self
);
638 PyErr_Restore(et
, ev
, etb
);
639 (PyTuple_Type
.tp_dealloc
)(self
);
643 Struct_tp_getattro(PyObject
*obj
, PyObject
*name
)
645 PyObject
*key
, *value
;
647 if (PyString_Check(name
)) {
650 else if (PyUnicode_Check(name
)) {
651 name
= PyUnicode_AsEncodedString(name
, NULL
, NULL
);
657 PyErr_SetString(PyExc_TypeError
, "attribute name must be string");
661 if (strcmp(PyString_AS_STRING(name
), "signature")) {
662 value
= dbus_py_variant_level_getattro(obj
, name
);
669 key
= PyLong_FromVoidPtr(obj
);
675 value
= PyDict_GetItem(struct_signatures
, key
);
684 PyTypeObject DBusPyStruct_Type
= {
685 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
690 Struct_tp_dealloc
, /* tp_dealloc */
695 (reprfunc
)Struct_tp_repr
, /* tp_repr */
696 0, /* tp_as_number */
697 0, /* tp_as_sequence */
698 0, /* tp_as_mapping */
702 Struct_tp_getattro
, /* tp_getattro */
703 dbus_py_immutable_setattro
, /* tp_setattro */
704 0, /* tp_as_buffer */
705 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /* tp_flags */
706 Struct_tp_doc
, /* tp_doc */
709 0, /* tp_richcompare */
710 0, /* tp_weaklistoffset */
718 0, /* tp_descr_get */
719 0, /* tp_descr_set */
720 0, /* tp_dictoffset */
723 Struct_tp_new
, /* tp_new */
727 dbus_py_init_container_types(void)
729 struct_signatures
= PyDict_New();
730 if (!struct_signatures
) return 0;
732 DBusPyArray_Type
.tp_base
= &PyList_Type
;
733 if (PyType_Ready(&DBusPyArray_Type
) < 0) return 0;
734 DBusPyArray_Type
.tp_print
= NULL
;
736 DBusPyDict_Type
.tp_base
= &PyDict_Type
;
737 if (PyType_Ready(&DBusPyDict_Type
) < 0) return 0;
738 DBusPyDict_Type
.tp_print
= NULL
;
740 DBusPyStruct_Type
.tp_base
= &PyTuple_Type
;
741 if (PyType_Ready(&DBusPyStruct_Type
) < 0) return 0;
742 DBusPyStruct_Type
.tp_print
= NULL
;
748 dbus_py_insert_container_types(PyObject
*this_module
)
750 Py_INCREF(&DBusPyArray_Type
);
751 if (PyModule_AddObject(this_module
, "Array",
752 (PyObject
*)&DBusPyArray_Type
) < 0) return 0;
754 Py_INCREF(&DBusPyDict_Type
);
755 if (PyModule_AddObject(this_module
, "Dictionary",
756 (PyObject
*)&DBusPyDict_Type
) < 0) return 0;
758 Py_INCREF(&DBusPyStruct_Type
);
759 if (PyModule_AddObject(this_module
, "Struct",
760 (PyObject
*)&DBusPyStruct_Type
) < 0) return 0;
765 /* vim:set ft=c cino< sw=4 sts=4 et: */