1 # The MIT License (MIT)
3 # Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 from bt2
import native_bt
, object, utils
24 import collections
.abc
27 import bt2
.integer_range_set
31 def _create_field_class_from_ptr_and_get_ref(ptr
):
32 typeid
= native_bt
.field_class_get_type(ptr
)
33 return _FIELD_CLASS_TYPE_TO_OBJ
[typeid
]._create
_from
_ptr
_and
_get
_ref
(ptr
)
36 class IntegerDisplayBase
:
37 BINARY
= native_bt
.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
38 OCTAL
= native_bt
.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
39 DECIMAL
= native_bt
.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
40 HEXADECIMAL
= native_bt
.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
43 class _FieldClass(object._SharedObject
):
44 _get_ref
= staticmethod(native_bt
.field_class_get_ref
)
45 _put_ref
= staticmethod(native_bt
.field_class_put_ref
)
47 def _check_create_status(self
, ptr
):
49 raise bt2
.CreationError('cannot create {} field class object'.format(self
._NAME
.lower()))
52 class _IntegerFieldClass(_FieldClass
):
54 def field_value_range(self
):
55 size
= native_bt
.field_class_integer_get_field_value_range(self
._ptr
)
59 def _field_value_range(self
, size
):
60 if size
< 1 or size
> 64:
61 raise ValueError("Value is outside valid range [1, 64] ({})".format(size
))
62 native_bt
.field_class_integer_set_field_value_range(self
._ptr
, size
)
64 _field_value_range
= property(fset
=_field_value_range
)
67 def preferred_display_base(self
):
68 base
= native_bt
.field_class_integer_get_preferred_display_base(
73 def _preferred_display_base(self
, base
):
74 utils
._check
_uint
64(base
)
76 if base
not in (IntegerDisplayBase
.BINARY
,
77 IntegerDisplayBase
.OCTAL
,
78 IntegerDisplayBase
.DECIMAL
,
79 IntegerDisplayBase
.HEXADECIMAL
):
80 raise ValueError("Display base is not a valid IntegerDisplayBase value")
82 native_bt
.field_class_integer_set_preferred_display_base(
85 _preferred_display_base
= property(fset
=_preferred_display_base
)
88 class _UnsignedIntegerFieldClass(_IntegerFieldClass
):
89 _NAME
= 'Unsigned integer'
92 class _SignedIntegerFieldClass(_IntegerFieldClass
):
93 _NAME
= 'Signed integer'
96 class _RealFieldClass(_FieldClass
):
100 def is_single_precision(self
):
101 return native_bt
.field_class_real_is_single_precision(self
._ptr
)
103 def _is_single_precision(self
, is_single_precision
):
104 utils
._check
_bool
(is_single_precision
)
105 native_bt
.field_class_real_set_is_single_precision(
106 self
._ptr
, is_single_precision
)
108 _is_single_precision
= property(fset
=_is_single_precision
)
111 # an enumeration field class mapping does not have a reference count, so
112 # we copy the properties here to avoid eventual memory access errors.
113 class _EnumerationFieldClassMapping
:
114 def __init__(self
, mapping_ptr
):
115 base_mapping_ptr
= self
._as
_enumeration
_field
_class
_mapping
_ptr
(mapping_ptr
)
116 self
._label
= native_bt
.field_class_enumeration_mapping_get_label(base_mapping_ptr
)
117 assert self
._label
is not None
118 ranges_ptr
= self
._mapping
_borrow
_ranges
_ptr
(mapping_ptr
)
119 assert ranges_ptr
is not None
120 self
._ranges
= self
._ranges
_type
._create
_from
_ptr
_and
_get
_ref
(ranges_ptr
)
131 class _UnsignedEnumerationFieldClassMapping(_EnumerationFieldClassMapping
):
132 _ranges_type
= bt2
.integer_range_set
.UnsignedIntegerRangeSet
133 _as_enumeration_field_class_mapping_ptr
= staticmethod(native_bt
.field_class_unsigned_enumeration_mapping_as_mapping_const
)
134 _mapping_borrow_ranges_ptr
= staticmethod(native_bt
.field_class_unsigned_enumeration_mapping_borrow_ranges_const
)
137 class _SignedEnumerationFieldClassMapping(_EnumerationFieldClassMapping
):
138 _ranges_type
= bt2
.integer_range_set
.SignedIntegerRangeSet
139 _as_enumeration_field_class_mapping_ptr
= staticmethod(native_bt
.field_class_signed_enumeration_mapping_as_mapping_const
)
140 _mapping_borrow_ranges_ptr
= staticmethod(native_bt
.field_class_signed_enumeration_mapping_borrow_ranges_const
)
143 class _EnumerationFieldClass(_IntegerFieldClass
, collections
.abc
.Mapping
):
145 count
= native_bt
.field_class_enumeration_get_mapping_count(self
._ptr
)
149 def add_mapping(self
, label
, ranges
):
150 utils
._check
_str
(label
)
151 utils
._check
_type
(ranges
, self
._range
_set
_type
)
154 raise bt2
.Error("duplicate mapping label '{}'".format(label
))
156 status
= self
._add
_mapping
(self
._ptr
, label
, ranges
._ptr
)
157 utils
._handle
_func
_status
(status
,
158 'cannot add mapping to enumeration field class object')
160 def mappings_for_value(self
, value
):
161 status
, labels
= self
._get
_mapping
_labels
_for
_value
(self
._ptr
, value
)
162 utils
._handle
_func
_status
(status
, 'cannot get mapping labels for value {}'.format(value
))
163 return [self
[label
] for label
in labels
]
166 for idx
in range(len(self
)):
167 mapping
= self
._get
_mapping
_by
_index
(self
._ptr
, idx
)
170 def __getitem__(self
, label
):
171 utils
._check
_str
(label
)
172 mapping
= self
._get
_mapping
_by
_label
(self
._ptr
, label
)
175 raise KeyError(label
)
179 def __iadd__(self
, mappings
):
180 for label
, ranges
in mappings
:
181 self
.add_mapping(label
, ranges
)
186 class _UnsignedEnumerationFieldClass(_EnumerationFieldClass
, _UnsignedIntegerFieldClass
):
187 _NAME
= 'Unsigned enumeration'
188 _range_set_type
= bt2
.integer_range_set
.UnsignedIntegerRangeSet
189 _add_mapping
= staticmethod(native_bt
.field_class_unsigned_enumeration_add_mapping
)
192 def _get_mapping_by_index(enum_ptr
, index
):
193 mapping_ptr
= native_bt
.field_class_unsigned_enumeration_borrow_mapping_by_index_const(enum_ptr
, index
)
194 assert mapping_ptr
is not None
195 return _UnsignedEnumerationFieldClassMapping(mapping_ptr
)
198 def _get_mapping_by_label(enum_ptr
, label
):
199 mapping_ptr
= native_bt
.field_class_unsigned_enumeration_borrow_mapping_by_label_const(enum_ptr
, label
)
201 if mapping_ptr
is None:
204 return _UnsignedEnumerationFieldClassMapping(mapping_ptr
)
207 def _get_mapping_labels_for_value(enum_ptr
, value
):
208 utils
._check
_uint
64(value
)
209 return native_bt
.field_class_unsigned_enumeration_get_mapping_labels_for_value(enum_ptr
, value
)
212 class _SignedEnumerationFieldClass(_EnumerationFieldClass
, _SignedIntegerFieldClass
):
213 _NAME
= 'Signed enumeration'
214 _range_set_type
= bt2
.integer_range_set
.SignedIntegerRangeSet
215 _add_mapping
= staticmethod(native_bt
.field_class_signed_enumeration_add_mapping
)
218 def _get_mapping_by_index(enum_ptr
, index
):
219 mapping_ptr
= native_bt
.field_class_signed_enumeration_borrow_mapping_by_index_const(enum_ptr
, index
)
220 assert mapping_ptr
is not None
221 return _SignedEnumerationFieldClassMapping(mapping_ptr
)
224 def _get_mapping_by_label(enum_ptr
, label
):
225 mapping_ptr
= native_bt
.field_class_signed_enumeration_borrow_mapping_by_label_const(enum_ptr
, label
)
227 if mapping_ptr
is None:
230 return _SignedEnumerationFieldClassMapping(mapping_ptr
)
233 def _get_mapping_labels_for_value(enum_ptr
, value
):
234 utils
._check
_int
64(value
)
235 return native_bt
.field_class_signed_enumeration_get_mapping_labels_for_value(enum_ptr
, value
)
238 class _StringFieldClass(_FieldClass
):
242 class _StructureFieldClassMember
:
243 def __init__(self
, name
, field_class
):
245 self
._field
_class
= field_class
252 def field_class(self
):
253 return self
._field
_class
256 class _StructureFieldClass(_FieldClass
, collections
.abc
.Mapping
):
259 def append_member(self
, name
, field_class
):
260 utils
._check
_str
(name
)
261 utils
._check
_type
(field_class
, _FieldClass
)
264 raise bt2
.Error("duplicate member name '{}'".format(name
))
266 status
= native_bt
.field_class_structure_append_member(self
._ptr
, name
, field_class
._ptr
)
267 utils
._handle
_func
_status
(status
,
268 'cannot append member to structure field class object')
271 count
= native_bt
.field_class_structure_get_member_count(self
._ptr
)
276 def _create_member_from_ptr(member_ptr
):
277 name
= native_bt
.field_class_structure_member_get_name(member_ptr
)
278 assert name
is not None
279 fc_ptr
= native_bt
.field_class_structure_member_borrow_field_class_const(member_ptr
)
280 assert fc_ptr
is not None
281 fc
= _create_field_class_from_ptr_and_get_ref(fc_ptr
)
282 return _StructureFieldClassMember(name
, fc
)
284 def __getitem__(self
, key
):
285 if not isinstance(key
, str):
286 raise TypeError("key must be a 'str' object, got '{}'".format(key
.__class
__.__name
__))
288 member_ptr
= native_bt
.field_class_structure_borrow_member_by_name_const(self
._ptr
, key
)
290 if member_ptr
is None:
293 return self
._create
_member
_from
_ptr
(member_ptr
)
296 for idx
in range(len(self
)):
297 member_ptr
= native_bt
.field_class_structure_borrow_member_by_index_const(self
._ptr
, idx
)
298 assert member_ptr
is not None
299 yield native_bt
.field_class_structure_member_get_name(member_ptr
)
301 def __iadd__(self
, members
):
302 for name
, field_class
in members
:
303 self
.append_member(name
, field_class
)
307 def member_at_index(self
, index
):
308 utils
._check
_uint
64(index
)
310 if index
>= len(self
):
313 member_ptr
= native_bt
.field_class_structure_borrow_member_by_index_const(self
._ptr
, index
)
314 assert member_ptr
is not None
315 return self
._create
_member
_from
_ptr
(member_ptr
)
318 class _VariantFieldClassOption
:
319 def __init__(self
, name
, field_class
):
321 self
._field
_class
= field_class
328 def field_class(self
):
329 return self
._field
_class
332 class _VariantFieldClassWithSelectorOption(_VariantFieldClassOption
):
333 def __init__(self
, name
, field_class
, ranges
):
334 super().__init
__(name
, field_class
)
335 self
._ranges
= ranges
342 class _VariantFieldClass(_FieldClass
, collections
.abc
.Mapping
):
344 _borrow_option_by_name_ptr
= staticmethod(native_bt
.field_class_variant_borrow_option_by_name_const
)
345 _borrow_member_by_index_ptr
= staticmethod(native_bt
.field_class_variant_borrow_option_by_index_const
)
348 def _as_option_ptr(opt_ptr
):
351 def _create_option_from_ptr(self
, opt_ptr
):
352 name
= native_bt
.field_class_variant_option_get_name(opt_ptr
)
353 assert name
is not None
354 fc_ptr
= native_bt
.field_class_variant_option_borrow_field_class_const(opt_ptr
)
355 assert fc_ptr
is not None
356 fc
= _create_field_class_from_ptr_and_get_ref(fc_ptr
)
357 return _VariantFieldClassOption(name
, fc
)
360 count
= native_bt
.field_class_variant_get_option_count(self
._ptr
)
364 def __getitem__(self
, key
):
365 if not isinstance(key
, str):
366 raise TypeError("key must be a 'str' object, got '{}'".format(key
.__class
__.__name
__))
368 opt_ptr
= self
._borrow
_option
_by
_name
_ptr
(self
._ptr
, key
)
373 return self
._create
_option
_from
_ptr
(opt_ptr
)
376 for idx
in range(len(self
)):
377 opt_ptr
= self
._borrow
_member
_by
_index
_ptr
(self
._ptr
, idx
)
378 assert opt_ptr
is not None
379 base_opt_ptr
= self
._as
_option
_ptr
(opt_ptr
)
380 yield native_bt
.field_class_variant_option_get_name(base_opt_ptr
)
382 def option_at_index(self
, index
):
383 utils
._check
_uint
64(index
)
385 if index
>= len(self
):
388 opt_ptr
= self
._borrow
_member
_by
_index
_ptr
(self
._ptr
, index
)
389 assert opt_ptr
is not None
390 return self
._create
_option
_from
_ptr
(opt_ptr
)
393 class _VariantFieldClassWithoutSelector(_VariantFieldClass
):
394 _NAME
= 'Variant (without selector)'
396 def append_option(self
, name
, field_class
):
397 utils
._check
_str
(name
)
398 utils
._check
_type
(field_class
, _FieldClass
)
401 raise bt2
.Error("duplicate option name '{}'".format(name
))
403 status
= native_bt
.field_class_variant_without_selector_append_option(self
._ptr
, name
, field_class
._ptr
)
404 utils
._handle
_func
_status
(status
,
405 'cannot append option to variant field class object')
407 def __iadd__(self
, options
):
408 for name
, field_class
in options
:
409 self
.append_option(name
, field_class
)
414 class _VariantFieldClassWithSelector(_VariantFieldClass
):
415 _NAME
= 'Variant (with selector)'
417 def _create_option_from_ptr(self
, opt_ptr
):
418 base_opt_ptr
= self
._as
_option
_ptr
(opt_ptr
)
419 name
= native_bt
.field_class_variant_option_get_name(base_opt_ptr
)
420 assert name
is not None
421 fc_ptr
= native_bt
.field_class_variant_option_borrow_field_class_const(base_opt_ptr
)
422 assert fc_ptr
is not None
423 fc
= _create_field_class_from_ptr_and_get_ref(fc_ptr
)
424 range_set_ptr
= self
._option
_borrow
_ranges
_ptr
(opt_ptr
)
425 assert range_set_ptr
is not None
426 range_set
= self
._range
_set
_type
._create
_from
_ptr
_and
_get
_ref
(range_set_ptr
)
427 return _VariantFieldClassWithSelectorOption(name
, fc
, range_set
)
430 def selector_field_path(self
):
431 ptr
= native_bt
.field_class_variant_with_selector_borrow_selector_field_path_const(self
._ptr
)
436 return bt2
.field_path
._FieldPath
._create
_from
_ptr
_and
_get
_ref
(ptr
)
438 def append_option(self
, name
, field_class
, ranges
):
439 utils
._check
_str
(name
)
440 utils
._check
_type
(field_class
, _FieldClass
)
441 utils
._check
_type
(ranges
, self
._range
_set
_type
)
444 raise bt2
.Error("duplicate option name '{}'".format(name
))
447 raise ValueError('range set is empty')
449 # TODO: check overlaps (precondition of self._append_option())
451 status
= self
._append
_option
(self
._ptr
, name
, field_class
._ptr
, ranges
._ptr
)
452 utils
._handle
_func
_status
(status
,
453 'cannot append option to variant field class object')
455 def __iadd__(self
, options
):
456 for name
, field_class
, ranges
in options
:
457 self
.append_option(name
, field_class
, ranges
)
462 class _VariantFieldClassWithUnsignedSelector(_VariantFieldClassWithSelector
):
463 _NAME
= 'Variant (with unsigned selector)'
464 _borrow_option_by_name_ptr
= staticmethod(native_bt
.field_class_variant_with_unsigned_selector_borrow_option_by_name_const
)
465 _borrow_member_by_index_ptr
= staticmethod(native_bt
.field_class_variant_with_unsigned_selector_borrow_option_by_index_const
)
466 _as_option_ptr
= staticmethod(native_bt
.field_class_variant_with_unsigned_selector_option_as_option_const
)
467 _append_option
= staticmethod(native_bt
.field_class_variant_with_unsigned_selector_append_option
)
468 _option_borrow_ranges_ptr
= staticmethod(native_bt
.field_class_variant_with_unsigned_selector_option_borrow_ranges_const
)
469 _range_set_type
= bt2
.integer_range_set
.UnsignedIntegerRangeSet
472 class _VariantFieldClassWithSignedSelector(_VariantFieldClassWithSelector
):
473 _NAME
= 'Variant (with signed selector)'
474 _borrow_option_by_name_ptr
= staticmethod(native_bt
.field_class_variant_with_signed_selector_borrow_option_by_name_const
)
475 _borrow_member_by_index_ptr
= staticmethod(native_bt
.field_class_variant_with_signed_selector_borrow_option_by_index_const
)
476 _as_option_ptr
= staticmethod(native_bt
.field_class_variant_with_signed_selector_option_as_option_const
)
477 _append_option
= staticmethod(native_bt
.field_class_variant_with_signed_selector_append_option
)
478 _option_borrow_ranges_ptr
= staticmethod(native_bt
.field_class_variant_with_signed_selector_option_borrow_ranges_const
)
479 _range_set_type
= bt2
.integer_range_set
.SignedIntegerRangeSet
482 class _ArrayFieldClass(_FieldClass
):
484 def element_field_class(self
):
485 elem_fc_ptr
= native_bt
.field_class_array_borrow_element_field_class_const(self
._ptr
)
486 return _create_field_class_from_ptr_and_get_ref(elem_fc_ptr
)
489 class _StaticArrayFieldClass(_ArrayFieldClass
):
492 return native_bt
.field_class_static_array_get_length(self
._ptr
)
495 class _DynamicArrayFieldClass(_ArrayFieldClass
):
497 def length_field_path(self
):
498 ptr
= native_bt
.field_class_dynamic_array_borrow_length_field_path_const(self
._ptr
)
502 return bt2
.field_path
._FieldPath
._create
_from
_ptr
_and
_get
_ref
(ptr
)
504 def _set_length_field_class(self
, length_fc
):
505 utils
._check
_type
(length_fc
, _UnsignedIntegerFieldClass
)
506 status
= native_bt
.field_class_dynamic_array_set_length_field_class(self
._ptr
, length_fc
._ptr
)
507 utils
._handle
_func
_status
(status
,
508 "cannot set dynamic array length field type")
510 _length_field_class
= property(fset
=_set_length_field_class
)
513 _FIELD_CLASS_TYPE_TO_OBJ
= {
514 native_bt
.FIELD_CLASS_TYPE_UNSIGNED_INTEGER
: _UnsignedIntegerFieldClass
,
515 native_bt
.FIELD_CLASS_TYPE_SIGNED_INTEGER
: _SignedIntegerFieldClass
,
516 native_bt
.FIELD_CLASS_TYPE_REAL
: _RealFieldClass
,
517 native_bt
.FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION
: _UnsignedEnumerationFieldClass
,
518 native_bt
.FIELD_CLASS_TYPE_SIGNED_ENUMERATION
: _SignedEnumerationFieldClass
,
519 native_bt
.FIELD_CLASS_TYPE_STRING
: _StringFieldClass
,
520 native_bt
.FIELD_CLASS_TYPE_STRUCTURE
: _StructureFieldClass
,
521 native_bt
.FIELD_CLASS_TYPE_STATIC_ARRAY
: _StaticArrayFieldClass
,
522 native_bt
.FIELD_CLASS_TYPE_DYNAMIC_ARRAY
: _DynamicArrayFieldClass
,
523 native_bt
.FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR
: _VariantFieldClassWithoutSelector
,
524 native_bt
.FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR
: _VariantFieldClassWithUnsignedSelector
,
525 native_bt
.FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR
: _VariantFieldClassWithSignedSelector
,