1 # SPDX-License-Identifier: MIT
3 # Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
11 from bt2
import error
as bt2_error
12 from bt2
import utils
as bt2_utils
13 from bt2
import object as bt2_object
14 from bt2
import native_bt
17 def _create_from_ptr_template(ptr
, object_map
):
21 # bt_value_null is translated to None. However, we are given a reference
22 # to it that we are not going to manage anymore, since we don't create a
23 # Python wrapper for it. Therefore put that reference immediately.
24 if ptr
== native_bt
.value_null
:
28 typeid
= native_bt
.value_get_type(ptr
)
29 return object_map
[typeid
]._create
_from
_ptr
(ptr
)
32 def _create_from_ptr(ptr
):
33 return _create_from_ptr_template(ptr
, _TYPE_TO_OBJ
)
36 def _create_from_const_ptr(ptr
):
37 return _create_from_ptr_template(ptr
, _TYPE_TO_CONST_OBJ
)
40 def _create_from_ptr_and_get_ref_template(ptr
, object_map
):
41 if ptr
is None or ptr
== native_bt
.value_null
:
44 typeid
= native_bt
.value_get_type(ptr
)
45 return object_map
[typeid
]._create
_from
_ptr
_and
_get
_ref
(ptr
)
48 def _create_from_ptr_and_get_ref(ptr
):
49 return _create_from_ptr_and_get_ref_template(ptr
, _TYPE_TO_OBJ
)
52 def _create_from_const_ptr_and_get_ref(ptr
):
53 return _create_from_ptr_and_get_ref_template(ptr
, _TYPE_TO_CONST_OBJ
)
56 def create_value(value
):
61 if isinstance(value
, _Value
):
64 if isinstance(value
, bool):
65 return BoolValue(value
)
67 if isinstance(value
, numbers
.Integral
):
68 return SignedIntegerValue(value
)
70 if isinstance(value
, numbers
.Real
):
71 return RealValue(value
)
73 if isinstance(value
, str):
74 return StringValue(value
)
76 if isinstance(value
, collections
.abc
.Sequence
):
77 return ArrayValue(value
)
79 if isinstance(value
, collections
.abc
.Mapping
):
80 return MapValue(value
)
83 "cannot create value object from '{}' object".format(value
.__class
__.__name
__)
87 class _ValueConst(bt2_object
._SharedObject
, metaclass
=abc
.ABCMeta
):
90 native_bt
.value_get_ref(ptr
)
94 native_bt
.value_put_ref(ptr
)
96 _create_value_from_ptr
= staticmethod(_create_from_const_ptr
)
97 _create_value_from_ptr_and_get_ref
= staticmethod(
98 _create_from_const_ptr_and_get_ref
101 def __ne__(self
, other
):
102 return not (self
== other
)
104 def _check_create_status(self
, ptr
):
106 raise bt2_error
._MemoryError
(
107 "cannot create {} value object".format(self
._NAME
.lower())
111 class _Value(_ValueConst
):
112 _create_value_from_ptr
= staticmethod(_create_from_ptr
)
113 _create_value_from_ptr_and_get_ref
= staticmethod(_create_from_ptr_and_get_ref
)
116 @functools.total_ordering
117 class _NumericValueConst(_ValueConst
):
119 def _extract_value(other
):
120 if isinstance(other
, _BoolValueConst
) or isinstance(other
, bool):
123 if isinstance(other
, numbers
.Integral
):
126 if isinstance(other
, numbers
.Real
):
129 if isinstance(other
, numbers
.Complex
):
130 return complex(other
)
133 "'{}' object is not a number object".format(other
.__class
__.__name
__)
137 return int(self
._value
)
140 return float(self
._value
)
143 return repr(self
._value
)
145 def __lt__(self
, other
):
146 return self
._value
< self
._extract
_value
(other
)
148 def __eq__(self
, other
):
150 return self
._value
== self
._extract
_value
(other
)
154 def __rmod__(self
, other
):
155 return self
._extract
_value
(other
) % self
._value
157 def __mod__(self
, other
):
158 return self
._value
% self
._extract
_value
(other
)
160 def __rfloordiv__(self
, other
):
161 return self
._extract
_value
(other
) // self
._value
163 def __floordiv__(self
, other
):
164 return self
._value
// self
._extract
_value
(other
)
166 def __round__(self
, ndigits
=None):
168 return round(self
._value
)
170 return round(self
._value
, ndigits
)
173 return math
.ceil(self
._value
)
176 return math
.floor(self
._value
)
179 return int(self
._value
)
182 return abs(self
._value
)
184 def __add__(self
, other
):
185 return self
._value
+ self
._extract
_value
(other
)
187 def __radd__(self
, other
):
188 return self
.__add
__(other
)
196 def __mul__(self
, other
):
197 return self
._value
* self
._extract
_value
(other
)
199 def __rmul__(self
, other
):
200 return self
.__mul
__(other
)
202 def __truediv__(self
, other
):
203 return self
._value
/ self
._extract
_value
(other
)
205 def __rtruediv__(self
, other
):
206 return self
._extract
_value
(other
) / self
._value
208 def __pow__(self
, exponent
):
209 return self
._value
** self
._extract
_value
(exponent
)
211 def __rpow__(self
, base
):
212 return self
._extract
_value
(base
) ** self
._value
215 class _NumericValue(_NumericValueConst
, _Value
):
219 class _IntegralValueConst(_NumericValueConst
, numbers
.Integral
):
220 def __lshift__(self
, other
):
221 return self
._value
<< self
._extract
_value
(other
)
223 def __rlshift__(self
, other
):
224 return self
._extract
_value
(other
) << self
._value
226 def __rshift__(self
, other
):
227 return self
._value
>> self
._extract
_value
(other
)
229 def __rrshift__(self
, other
):
230 return self
._extract
_value
(other
) >> self
._value
232 def __and__(self
, other
):
233 return self
._value
& self
._extract
_value
(other
)
235 def __rand__(self
, other
):
236 return self
._extract
_value
(other
) & self
._value
238 def __xor__(self
, other
):
239 return self
._value ^ self
._extract
_value
(other
)
241 def __rxor__(self
, other
):
242 return self
._extract
_value
(other
) ^ self
._value
244 def __or__(self
, other
):
245 return self
._value | self
._extract
_value
(other
)
247 def __ror__(self
, other
):
248 return self
._extract
_value
(other
) | self
._value
250 def __invert__(self
):
254 class _IntegralValue(_IntegralValueConst
, _NumericValue
):
258 class _BoolValueConst(_IntegralValueConst
):
259 _NAME
= "Const boolean"
265 return repr(self
._value
)
269 value
= native_bt
.value_bool_get(self
._ptr
)
273 class BoolValue(_BoolValueConst
, _IntegralValue
):
276 def __init__(self
, value
=None):
278 ptr
= native_bt
.value_bool_create()
280 ptr
= native_bt
.value_bool_create_init(self
._value
_to
_bool
(value
))
282 self
._check
_create
_status
(ptr
)
283 super().__init
__(ptr
)
286 def _value_to_bool(cls
, value
):
287 if isinstance(value
, _BoolValueConst
):
290 if not isinstance(value
, bool):
292 "'{}' object is not a 'bool', 'BoolValue', or '_BoolValueConst' object".format(
299 def _set_value(self
, value
):
300 native_bt
.value_bool_set(self
._ptr
, self
._value
_to
_bool
(value
))
302 value
= property(fset
=_set_value
)
305 class _IntegerValueConst(_IntegralValueConst
):
308 return self
._get
_value
(self
._ptr
)
311 class _IntegerValue(_IntegerValueConst
, _IntegralValue
):
312 def __init__(self
, value
=None):
314 ptr
= self
._create
_default
_value
()
316 ptr
= self
._create
_value
(self
._value
_to
_int
(value
))
318 self
._check
_create
_status
(ptr
)
319 super().__init
__(ptr
)
322 def _value_to_int(cls
, value
):
323 if not isinstance(value
, numbers
.Integral
):
324 raise TypeError("expecting an integral number object")
327 cls
._check
_int
_range
(value
)
330 def _prop_set_value(self
, value
):
331 self
._set
_value
(self
._ptr
, self
._value
_to
_int
(value
))
333 value
= property(fset
=_prop_set_value
)
336 class _UnsignedIntegerValueConst(_IntegerValueConst
):
337 _NAME
= "Const unsigned integer"
338 _get_value
= staticmethod(native_bt
.value_integer_unsigned_get
)
341 class UnsignedIntegerValue(_UnsignedIntegerValueConst
, _IntegerValue
):
342 _NAME
= "Unsigned integer"
343 _check_int_range
= staticmethod(bt2_utils
._check
_uint
64)
344 _create_default_value
= staticmethod(native_bt
.value_integer_unsigned_create
)
345 _create_value
= staticmethod(native_bt
.value_integer_unsigned_create_init
)
346 _set_value
= staticmethod(native_bt
.value_integer_unsigned_set
)
349 class _SignedIntegerValueConst(_IntegerValueConst
):
350 _NAME
= "Const signed integer"
351 _get_value
= staticmethod(native_bt
.value_integer_signed_get
)
354 class SignedIntegerValue(_SignedIntegerValueConst
, _IntegerValue
):
355 _NAME
= "Signed integer"
356 _check_int_range
= staticmethod(bt2_utils
._check
_int
64)
357 _create_default_value
= staticmethod(native_bt
.value_integer_signed_create
)
358 _create_value
= staticmethod(native_bt
.value_integer_signed_create_init
)
359 _set_value
= staticmethod(native_bt
.value_integer_signed_set
)
362 class _RealValueConst(_NumericValueConst
, numbers
.Real
):
363 _NAME
= "Const real number"
367 return native_bt
.value_real_get(self
._ptr
)
370 class RealValue(_RealValueConst
, _NumericValue
):
371 _NAME
= "Real number"
373 def __init__(self
, value
=None):
375 ptr
= native_bt
.value_real_create()
377 value
= self
._value
_to
_float
(value
)
378 ptr
= native_bt
.value_real_create_init(value
)
380 self
._check
_create
_status
(ptr
)
381 super().__init
__(ptr
)
384 def _value_to_float(cls
, value
):
385 if not isinstance(value
, numbers
.Real
):
386 raise TypeError("expecting a real number object")
390 def _set_value(self
, value
):
391 native_bt
.value_real_set(self
._ptr
, self
._value
_to
_float
(value
))
393 value
= property(fset
=_set_value
)
396 @functools.total_ordering
397 class _StringValueConst(collections
.abc
.Sequence
, _Value
):
398 _NAME
= "Const string"
401 def _value_to_str(cls
, value
):
402 if isinstance(value
, _StringValueConst
):
405 bt2_utils
._check
_str
(value
)
410 return native_bt
.value_string_get(self
._ptr
)
412 def __eq__(self
, other
):
414 return self
._value
== self
._value
_to
_str
(other
)
418 def __lt__(self
, other
):
419 return self
._value
< self
._value
_to
_str
(other
)
422 return bool(self
._value
)
425 return repr(self
._value
)
430 def __getitem__(self
, index
):
431 return self
._value
[index
]
434 return len(self
._value
)
436 def __contains__(self
, item
):
437 return self
._value
_to
_str
(item
) in self
._value
440 class StringValue(_StringValueConst
, _Value
):
443 def __init__(self
, value
=None):
445 ptr
= native_bt
.value_string_create()
447 ptr
= native_bt
.value_string_create_init(self
._value
_to
_str
(value
))
449 self
._check
_create
_status
(ptr
)
450 super().__init
__(ptr
)
452 def _set_value(self
, value
):
453 status
= native_bt
.value_string_set(self
._ptr
, self
._value
_to
_str
(value
))
454 bt2_utils
._handle
_func
_status
(status
)
456 value
= property(fset
=_set_value
)
458 def __iadd__(self
, value
):
459 curvalue
= self
._value
460 curvalue
+= self
._value
_to
_str
(value
)
461 self
.value
= curvalue
465 class _ContainerConst
:
467 return len(self
) != 0
470 class _Container(_ContainerConst
):
471 def __delitem__(self
, index
):
472 raise NotImplementedError
475 class _ArrayValueConst(_ContainerConst
, collections
.abc
.Sequence
, _ValueConst
):
476 _NAME
= "Const array"
477 _borrow_element_by_index
= staticmethod(
478 native_bt
.value_array_borrow_element_by_index_const
482 def __eq__(self
, other
):
483 if not isinstance(other
, collections
.abc
.Sequence
):
486 if len(self
) != len(other
):
490 for self_elem
, other_elem
in zip(self
, other
):
491 if self_elem
!= other_elem
:
497 size
= native_bt
.value_array_get_length(self
._ptr
)
501 def _check_index(self
, index
):
502 # TODO: support slices also
503 if not isinstance(index
, numbers
.Integral
):
505 "'{}' object is not an integral number object: invalid index".format(
506 index
.__class
__.__name
__
512 if index
< 0 or index
>= len(self
):
513 raise IndexError("array value object index is out of range")
515 def __getitem__(self
, index
):
516 self
._check
_index
(index
)
517 ptr
= self
._borrow
_element
_by
_index
(self
._ptr
, index
)
519 return self
._create
_value
_from
_ptr
_and
_get
_ref
(ptr
)
522 return "[{}]".format(", ".join([repr(v
) for v
in self
]))
525 class ArrayValue(_ArrayValueConst
, _Container
, collections
.abc
.MutableSequence
, _Value
):
527 _borrow_element_by_index
= staticmethod(
528 native_bt
.value_array_borrow_element_by_index
531 def __init__(self
, value
=None):
532 ptr
= native_bt
.value_array_create()
533 self
._check
_create
_status
(ptr
)
534 super().__init
__(ptr
)
536 # Python will raise a TypeError if there's anything wrong with
537 # the iterable protocol.
538 if value
is not None:
542 def __setitem__(self
, index
, value
):
543 self
._check
_index
(index
)
544 value
= create_value(value
)
547 ptr
= native_bt
.value_null
551 status
= native_bt
.value_array_set_element_by_index(self
._ptr
, index
, ptr
)
552 bt2_utils
._handle
_func
_status
(status
)
554 def append(self
, value
):
555 value
= create_value(value
)
558 ptr
= native_bt
.value_null
562 status
= native_bt
.value_array_append_element(self
._ptr
, ptr
)
563 bt2_utils
._handle
_func
_status
(status
)
565 def __iadd__(self
, iterable
):
566 # Python will raise a TypeError if there's anything wrong with
567 # the iterable protocol.
568 for elem
in iterable
:
573 def insert(self
, value
):
574 raise NotImplementedError
577 class _MapValueKeyIterator(collections
.abc
.Iterator
):
578 def __init__(self
, map_obj
):
579 self
._map
_obj
= map_obj
581 keys_ptr
= native_bt
.value_map_get_keys(map_obj
._ptr
)
584 raise RuntimeError("unexpected error: cannot get map value object keys")
586 self
._keys
= _create_from_ptr(keys_ptr
)
589 if self
._at
== len(self
._map
_obj
):
592 key
= self
._keys
[self
._at
]
597 class _MapValueConst(_ContainerConst
, collections
.abc
.Mapping
, _ValueConst
):
599 _borrow_entry_value_ptr
= staticmethod(native_bt
.value_map_borrow_entry_value_const
)
601 def __ne__(self
, other
):
602 return _Value
.__ne
__(self
, other
)
604 def __eq__(self
, other
):
605 if not isinstance(other
, collections
.abc
.Mapping
):
608 if len(self
) != len(other
):
612 for self_key
in self
:
613 if self_key
not in other
:
616 if self
[self_key
] != other
[self_key
]:
622 size
= native_bt
.value_map_get_size(self
._ptr
)
626 def __contains__(self
, key
):
627 self
._check
_key
_type
(key
)
628 return native_bt
.value_map_has_entry(self
._ptr
, key
)
630 def _check_key_type(self
, key
):
631 bt2_utils
._check
_str
(key
)
633 def _check_key(self
, key
):
637 def __getitem__(self
, key
):
639 ptr
= self
._borrow
_entry
_value
_ptr
(self
._ptr
, key
)
641 return self
._create
_value
_from
_ptr
_and
_get
_ref
(ptr
)
644 return _MapValueKeyIterator(self
)
647 items
= ["{}: {}".format(repr(k
), repr(v
)) for k
, v
in self
.items()]
648 return "{{{}}}".format(", ".join(items
))
651 class MapValue(_MapValueConst
, _Container
, collections
.abc
.MutableMapping
, _Value
):
653 _borrow_entry_value_ptr
= staticmethod(native_bt
.value_map_borrow_entry_value
)
655 def __init__(self
, value
=None):
656 ptr
= native_bt
.value_map_create()
657 self
._check
_create
_status
(ptr
)
658 super().__init
__(ptr
)
660 # Python will raise a TypeError if there's anything wrong with
661 # the iterable/mapping protocol.
662 if value
is not None:
663 for key
, elem
in value
.items():
666 def __setitem__(self
, key
, value
):
667 self
._check
_key
_type
(key
)
668 value
= create_value(value
)
671 ptr
= native_bt
.value_null
675 status
= native_bt
.value_map_insert_entry(self
._ptr
, key
, ptr
)
676 bt2_utils
._handle
_func
_status
(status
)
680 native_bt
.VALUE_TYPE_BOOL
: BoolValue
,
681 native_bt
.VALUE_TYPE_UNSIGNED_INTEGER
: UnsignedIntegerValue
,
682 native_bt
.VALUE_TYPE_SIGNED_INTEGER
: SignedIntegerValue
,
683 native_bt
.VALUE_TYPE_REAL
: RealValue
,
684 native_bt
.VALUE_TYPE_STRING
: StringValue
,
685 native_bt
.VALUE_TYPE_ARRAY
: ArrayValue
,
686 native_bt
.VALUE_TYPE_MAP
: MapValue
,
689 _TYPE_TO_CONST_OBJ
= {
690 native_bt
.VALUE_TYPE_BOOL
: _BoolValueConst
,
691 native_bt
.VALUE_TYPE_UNSIGNED_INTEGER
: _UnsignedIntegerValueConst
,
692 native_bt
.VALUE_TYPE_SIGNED_INTEGER
: _SignedIntegerValueConst
,
693 native_bt
.VALUE_TYPE_REAL
: _RealValueConst
,
694 native_bt
.VALUE_TYPE_STRING
: _StringValueConst
,
695 native_bt
.VALUE_TYPE_ARRAY
: _ArrayValueConst
,
696 native_bt
.VALUE_TYPE_MAP
: _MapValueConst
,