1 # SPDX-License-Identifier: MIT
3 # Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
5 from bt2
import native_bt
, object, utils
14 def _create_from_ptr_template(ptr
, object_map
):
18 # bt_value_null is translated to None. However, we are given a reference
19 # to it that we are not going to manage anymore, since we don't create a
20 # Python wrapper for it. Therefore put that reference immediately.
21 if ptr
== native_bt
.value_null
:
25 typeid
= native_bt
.value_get_type(ptr
)
26 return object_map
[typeid
]._create
_from
_ptr
(ptr
)
29 def _create_from_ptr(ptr
):
30 return _create_from_ptr_template(ptr
, _TYPE_TO_OBJ
)
33 def _create_from_const_ptr(ptr
):
34 return _create_from_ptr_template(ptr
, _TYPE_TO_CONST_OBJ
)
37 def _create_from_ptr_and_get_ref_template(ptr
, object_map
):
38 if ptr
is None or ptr
== native_bt
.value_null
:
41 typeid
= native_bt
.value_get_type(ptr
)
42 return object_map
[typeid
]._create
_from
_ptr
_and
_get
_ref
(ptr
)
45 def _create_from_ptr_and_get_ref(ptr
):
46 return _create_from_ptr_and_get_ref_template(ptr
, _TYPE_TO_OBJ
)
49 def _create_from_const_ptr_and_get_ref(ptr
):
50 return _create_from_ptr_and_get_ref_template(ptr
, _TYPE_TO_CONST_OBJ
)
53 def create_value(value
):
58 if isinstance(value
, _Value
):
61 if isinstance(value
, bool):
62 return BoolValue(value
)
64 if isinstance(value
, numbers
.Integral
):
65 return SignedIntegerValue(value
)
67 if isinstance(value
, numbers
.Real
):
68 return RealValue(value
)
70 if isinstance(value
, str):
71 return StringValue(value
)
73 if isinstance(value
, collections
.abc
.Sequence
):
74 return ArrayValue(value
)
76 if isinstance(value
, collections
.abc
.Mapping
):
77 return MapValue(value
)
80 "cannot create value object from '{}' object".format(value
.__class
__.__name
__)
84 class _ValueConst(object._SharedObject
, metaclass
=abc
.ABCMeta
):
85 _get_ref
= staticmethod(native_bt
.value_get_ref
)
86 _put_ref
= staticmethod(native_bt
.value_put_ref
)
87 _create_value_from_ptr
= staticmethod(_create_from_const_ptr
)
88 _create_value_from_ptr_and_get_ref
= staticmethod(
89 _create_from_const_ptr_and_get_ref
92 def __ne__(self
, other
):
93 return not (self
== other
)
95 def _check_create_status(self
, ptr
):
97 raise bt2
._MemoryError(
98 'cannot create {} value object'.format(self
._NAME
.lower())
102 class _Value(_ValueConst
):
103 _create_value_from_ptr
= staticmethod(_create_from_ptr
)
104 _create_value_from_ptr_and_get_ref
= staticmethod(_create_from_ptr_and_get_ref
)
107 @functools.total_ordering
108 class _NumericValueConst(_ValueConst
):
110 def _extract_value(other
):
111 if isinstance(other
, _BoolValueConst
) or isinstance(other
, bool):
114 if isinstance(other
, numbers
.Integral
):
117 if isinstance(other
, numbers
.Real
):
120 if isinstance(other
, numbers
.Complex
):
121 return complex(other
)
124 "'{}' object is not a number object".format(other
.__class
__.__name
__)
128 return int(self
._value
)
131 return float(self
._value
)
134 return repr(self
._value
)
136 def __lt__(self
, other
):
137 return self
._value
< self
._extract
_value
(other
)
139 def __eq__(self
, other
):
141 return self
._value
== self
._extract
_value
(other
)
145 def __rmod__(self
, other
):
146 return self
._extract
_value
(other
) % self
._value
148 def __mod__(self
, other
):
149 return self
._value
% self
._extract
_value
(other
)
151 def __rfloordiv__(self
, other
):
152 return self
._extract
_value
(other
) // self
._value
154 def __floordiv__(self
, other
):
155 return self
._value
// self
._extract
_value
(other
)
157 def __round__(self
, ndigits
=None):
159 return round(self
._value
)
161 return round(self
._value
, ndigits
)
164 return math
.ceil(self
._value
)
167 return math
.floor(self
._value
)
170 return int(self
._value
)
173 return abs(self
._value
)
175 def __add__(self
, other
):
176 return self
._value
+ self
._extract
_value
(other
)
178 def __radd__(self
, other
):
179 return self
.__add
__(other
)
187 def __mul__(self
, other
):
188 return self
._value
* self
._extract
_value
(other
)
190 def __rmul__(self
, other
):
191 return self
.__mul
__(other
)
193 def __truediv__(self
, other
):
194 return self
._value
/ self
._extract
_value
(other
)
196 def __rtruediv__(self
, other
):
197 return self
._extract
_value
(other
) / self
._value
199 def __pow__(self
, exponent
):
200 return self
._value
** self
._extract
_value
(exponent
)
202 def __rpow__(self
, base
):
203 return self
._extract
_value
(base
) ** self
._value
206 class _NumericValue(_NumericValueConst
, _Value
):
210 class _IntegralValueConst(_NumericValueConst
, numbers
.Integral
):
211 def __lshift__(self
, other
):
212 return self
._value
<< self
._extract
_value
(other
)
214 def __rlshift__(self
, other
):
215 return self
._extract
_value
(other
) << self
._value
217 def __rshift__(self
, other
):
218 return self
._value
>> self
._extract
_value
(other
)
220 def __rrshift__(self
, other
):
221 return self
._extract
_value
(other
) >> self
._value
223 def __and__(self
, other
):
224 return self
._value
& self
._extract
_value
(other
)
226 def __rand__(self
, other
):
227 return self
._extract
_value
(other
) & self
._value
229 def __xor__(self
, other
):
230 return self
._value ^ self
._extract
_value
(other
)
232 def __rxor__(self
, other
):
233 return self
._extract
_value
(other
) ^ self
._value
235 def __or__(self
, other
):
236 return self
._value | self
._extract
_value
(other
)
238 def __ror__(self
, other
):
239 return self
._extract
_value
(other
) | self
._value
241 def __invert__(self
):
245 class _IntegralValue(_IntegralValueConst
, _NumericValue
):
249 class _BoolValueConst(_IntegralValueConst
):
250 _NAME
= 'Const boolean'
256 return repr(self
._value
)
260 value
= native_bt
.value_bool_get(self
._ptr
)
264 class BoolValue(_BoolValueConst
, _IntegralValue
):
267 def __init__(self
, value
=None):
269 ptr
= native_bt
.value_bool_create()
271 ptr
= native_bt
.value_bool_create_init(self
._value
_to
_bool
(value
))
273 self
._check
_create
_status
(ptr
)
274 super().__init
__(ptr
)
277 def _value_to_bool(cls
, value
):
278 if isinstance(value
, _BoolValueConst
):
281 if not isinstance(value
, bool):
283 "'{}' object is not a 'bool', 'BoolValue', or '_BoolValueConst' object".format(
290 def _set_value(self
, value
):
291 native_bt
.value_bool_set(self
._ptr
, self
._value
_to
_bool
(value
))
293 value
= property(fset
=_set_value
)
296 class _IntegerValueConst(_IntegralValueConst
):
299 return self
._get
_value
(self
._ptr
)
302 class _IntegerValue(_IntegerValueConst
, _IntegralValue
):
303 def __init__(self
, value
=None):
305 ptr
= self
._create
_default
_value
()
307 ptr
= self
._create
_value
(self
._value
_to
_int
(value
))
309 self
._check
_create
_status
(ptr
)
310 super().__init
__(ptr
)
313 def _value_to_int(cls
, value
):
314 if not isinstance(value
, numbers
.Integral
):
315 raise TypeError('expecting an integral number object')
318 cls
._check
_int
_range
(value
)
321 def _prop_set_value(self
, value
):
322 self
._set
_value
(self
._ptr
, self
._value
_to
_int
(value
))
324 value
= property(fset
=_prop_set_value
)
327 class _UnsignedIntegerValueConst(_IntegerValueConst
):
328 _NAME
= 'Const unsigned integer'
329 _get_value
= staticmethod(native_bt
.value_integer_unsigned_get
)
332 class UnsignedIntegerValue(_UnsignedIntegerValueConst
, _IntegerValue
):
333 _NAME
= 'Unsigned integer'
334 _check_int_range
= staticmethod(utils
._check
_uint
64)
335 _create_default_value
= staticmethod(native_bt
.value_integer_unsigned_create
)
336 _create_value
= staticmethod(native_bt
.value_integer_unsigned_create_init
)
337 _set_value
= staticmethod(native_bt
.value_integer_unsigned_set
)
340 class _SignedIntegerValueConst(_IntegerValueConst
):
341 _NAME
= 'Const signed integer'
342 _get_value
= staticmethod(native_bt
.value_integer_signed_get
)
345 class SignedIntegerValue(_SignedIntegerValueConst
, _IntegerValue
):
346 _NAME
= 'Signed integer'
347 _check_int_range
= staticmethod(utils
._check
_int
64)
348 _create_default_value
= staticmethod(native_bt
.value_integer_signed_create
)
349 _create_value
= staticmethod(native_bt
.value_integer_signed_create_init
)
350 _set_value
= staticmethod(native_bt
.value_integer_signed_set
)
353 class _RealValueConst(_NumericValueConst
, numbers
.Real
):
354 _NAME
= 'Const real number'
358 return native_bt
.value_real_get(self
._ptr
)
361 class RealValue(_RealValueConst
, _NumericValue
):
362 _NAME
= 'Real number'
364 def __init__(self
, value
=None):
366 ptr
= native_bt
.value_real_create()
368 value
= self
._value
_to
_float
(value
)
369 ptr
= native_bt
.value_real_create_init(value
)
371 self
._check
_create
_status
(ptr
)
372 super().__init
__(ptr
)
375 def _value_to_float(cls
, value
):
376 if not isinstance(value
, numbers
.Real
):
377 raise TypeError("expecting a real number object")
381 def _set_value(self
, value
):
382 native_bt
.value_real_set(self
._ptr
, self
._value
_to
_float
(value
))
384 value
= property(fset
=_set_value
)
387 @functools.total_ordering
388 class _StringValueConst(collections
.abc
.Sequence
, _Value
):
389 _NAME
= 'Const string'
392 def _value_to_str(cls
, value
):
393 if isinstance(value
, _StringValueConst
):
396 utils
._check
_str
(value
)
401 return native_bt
.value_string_get(self
._ptr
)
403 def __eq__(self
, other
):
405 return self
._value
== self
._value
_to
_str
(other
)
409 def __lt__(self
, other
):
410 return self
._value
< self
._value
_to
_str
(other
)
413 return bool(self
._value
)
416 return repr(self
._value
)
421 def __getitem__(self
, index
):
422 return self
._value
[index
]
425 return len(self
._value
)
427 def __contains__(self
, item
):
428 return self
._value
_to
_str
(item
) in self
._value
431 class StringValue(_StringValueConst
, _Value
):
434 def __init__(self
, value
=None):
436 ptr
= native_bt
.value_string_create()
438 ptr
= native_bt
.value_string_create_init(self
._value
_to
_str
(value
))
440 self
._check
_create
_status
(ptr
)
441 super().__init
__(ptr
)
443 def _set_value(self
, value
):
444 status
= native_bt
.value_string_set(self
._ptr
, self
._value
_to
_str
(value
))
445 utils
._handle
_func
_status
(status
)
447 value
= property(fset
=_set_value
)
449 def __iadd__(self
, value
):
450 curvalue
= self
._value
451 curvalue
+= self
._value
_to
_str
(value
)
452 self
.value
= curvalue
456 class _ContainerConst
:
458 return len(self
) != 0
461 class _Container(_ContainerConst
):
462 def __delitem__(self
, index
):
463 raise NotImplementedError
466 class _ArrayValueConst(_ContainerConst
, collections
.abc
.Sequence
, _ValueConst
):
467 _NAME
= 'Const array'
468 _borrow_element_by_index
= staticmethod(
469 native_bt
.value_array_borrow_element_by_index_const
473 def __eq__(self
, other
):
474 if not isinstance(other
, collections
.abc
.Sequence
):
477 if len(self
) != len(other
):
481 for self_elem
, other_elem
in zip(self
, other
):
482 if self_elem
!= other_elem
:
488 size
= native_bt
.value_array_get_length(self
._ptr
)
492 def _check_index(self
, index
):
493 # TODO: support slices also
494 if not isinstance(index
, numbers
.Integral
):
496 "'{}' object is not an integral number object: invalid index".format(
497 index
.__class
__.__name
__
503 if index
< 0 or index
>= len(self
):
504 raise IndexError('array value object index is out of range')
506 def __getitem__(self
, index
):
507 self
._check
_index
(index
)
508 ptr
= self
._borrow
_element
_by
_index
(self
._ptr
, index
)
510 return self
._create
_value
_from
_ptr
_and
_get
_ref
(ptr
)
513 return '[{}]'.format(', '.join([repr(v
) for v
in self
]))
516 class ArrayValue(_ArrayValueConst
, _Container
, collections
.abc
.MutableSequence
, _Value
):
518 _borrow_element_by_index
= staticmethod(
519 native_bt
.value_array_borrow_element_by_index
522 def __init__(self
, value
=None):
523 ptr
= native_bt
.value_array_create()
524 self
._check
_create
_status
(ptr
)
525 super().__init
__(ptr
)
527 # Python will raise a TypeError if there's anything wrong with
528 # the iterable protocol.
529 if value
is not None:
533 def __setitem__(self
, index
, value
):
534 self
._check
_index
(index
)
535 value
= create_value(value
)
538 ptr
= native_bt
.value_null
542 status
= native_bt
.value_array_set_element_by_index(self
._ptr
, index
, ptr
)
543 utils
._handle
_func
_status
(status
)
545 def append(self
, value
):
546 value
= create_value(value
)
549 ptr
= native_bt
.value_null
553 status
= native_bt
.value_array_append_element(self
._ptr
, ptr
)
554 utils
._handle
_func
_status
(status
)
556 def __iadd__(self
, iterable
):
557 # Python will raise a TypeError if there's anything wrong with
558 # the iterable protocol.
559 for elem
in iterable
:
564 def insert(self
, value
):
565 raise NotImplementedError
568 class _MapValueKeyIterator(collections
.abc
.Iterator
):
569 def __init__(self
, map_obj
):
570 self
._map
_obj
= map_obj
572 keys_ptr
= native_bt
.value_map_get_keys(map_obj
._ptr
)
575 raise RuntimeError('unexpected error: cannot get map value object keys')
577 self
._keys
= _create_from_ptr(keys_ptr
)
580 if self
._at
== len(self
._map
_obj
):
583 key
= self
._keys
[self
._at
]
588 class _MapValueConst(_ContainerConst
, collections
.abc
.Mapping
, _ValueConst
):
590 _borrow_entry_value_ptr
= staticmethod(native_bt
.value_map_borrow_entry_value_const
)
592 def __ne__(self
, other
):
593 return _Value
.__ne
__(self
, other
)
595 def __eq__(self
, other
):
596 if not isinstance(other
, collections
.abc
.Mapping
):
599 if len(self
) != len(other
):
603 for self_key
in self
:
604 if self_key
not in other
:
607 if self
[self_key
] != other
[self_key
]:
613 size
= native_bt
.value_map_get_size(self
._ptr
)
617 def __contains__(self
, key
):
618 self
._check
_key
_type
(key
)
619 return native_bt
.value_map_has_entry(self
._ptr
, key
)
621 def _check_key_type(self
, key
):
622 utils
._check
_str
(key
)
624 def _check_key(self
, key
):
628 def __getitem__(self
, key
):
630 ptr
= self
._borrow
_entry
_value
_ptr
(self
._ptr
, key
)
632 return self
._create
_value
_from
_ptr
_and
_get
_ref
(ptr
)
635 return _MapValueKeyIterator(self
)
638 items
= ['{}: {}'.format(repr(k
), repr(v
)) for k
, v
in self
.items()]
639 return '{{{}}}'.format(', '.join(items
))
642 class MapValue(_MapValueConst
, _Container
, collections
.abc
.MutableMapping
, _Value
):
644 _borrow_entry_value_ptr
= staticmethod(native_bt
.value_map_borrow_entry_value
)
646 def __init__(self
, value
=None):
647 ptr
= native_bt
.value_map_create()
648 self
._check
_create
_status
(ptr
)
649 super().__init
__(ptr
)
651 # Python will raise a TypeError if there's anything wrong with
652 # the iterable/mapping protocol.
653 if value
is not None:
654 for key
, elem
in value
.items():
657 def __setitem__(self
, key
, value
):
658 self
._check
_key
_type
(key
)
659 value
= create_value(value
)
662 ptr
= native_bt
.value_null
666 status
= native_bt
.value_map_insert_entry(self
._ptr
, key
, ptr
)
667 utils
._handle
_func
_status
(status
)
671 native_bt
.VALUE_TYPE_BOOL
: BoolValue
,
672 native_bt
.VALUE_TYPE_UNSIGNED_INTEGER
: UnsignedIntegerValue
,
673 native_bt
.VALUE_TYPE_SIGNED_INTEGER
: SignedIntegerValue
,
674 native_bt
.VALUE_TYPE_REAL
: RealValue
,
675 native_bt
.VALUE_TYPE_STRING
: StringValue
,
676 native_bt
.VALUE_TYPE_ARRAY
: ArrayValue
,
677 native_bt
.VALUE_TYPE_MAP
: MapValue
,
680 _TYPE_TO_CONST_OBJ
= {
681 native_bt
.VALUE_TYPE_BOOL
: _BoolValueConst
,
682 native_bt
.VALUE_TYPE_UNSIGNED_INTEGER
: _UnsignedIntegerValueConst
,
683 native_bt
.VALUE_TYPE_SIGNED_INTEGER
: _SignedIntegerValueConst
,
684 native_bt
.VALUE_TYPE_REAL
: _RealValueConst
,
685 native_bt
.VALUE_TYPE_STRING
: _StringValueConst
,
686 native_bt
.VALUE_TYPE_ARRAY
: _ArrayValueConst
,
687 native_bt
.VALUE_TYPE_MAP
: _MapValueConst
,