Add wrapper for DBusServer.
[dbus-python-phuang.git] / _dbus_bindings / abstract.c
blob9a4f350424e83b568928f36b27841bae7e9f589e
1 /* Subclasses of built-in Python types supporting extra D-Bus functionality.
3 * Copyright (C) 2006-2007 Collabora Ltd. <http://www.collabora.co.uk/>
5 * Permission is hereby granted, free of charge, to any person
6 * obtaining a copy of this software and associated documentation
7 * files (the "Software"), to deal in the Software without
8 * restriction, including without limitation the rights to use, copy,
9 * modify, merge, publish, distribute, sublicense, and/or sell copies
10 * of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
26 #include <Python.h>
27 #include <structmember.h>
29 #include <stdint.h>
31 #include "dbus_bindings-internal.h"
32 #include "types-internal.h"
34 /* Dict indexed by object IDs, whose values are nonzero variant levels
35 * for immutable variable-sized D-Bus data types (_LongBase, _StrBase, Struct).
37 * This is a strange way to store them, but adding a __dict__ to the offending
38 * objects seems even more error-prone, given that their sizes are variable!
40 PyObject *_dbus_py_variant_levels = NULL;
42 long
43 dbus_py_variant_level_get(PyObject *obj)
45 PyObject *vl_obj;
46 PyObject *key = PyLong_FromVoidPtr(obj);
48 if (!key) {
49 return 0;
52 vl_obj = PyDict_GetItem(_dbus_py_variant_levels, key);
53 Py_DECREF(key);
55 if (!vl_obj)
56 return 0;
57 return PyInt_AsLong(vl_obj);
60 dbus_bool_t
61 dbus_py_variant_level_set(PyObject *obj, long variant_level)
63 /* key is the object's ID (= pointer) to avoid referencing it */
64 PyObject *key = PyLong_FromVoidPtr(obj);
66 if (!key) {
67 return FALSE;
70 if (variant_level <= 0) {
71 if (PyDict_GetItem (_dbus_py_variant_levels, key)) {
72 if (PyDict_DelItem (_dbus_py_variant_levels, key) < 0) {
73 Py_DECREF(key);
74 return FALSE;
78 else {
79 PyObject *vl_obj = PyInt_FromLong(variant_level);
80 if (!vl_obj) {
81 Py_DECREF(key);
82 return FALSE;
84 if (PyDict_SetItem (_dbus_py_variant_levels, key, vl_obj) < 0) {
85 Py_DECREF(key);
86 return FALSE;
89 Py_DECREF(key);
90 return TRUE;
93 PyObject *
94 dbus_py_variant_level_getattro(PyObject *obj, PyObject *name)
96 PyObject *key, *value;
98 if (PyString_Check(name)) {
99 Py_INCREF(name);
101 else if (PyUnicode_Check(name)) {
102 name = PyUnicode_AsEncodedString(name, NULL, NULL);
103 if (!name) {
104 return NULL;
107 else {
108 PyErr_SetString(PyExc_TypeError, "attribute name must be string");
109 return NULL;
112 if (strcmp(PyString_AS_STRING(name), "variant_level")) {
113 value = PyObject_GenericGetAttr(obj, name);
114 Py_DECREF(name);
115 return value;
118 Py_DECREF(name);
120 key = PyLong_FromVoidPtr(obj);
122 if (!key) {
123 return NULL;
126 value = PyDict_GetItem(_dbus_py_variant_levels, key);
127 Py_DECREF(key);
129 if (!value)
130 return PyInt_FromLong(0);
131 Py_INCREF(value);
132 return value;
135 /* To be invoked by destructors. Clear the variant level without touching the
136 * exception state */
137 void
138 dbus_py_variant_level_clear(PyObject *self)
140 PyObject *et, *ev, *etb;
142 /* avoid clobbering any pending exception */
143 PyErr_Fetch(&et, &ev, &etb);
144 if (!dbus_py_variant_level_set(self, 0)) {
145 /* should never happen */
146 PyErr_WriteUnraisable(self);
148 PyErr_Restore(et, ev, etb);
151 /* Support code for int subclasses. ================================== */
153 PyDoc_STRVAR(DBusPythonInt_tp_doc,\
154 "Base class for int subclasses with a ``variant_level`` attribute.\n"
155 "Do not rely on the existence of this class outside dbus-python.\n"
158 static PyMemberDef DBusPythonInt_tp_members[] = {
159 {"variant_level", T_LONG, offsetof(DBusPyIntBase, variant_level),
160 READONLY,
161 "The number of nested variants wrapping the real data. "
162 "0 if not in a variant."},
163 {NULL},
166 static PyObject *
167 DBusPythonInt_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
169 PyObject *self;
170 long variantness = 0;
171 static char *argnames[] = {"variant_level", NULL};
173 if (PyTuple_Size(args) > 1) {
174 PyErr_SetString(PyExc_TypeError,
175 "__new__ takes at most one positional parameter");
176 return NULL;
178 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
179 "|l:__new__", argnames,
180 &variantness)) return NULL;
181 if (variantness < 0) {
182 PyErr_SetString(PyExc_ValueError,
183 "variant_level must be non-negative");
184 return NULL;
187 self = (PyInt_Type.tp_new)(cls, args, NULL);
188 if (self) {
189 ((DBusPyIntBase *)self)->variant_level = variantness;
191 return self;
194 static PyObject *
195 DBusPythonInt_tp_repr(PyObject *self)
197 PyObject *parent_repr = (PyInt_Type.tp_repr)(self);
198 long variant_level = ((DBusPyIntBase *)self)->variant_level;
199 PyObject *my_repr;
201 if (!parent_repr) return NULL;
202 if (variant_level > 0) {
203 my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)",
204 self->ob_type->tp_name,
205 PyString_AS_STRING(parent_repr),
206 variant_level);
208 else {
209 my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
210 PyString_AS_STRING(parent_repr));
212 /* whether my_repr is NULL or not: */
213 Py_DECREF(parent_repr);
214 return my_repr;
217 PyTypeObject DBusPyIntBase_Type = {
218 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
220 "_dbus_bindings._IntBase",
221 sizeof(DBusPyIntBase),
223 0, /* tp_dealloc */
224 0, /* tp_print */
225 0, /* tp_getattr */
226 0, /* tp_setattr */
227 0, /* tp_compare */
228 DBusPythonInt_tp_repr, /* tp_repr */
229 0, /* tp_as_number */
230 0, /* tp_as_sequence */
231 0, /* tp_as_mapping */
232 0, /* tp_hash */
233 0, /* tp_call */
234 0, /* tp_str */
235 0, /* tp_getattro */
236 0, /* tp_setattro */
237 0, /* tp_as_buffer */
238 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
239 DBusPythonInt_tp_doc, /* tp_doc */
240 0, /* tp_traverse */
241 0, /* tp_clear */
242 0, /* tp_richcompare */
243 0, /* tp_weaklistoffset */
244 0, /* tp_iter */
245 0, /* tp_iternext */
246 0, /* tp_methods */
247 DBusPythonInt_tp_members, /* tp_members */
248 0, /* tp_getset */
249 DEFERRED_ADDRESS(&PyInt_Type), /* tp_base */
250 0, /* tp_dict */
251 0, /* tp_descr_get */
252 0, /* tp_descr_set */
253 0, /* tp_dictoffset */
254 0, /* tp_init */
255 PyType_GenericAlloc, /* tp_alloc */
256 DBusPythonInt_tp_new, /* tp_new */
257 PyObject_Del, /* tp_free */
260 /* Support code for float subclasses. ================================ */
262 /* There's only one subclass at the moment (Double) but these are factored
263 out to make room for Float later. (Float is implemented and #if'd out) */
265 PyDoc_STRVAR(DBusPythonFloat_tp_doc,\
266 "Base class for float subclasses with a ``variant_level`` attribute.\n"
267 "Do not rely on the existence of this class outside dbus-python.\n"
270 static PyMemberDef DBusPythonFloat_tp_members[] = {
271 {"variant_level", T_LONG, offsetof(DBusPyFloatBase, variant_level),
272 READONLY,
273 "The number of nested variants wrapping the real data. "
274 "0 if not in a variant."},
275 {NULL},
278 static PyObject *
279 DBusPythonFloat_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
281 PyObject *self;
282 long variantness = 0;
283 static char *argnames[] = {"variant_level", NULL};
285 if (PyTuple_Size(args) > 1) {
286 PyErr_SetString(PyExc_TypeError,
287 "__new__ takes at most one positional parameter");
288 return NULL;
290 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
291 "|l:__new__", argnames,
292 &variantness)) return NULL;
293 if (variantness < 0) {
294 PyErr_SetString(PyExc_ValueError,
295 "variant_level must be non-negative");
296 return NULL;
299 self = (PyFloat_Type.tp_new)(cls, args, NULL);
300 if (self) {
301 ((DBusPyFloatBase *)self)->variant_level = variantness;
303 return self;
306 static PyObject *
307 DBusPythonFloat_tp_repr(PyObject *self)
309 PyObject *parent_repr = (PyFloat_Type.tp_repr)(self);
310 long variant_level = ((DBusPyFloatBase *)self)->variant_level;
311 PyObject *my_repr;
313 if (!parent_repr) return NULL;
314 if (variant_level > 0) {
315 my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)",
316 self->ob_type->tp_name,
317 PyString_AS_STRING(parent_repr),
318 variant_level);
320 else {
321 my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
322 PyString_AS_STRING(parent_repr));
324 /* whether my_repr is NULL or not: */
325 Py_DECREF(parent_repr);
326 return my_repr;
329 PyTypeObject DBusPyFloatBase_Type = {
330 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
332 "_dbus_bindings._FloatBase",
333 sizeof(DBusPyFloatBase),
335 0, /* tp_dealloc */
336 0, /* tp_print */
337 0, /* tp_getattr */
338 0, /* tp_setattr */
339 0, /* tp_compare */
340 DBusPythonFloat_tp_repr, /* tp_repr */
341 0, /* tp_as_number */
342 0, /* tp_as_sequence */
343 0, /* tp_as_mapping */
344 0, /* tp_hash */
345 0, /* tp_call */
346 0, /* tp_str */
347 0, /* tp_getattro */
348 0, /* tp_setattro */
349 0, /* tp_as_buffer */
350 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
351 DBusPythonFloat_tp_doc, /* tp_doc */
352 0, /* tp_traverse */
353 0, /* tp_clear */
354 0, /* tp_richcompare */
355 0, /* tp_weaklistoffset */
356 0, /* tp_iter */
357 0, /* tp_iternext */
358 0, /* tp_methods */
359 DBusPythonFloat_tp_members, /* tp_members */
360 0, /* tp_getset */
361 DEFERRED_ADDRESS(&PyFloat_Type), /* tp_base */
362 0, /* tp_dict */
363 0, /* tp_descr_get */
364 0, /* tp_descr_set */
365 0, /* tp_dictoffset */
366 0, /* tp_init */
367 0, /* tp_alloc */
368 DBusPythonFloat_tp_new, /* tp_new */
371 /* Support code for str subclasses ================================== */
373 PyDoc_STRVAR(DBusPythonString_tp_doc,\
374 "Base class for str subclasses with a ``variant_level`` attribute.\n"
375 "Do not rely on the existence of this class outside dbus-python.\n"
378 static PyObject *
379 DBusPythonString_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
381 PyObject *self;
382 long variantness = 0;
383 static char *argnames[] = {"variant_level", NULL};
385 if (PyTuple_Size(args) > 1) {
386 PyErr_SetString(PyExc_TypeError,
387 "__new__ takes at most one positional parameter");
388 return NULL;
390 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
391 "|l:__new__", argnames,
392 &variantness)) return NULL;
393 if (variantness < 0) {
394 PyErr_SetString(PyExc_ValueError,
395 "variant_level must be non-negative");
396 return NULL;
399 self = (PyString_Type.tp_new)(cls, args, NULL);
400 if (self) {
401 if (!dbus_py_variant_level_set(self, variantness)) {
402 Py_DECREF(self);
403 return NULL;
406 return self;
409 static PyObject *
410 DBusPythonString_tp_repr(PyObject *self)
412 PyObject *parent_repr = (PyString_Type.tp_repr)(self);
413 PyObject *vl_obj;
414 PyObject *my_repr;
415 long variant_level;
417 if (!parent_repr) return NULL;
418 vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const);
419 if (!vl_obj) {
420 Py_DECREF(parent_repr);
421 return NULL;
423 variant_level = PyInt_AsLong(vl_obj);
424 Py_DECREF(vl_obj);
425 if (variant_level > 0) {
426 my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)",
427 self->ob_type->tp_name,
428 PyString_AS_STRING(parent_repr),
429 variant_level);
431 else {
432 my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
433 PyString_AS_STRING(parent_repr));
435 /* whether my_repr is NULL or not: */
436 Py_DECREF(parent_repr);
437 return my_repr;
440 static void
441 DBusPyStrBase_tp_dealloc(PyObject *self)
443 dbus_py_variant_level_clear(self);
444 (PyString_Type.tp_dealloc)(self);
447 PyTypeObject DBusPyStrBase_Type = {
448 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
450 "_dbus_bindings._StrBase",
453 DBusPyStrBase_tp_dealloc, /* tp_dealloc */
454 0, /* tp_print */
455 0, /* tp_getattr */
456 0, /* tp_setattr */
457 0, /* tp_compare */
458 DBusPythonString_tp_repr, /* tp_repr */
459 0, /* tp_as_number */
460 0, /* tp_as_sequence */
461 0, /* tp_as_mapping */
462 0, /* tp_hash */
463 0, /* tp_call */
464 0, /* tp_str */
465 dbus_py_variant_level_getattro, /* tp_getattro */
466 dbus_py_immutable_setattro, /* tp_setattro */
467 0, /* tp_as_buffer */
468 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
469 DBusPythonString_tp_doc, /* tp_doc */
470 0, /* tp_traverse */
471 0, /* tp_clear */
472 0, /* tp_richcompare */
473 0, /* tp_weaklistoffset */
474 0, /* tp_iter */
475 0, /* tp_iternext */
476 0, /* tp_methods */
477 0, /* tp_members */
478 0, /* tp_getset */
479 DEFERRED_ADDRESS(&PyString_Type), /* tp_base */
480 0, /* tp_dict */
481 0, /* tp_descr_get */
482 0, /* tp_descr_set */
483 0, /* tp_dictoffset */
484 0, /* tp_init */
485 0, /* tp_alloc */
486 DBusPythonString_tp_new, /* tp_new */
489 /* Support code for long subclasses ================================= */
491 PyDoc_STRVAR(DBusPythonLong_tp_doc,\
492 "Base class for ``long`` subclasses with a ``variant_level`` attribute.\n"
493 "Do not rely on the existence of this class outside dbus-python.\n"
496 static PyObject *
497 DBusPythonLong_tp_new(PyTypeObject *cls, PyObject *args, PyObject *kwargs)
499 PyObject *self;
500 long variantness = 0;
501 static char *argnames[] = {"variant_level", NULL};
503 if (PyTuple_Size(args) > 1) {
504 PyErr_SetString(PyExc_TypeError,
505 "__new__ takes at most one positional parameter");
506 return NULL;
508 if (!PyArg_ParseTupleAndKeywords(dbus_py_empty_tuple, kwargs,
509 "|l:__new__", argnames,
510 &variantness)) return NULL;
511 if (variantness < 0) {
512 PyErr_SetString(PyExc_ValueError,
513 "variant_level must be non-negative");
514 return NULL;
517 self = (PyLong_Type.tp_new)(cls, args, NULL);
518 if (self) {
519 if (!dbus_py_variant_level_set(self, variantness)) {
520 Py_DECREF(self);
521 return NULL;
524 return self;
527 static PyObject *
528 DBusPythonLong_tp_repr(PyObject *self)
530 PyObject *parent_repr = (PyLong_Type.tp_repr)(self);
531 PyObject *vl_obj;
532 PyObject *my_repr;
533 long variant_level;
535 if (!parent_repr) return NULL;
536 vl_obj = PyObject_GetAttr(self, dbus_py_variant_level_const);
537 if (!vl_obj) {
538 Py_DECREF(parent_repr);
539 return NULL;
541 variant_level = PyInt_AsLong(vl_obj);
542 Py_DECREF(vl_obj);
543 if (variant_level) {
544 my_repr = PyString_FromFormat("%s(%s, variant_level=%ld)",
545 self->ob_type->tp_name,
546 PyString_AS_STRING(parent_repr),
547 variant_level);
549 else {
550 my_repr = PyString_FromFormat("%s(%s)", self->ob_type->tp_name,
551 PyString_AS_STRING(parent_repr));
553 /* whether my_repr is NULL or not: */
554 Py_DECREF(parent_repr);
555 return my_repr;
558 static void
559 DBusPyLongBase_tp_dealloc(PyObject *self)
561 dbus_py_variant_level_clear(self);
562 (PyLong_Type.tp_dealloc)(self);
565 PyTypeObject DBusPyLongBase_Type = {
566 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
568 "_dbus_bindings._LongBase",
571 DBusPyLongBase_tp_dealloc, /* tp_dealloc */
572 0, /* tp_print */
573 0, /* tp_getattr */
574 0, /* tp_setattr */
575 0, /* tp_compare */
576 DBusPythonLong_tp_repr, /* tp_repr */
577 0, /* tp_as_number */
578 0, /* tp_as_sequence */
579 0, /* tp_as_mapping */
580 0, /* tp_hash */
581 0, /* tp_call */
582 0, /* tp_str */
583 dbus_py_variant_level_getattro, /* tp_getattro */
584 dbus_py_immutable_setattro, /* tp_setattro */
585 0, /* tp_as_buffer */
586 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
587 DBusPythonLong_tp_doc, /* tp_doc */
588 0, /* tp_traverse */
589 0, /* tp_clear */
590 0, /* tp_richcompare */
591 0, /* tp_weaklistoffset */
592 0, /* tp_iter */
593 0, /* tp_iternext */
594 0, /* tp_methods */
595 0, /* tp_members */
596 0, /* tp_getset */
597 DEFERRED_ADDRESS(&PyLong_Type), /* tp_base */
598 0, /* tp_dict */
599 0, /* tp_descr_get */
600 0, /* tp_descr_set */
601 0, /* tp_dictoffset */
602 0, /* tp_init */
603 0, /* tp_alloc */
604 DBusPythonLong_tp_new, /* tp_new */
607 PyObject *dbus_py_variant_level_const = NULL;
608 PyObject *dbus_py_signature_const = NULL;
609 PyObject *dbus_py__dbus_object_path__const = NULL;
611 dbus_bool_t
612 dbus_py_init_abstract(void)
614 _dbus_py_variant_levels = PyDict_New();
615 if (!_dbus_py_variant_levels) return 0;
617 dbus_py__dbus_object_path__const = PyString_InternFromString("__dbus_object_path__");
618 if (!dbus_py__dbus_object_path__const) return 0;
620 dbus_py_variant_level_const = PyString_InternFromString("variant_level");
621 if (!dbus_py_variant_level_const) return 0;
623 dbus_py_signature_const = PyString_InternFromString("signature");
624 if (!dbus_py_signature_const) return 0;
626 DBusPyIntBase_Type.tp_base = &PyInt_Type;
627 if (PyType_Ready(&DBusPyIntBase_Type) < 0) return 0;
628 /* disable the tp_print copied from PyInt_Type, so tp_repr gets called as
629 desired */
630 DBusPyIntBase_Type.tp_print = NULL;
632 DBusPyFloatBase_Type.tp_base = &PyFloat_Type;
633 if (PyType_Ready(&DBusPyFloatBase_Type) < 0) return 0;
634 DBusPyFloatBase_Type.tp_print = NULL;
636 DBusPyLongBase_Type.tp_base = &PyLong_Type;
637 if (PyType_Ready(&DBusPyLongBase_Type) < 0) return 0;
638 DBusPyLongBase_Type.tp_print = NULL;
640 DBusPyStrBase_Type.tp_base = &PyString_Type;
641 if (PyType_Ready(&DBusPyStrBase_Type) < 0) return 0;
642 DBusPyStrBase_Type.tp_print = NULL;
644 return 1;
647 dbus_bool_t
648 dbus_py_insert_abstract_types(PyObject *this_module)
650 Py_INCREF(&DBusPyIntBase_Type);
651 Py_INCREF(&DBusPyLongBase_Type);
652 Py_INCREF(&DBusPyStrBase_Type);
653 Py_INCREF(&DBusPyFloatBase_Type);
654 if (PyModule_AddObject(this_module, "_IntBase",
655 (PyObject *)&DBusPyIntBase_Type) < 0) return 0;
656 if (PyModule_AddObject(this_module, "_LongBase",
657 (PyObject *)&DBusPyLongBase_Type) < 0) return 0;
658 if (PyModule_AddObject(this_module, "_StrBase",
659 (PyObject *)&DBusPyStrBase_Type) < 0) return 0;
660 if (PyModule_AddObject(this_module, "_FloatBase",
661 (PyObject *)&DBusPyFloatBase_Type) < 0) return 0;
663 return 1;