bt2: add bit array field class and field support
[babeltrace.git] / src / bindings / python / bt2 / bt2 / field_class.py
1 # The MIT License (MIT)
2 #
3 # Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
4 #
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:
11 #
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
14 #
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
21 # THE SOFTWARE.
22
23 from bt2 import native_bt, object, utils
24 import collections.abc
25 from bt2 import field_path as bt2_field_path
26 from bt2 import integer_range_set as bt2_integer_range_set
27 import bt2
28
29
30 def _create_field_class_from_ptr_and_get_ref(ptr):
31 typeid = native_bt.field_class_get_type(ptr)
32 return _FIELD_CLASS_TYPE_TO_OBJ[typeid]._create_from_ptr_and_get_ref(ptr)
33
34
35 class IntegerDisplayBase:
36 BINARY = native_bt.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
37 OCTAL = native_bt.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
38 DECIMAL = native_bt.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
39 HEXADECIMAL = native_bt.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
40
41
42 class _FieldClass(object._SharedObject):
43 _get_ref = staticmethod(native_bt.field_class_get_ref)
44 _put_ref = staticmethod(native_bt.field_class_put_ref)
45
46 def _check_create_status(self, ptr):
47 if ptr is None:
48 raise bt2._MemoryError(
49 'cannot create {} field class object'.format(self._NAME.lower())
50 )
51
52
53 class _BoolFieldClass(_FieldClass):
54 _NAME = 'Boolean'
55
56
57 class _BitArrayFieldClass(_FieldClass):
58 _NAME = 'Bit array'
59
60 @property
61 def length(self):
62 length = native_bt.field_class_bit_array_get_length(self._ptr)
63 assert length >= 1
64 return length
65
66
67 class _IntegerFieldClass(_FieldClass):
68 @property
69 def field_value_range(self):
70 size = native_bt.field_class_integer_get_field_value_range(self._ptr)
71 assert size >= 1
72 return size
73
74 def _field_value_range(self, size):
75 if size < 1 or size > 64:
76 raise ValueError("Value is outside valid range [1, 64] ({})".format(size))
77 native_bt.field_class_integer_set_field_value_range(self._ptr, size)
78
79 _field_value_range = property(fset=_field_value_range)
80
81 @property
82 def preferred_display_base(self):
83 base = native_bt.field_class_integer_get_preferred_display_base(self._ptr)
84 assert base >= 0
85 return base
86
87 def _preferred_display_base(self, base):
88 utils._check_uint64(base)
89
90 if base not in (
91 IntegerDisplayBase.BINARY,
92 IntegerDisplayBase.OCTAL,
93 IntegerDisplayBase.DECIMAL,
94 IntegerDisplayBase.HEXADECIMAL,
95 ):
96 raise ValueError("Display base is not a valid IntegerDisplayBase value")
97
98 native_bt.field_class_integer_set_preferred_display_base(self._ptr, base)
99
100 _preferred_display_base = property(fset=_preferred_display_base)
101
102
103 class _UnsignedIntegerFieldClass(_IntegerFieldClass):
104 _NAME = 'Unsigned integer'
105
106
107 class _SignedIntegerFieldClass(_IntegerFieldClass):
108 _NAME = 'Signed integer'
109
110
111 class _RealFieldClass(_FieldClass):
112 _NAME = 'Real'
113
114 @property
115 def is_single_precision(self):
116 return native_bt.field_class_real_is_single_precision(self._ptr)
117
118 def _is_single_precision(self, is_single_precision):
119 utils._check_bool(is_single_precision)
120 native_bt.field_class_real_set_is_single_precision(
121 self._ptr, is_single_precision
122 )
123
124 _is_single_precision = property(fset=_is_single_precision)
125
126
127 # an enumeration field class mapping does not have a reference count, so
128 # we copy the properties here to avoid eventual memory access errors.
129 class _EnumerationFieldClassMapping:
130 def __init__(self, mapping_ptr):
131 base_mapping_ptr = self._as_enumeration_field_class_mapping_ptr(mapping_ptr)
132 self._label = native_bt.field_class_enumeration_mapping_get_label(
133 base_mapping_ptr
134 )
135 assert self._label is not None
136 ranges_ptr = self._mapping_borrow_ranges_ptr(mapping_ptr)
137 assert ranges_ptr is not None
138 self._ranges = self._ranges_type._create_from_ptr_and_get_ref(ranges_ptr)
139
140 @property
141 def label(self):
142 return self._label
143
144 @property
145 def ranges(self):
146 return self._ranges
147
148
149 class _UnsignedEnumerationFieldClassMapping(_EnumerationFieldClassMapping):
150 _ranges_type = bt2_integer_range_set.UnsignedIntegerRangeSet
151 _as_enumeration_field_class_mapping_ptr = staticmethod(
152 native_bt.field_class_enumeration_unsigned_mapping_as_mapping_const
153 )
154 _mapping_borrow_ranges_ptr = staticmethod(
155 native_bt.field_class_enumeration_unsigned_mapping_borrow_ranges_const
156 )
157
158
159 class _SignedEnumerationFieldClassMapping(_EnumerationFieldClassMapping):
160 _ranges_type = bt2_integer_range_set.SignedIntegerRangeSet
161 _as_enumeration_field_class_mapping_ptr = staticmethod(
162 native_bt.field_class_enumeration_signed_mapping_as_mapping_const
163 )
164 _mapping_borrow_ranges_ptr = staticmethod(
165 native_bt.field_class_enumeration_signed_mapping_borrow_ranges_const
166 )
167
168
169 class _EnumerationFieldClass(_IntegerFieldClass, collections.abc.Mapping):
170 def __len__(self):
171 count = native_bt.field_class_enumeration_get_mapping_count(self._ptr)
172 assert count >= 0
173 return count
174
175 def add_mapping(self, label, ranges):
176 utils._check_str(label)
177 utils._check_type(ranges, self._range_set_type)
178
179 if label in self:
180 raise ValueError("duplicate mapping label '{}'".format(label))
181
182 status = self._add_mapping(self._ptr, label, ranges._ptr)
183 utils._handle_func_status(
184 status, 'cannot add mapping to enumeration field class object'
185 )
186
187 def mappings_for_value(self, value):
188 status, labels = self._get_mapping_labels_for_value(self._ptr, value)
189 utils._handle_func_status(
190 status, 'cannot get mapping labels for value {}'.format(value)
191 )
192 return [self[label] for label in labels]
193
194 def __iter__(self):
195 for idx in range(len(self)):
196 mapping = self._get_mapping_by_index(self._ptr, idx)
197 yield mapping.label
198
199 def __getitem__(self, label):
200 utils._check_str(label)
201 mapping = self._get_mapping_by_label(self._ptr, label)
202
203 if mapping is None:
204 raise KeyError(label)
205
206 return mapping
207
208 def __iadd__(self, mappings):
209 for label, ranges in mappings:
210 self.add_mapping(label, ranges)
211
212 return self
213
214
215 class _UnsignedEnumerationFieldClass(
216 _EnumerationFieldClass, _UnsignedIntegerFieldClass
217 ):
218 _NAME = 'Unsigned enumeration'
219 _range_set_type = bt2_integer_range_set.UnsignedIntegerRangeSet
220 _add_mapping = staticmethod(native_bt.field_class_enumeration_unsigned_add_mapping)
221
222 @staticmethod
223 def _get_mapping_by_index(enum_ptr, index):
224 mapping_ptr = native_bt.field_class_enumeration_unsigned_borrow_mapping_by_index_const(
225 enum_ptr, index
226 )
227 assert mapping_ptr is not None
228 return _UnsignedEnumerationFieldClassMapping(mapping_ptr)
229
230 @staticmethod
231 def _get_mapping_by_label(enum_ptr, label):
232 mapping_ptr = native_bt.field_class_enumeration_unsigned_borrow_mapping_by_label_const(
233 enum_ptr, label
234 )
235
236 if mapping_ptr is None:
237 return
238
239 return _UnsignedEnumerationFieldClassMapping(mapping_ptr)
240
241 @staticmethod
242 def _get_mapping_labels_for_value(enum_ptr, value):
243 utils._check_uint64(value)
244 return native_bt.field_class_enumeration_unsigned_get_mapping_labels_for_value(
245 enum_ptr, value
246 )
247
248
249 class _SignedEnumerationFieldClass(_EnumerationFieldClass, _SignedIntegerFieldClass):
250 _NAME = 'Signed enumeration'
251 _range_set_type = bt2_integer_range_set.SignedIntegerRangeSet
252 _add_mapping = staticmethod(native_bt.field_class_enumeration_signed_add_mapping)
253
254 @staticmethod
255 def _get_mapping_by_index(enum_ptr, index):
256 mapping_ptr = native_bt.field_class_enumeration_signed_borrow_mapping_by_index_const(
257 enum_ptr, index
258 )
259 assert mapping_ptr is not None
260 return _SignedEnumerationFieldClassMapping(mapping_ptr)
261
262 @staticmethod
263 def _get_mapping_by_label(enum_ptr, label):
264 mapping_ptr = native_bt.field_class_enumeration_signed_borrow_mapping_by_label_const(
265 enum_ptr, label
266 )
267
268 if mapping_ptr is None:
269 return
270
271 return _SignedEnumerationFieldClassMapping(mapping_ptr)
272
273 @staticmethod
274 def _get_mapping_labels_for_value(enum_ptr, value):
275 utils._check_int64(value)
276 return native_bt.field_class_enumeration_signed_get_mapping_labels_for_value(
277 enum_ptr, value
278 )
279
280
281 class _StringFieldClass(_FieldClass):
282 _NAME = 'String'
283
284
285 class _StructureFieldClassMember:
286 def __init__(self, name, field_class):
287 self._name = name
288 self._field_class = field_class
289
290 @property
291 def name(self):
292 return self._name
293
294 @property
295 def field_class(self):
296 return self._field_class
297
298
299 class _StructureFieldClass(_FieldClass, collections.abc.Mapping):
300 _NAME = 'Structure'
301
302 def append_member(self, name, field_class):
303 utils._check_str(name)
304 utils._check_type(field_class, _FieldClass)
305
306 if name in self:
307 raise ValueError("duplicate member name '{}'".format(name))
308
309 status = native_bt.field_class_structure_append_member(
310 self._ptr, name, field_class._ptr
311 )
312 utils._handle_func_status(
313 status, 'cannot append member to structure field class object'
314 )
315
316 def __len__(self):
317 count = native_bt.field_class_structure_get_member_count(self._ptr)
318 assert count >= 0
319 return count
320
321 @staticmethod
322 def _create_member_from_ptr(member_ptr):
323 name = native_bt.field_class_structure_member_get_name(member_ptr)
324 assert name is not None
325 fc_ptr = native_bt.field_class_structure_member_borrow_field_class_const(
326 member_ptr
327 )
328 assert fc_ptr is not None
329 fc = _create_field_class_from_ptr_and_get_ref(fc_ptr)
330 return _StructureFieldClassMember(name, fc)
331
332 def __getitem__(self, key):
333 if not isinstance(key, str):
334 raise TypeError(
335 "key must be a 'str' object, got '{}'".format(key.__class__.__name__)
336 )
337
338 member_ptr = native_bt.field_class_structure_borrow_member_by_name_const(
339 self._ptr, key
340 )
341
342 if member_ptr is None:
343 raise KeyError(key)
344
345 return self._create_member_from_ptr(member_ptr)
346
347 def __iter__(self):
348 for idx in range(len(self)):
349 member_ptr = native_bt.field_class_structure_borrow_member_by_index_const(
350 self._ptr, idx
351 )
352 assert member_ptr is not None
353 yield native_bt.field_class_structure_member_get_name(member_ptr)
354
355 def __iadd__(self, members):
356 for name, field_class in members:
357 self.append_member(name, field_class)
358
359 return self
360
361 def member_at_index(self, index):
362 utils._check_uint64(index)
363
364 if index >= len(self):
365 raise IndexError
366
367 member_ptr = native_bt.field_class_structure_borrow_member_by_index_const(
368 self._ptr, index
369 )
370 assert member_ptr is not None
371 return self._create_member_from_ptr(member_ptr)
372
373
374 class _OptionFieldClass(_FieldClass):
375 @property
376 def field_class(self):
377 elem_fc_ptr = native_bt.field_class_option_borrow_field_class_const(self._ptr)
378 return _create_field_class_from_ptr_and_get_ref(elem_fc_ptr)
379
380 @property
381 def selector_field_path(self):
382 ptr = native_bt.field_class_option_borrow_selector_field_path_const(self._ptr)
383 if ptr is None:
384 return
385
386 return bt2_field_path._FieldPath._create_from_ptr_and_get_ref(ptr)
387
388
389 class _VariantFieldClassOption:
390 def __init__(self, name, field_class):
391 self._name = name
392 self._field_class = field_class
393
394 @property
395 def name(self):
396 return self._name
397
398 @property
399 def field_class(self):
400 return self._field_class
401
402
403 class _VariantFieldClassWithSelectorOption(_VariantFieldClassOption):
404 def __init__(self, name, field_class, ranges):
405 super().__init__(name, field_class)
406 self._ranges = ranges
407
408 @property
409 def ranges(self):
410 return self._ranges
411
412
413 class _VariantFieldClass(_FieldClass, collections.abc.Mapping):
414 _NAME = 'Variant'
415 _borrow_option_by_name_ptr = staticmethod(
416 native_bt.field_class_variant_borrow_option_by_name_const
417 )
418 _borrow_member_by_index_ptr = staticmethod(
419 native_bt.field_class_variant_borrow_option_by_index_const
420 )
421
422 @staticmethod
423 def _as_option_ptr(opt_ptr):
424 return opt_ptr
425
426 def _create_option_from_ptr(self, opt_ptr):
427 name = native_bt.field_class_variant_option_get_name(opt_ptr)
428 assert name is not None
429 fc_ptr = native_bt.field_class_variant_option_borrow_field_class_const(opt_ptr)
430 assert fc_ptr is not None
431 fc = _create_field_class_from_ptr_and_get_ref(fc_ptr)
432 return _VariantFieldClassOption(name, fc)
433
434 def __len__(self):
435 count = native_bt.field_class_variant_get_option_count(self._ptr)
436 assert count >= 0
437 return count
438
439 def __getitem__(self, key):
440 if not isinstance(key, str):
441 raise TypeError(
442 "key must be a 'str' object, got '{}'".format(key.__class__.__name__)
443 )
444
445 opt_ptr = self._borrow_option_by_name_ptr(self._ptr, key)
446
447 if opt_ptr is None:
448 raise KeyError(key)
449
450 return self._create_option_from_ptr(opt_ptr)
451
452 def __iter__(self):
453 for idx in range(len(self)):
454 opt_ptr = self._borrow_member_by_index_ptr(self._ptr, idx)
455 assert opt_ptr is not None
456 base_opt_ptr = self._as_option_ptr(opt_ptr)
457 yield native_bt.field_class_variant_option_get_name(base_opt_ptr)
458
459 def option_at_index(self, index):
460 utils._check_uint64(index)
461
462 if index >= len(self):
463 raise IndexError
464
465 opt_ptr = self._borrow_member_by_index_ptr(self._ptr, index)
466 assert opt_ptr is not None
467 return self._create_option_from_ptr(opt_ptr)
468
469
470 class _VariantFieldClassWithoutSelector(_VariantFieldClass):
471 _NAME = 'Variant (without selector)'
472
473 def append_option(self, name, field_class):
474 utils._check_str(name)
475 utils._check_type(field_class, _FieldClass)
476
477 if name in self:
478 raise ValueError("duplicate option name '{}'".format(name))
479
480 status = native_bt.field_class_variant_without_selector_append_option(
481 self._ptr, name, field_class._ptr
482 )
483 utils._handle_func_status(
484 status, 'cannot append option to variant field class object'
485 )
486
487 def __iadd__(self, options):
488 for name, field_class in options:
489 self.append_option(name, field_class)
490
491 return self
492
493
494 class _VariantFieldClassWithSelector(_VariantFieldClass):
495 _NAME = 'Variant (with selector)'
496
497 def _create_option_from_ptr(self, opt_ptr):
498 base_opt_ptr = self._as_option_ptr(opt_ptr)
499 name = native_bt.field_class_variant_option_get_name(base_opt_ptr)
500 assert name is not None
501 fc_ptr = native_bt.field_class_variant_option_borrow_field_class_const(
502 base_opt_ptr
503 )
504 assert fc_ptr is not None
505 fc = _create_field_class_from_ptr_and_get_ref(fc_ptr)
506 range_set_ptr = self._option_borrow_ranges_ptr(opt_ptr)
507 assert range_set_ptr is not None
508 range_set = self._range_set_type._create_from_ptr_and_get_ref(range_set_ptr)
509 return _VariantFieldClassWithSelectorOption(name, fc, range_set)
510
511 @property
512 def selector_field_path(self):
513 ptr = native_bt.field_class_variant_with_selector_borrow_selector_field_path_const(
514 self._ptr
515 )
516
517 if ptr is None:
518 return
519
520 return bt2_field_path._FieldPath._create_from_ptr_and_get_ref(ptr)
521
522 def append_option(self, name, field_class, ranges):
523 utils._check_str(name)
524 utils._check_type(field_class, _FieldClass)
525 utils._check_type(ranges, self._range_set_type)
526
527 if name in self:
528 raise ValueError("duplicate option name '{}'".format(name))
529
530 if len(ranges) == 0:
531 raise ValueError('range set is empty')
532
533 # TODO: check overlaps (precondition of self._append_option())
534
535 status = self._append_option(self._ptr, name, field_class._ptr, ranges._ptr)
536 utils._handle_func_status(
537 status, 'cannot append option to variant field class object'
538 )
539
540 def __iadd__(self, options):
541 for name, field_class, ranges in options:
542 self.append_option(name, field_class, ranges)
543
544 return self
545
546
547 class _VariantFieldClassWithUnsignedSelector(_VariantFieldClassWithSelector):
548 _NAME = 'Variant (with unsigned selector)'
549 _borrow_option_by_name_ptr = staticmethod(
550 native_bt.field_class_variant_with_selector_unsigned_borrow_option_by_name_const
551 )
552 _borrow_member_by_index_ptr = staticmethod(
553 native_bt.field_class_variant_with_selector_unsigned_borrow_option_by_index_const
554 )
555 _as_option_ptr = staticmethod(
556 native_bt.field_class_variant_with_selector_unsigned_option_as_option_const
557 )
558 _append_option = staticmethod(
559 native_bt.field_class_variant_with_selector_unsigned_append_option
560 )
561 _option_borrow_ranges_ptr = staticmethod(
562 native_bt.field_class_variant_with_selector_unsigned_option_borrow_ranges_const
563 )
564 _range_set_type = bt2_integer_range_set.UnsignedIntegerRangeSet
565
566
567 class _VariantFieldClassWithSignedSelector(_VariantFieldClassWithSelector):
568 _NAME = 'Variant (with signed selector)'
569 _borrow_option_by_name_ptr = staticmethod(
570 native_bt.field_class_variant_with_selector_signed_borrow_option_by_name_const
571 )
572 _borrow_member_by_index_ptr = staticmethod(
573 native_bt.field_class_variant_with_selector_signed_borrow_option_by_index_const
574 )
575 _as_option_ptr = staticmethod(
576 native_bt.field_class_variant_with_selector_signed_option_as_option_const
577 )
578 _append_option = staticmethod(
579 native_bt.field_class_variant_with_selector_signed_append_option
580 )
581 _option_borrow_ranges_ptr = staticmethod(
582 native_bt.field_class_variant_with_selector_signed_option_borrow_ranges_const
583 )
584 _range_set_type = bt2_integer_range_set.SignedIntegerRangeSet
585
586
587 class _ArrayFieldClass(_FieldClass):
588 @property
589 def element_field_class(self):
590 elem_fc_ptr = native_bt.field_class_array_borrow_element_field_class_const(
591 self._ptr
592 )
593 return _create_field_class_from_ptr_and_get_ref(elem_fc_ptr)
594
595
596 class _StaticArrayFieldClass(_ArrayFieldClass):
597 @property
598 def length(self):
599 return native_bt.field_class_array_static_get_length(self._ptr)
600
601
602 class _DynamicArrayFieldClass(_ArrayFieldClass):
603 @property
604 def length_field_path(self):
605 ptr = native_bt.field_class_array_dynamic_borrow_length_field_path_const(
606 self._ptr
607 )
608 if ptr is None:
609 return
610
611 return bt2_field_path._FieldPath._create_from_ptr_and_get_ref(ptr)
612
613
614 _FIELD_CLASS_TYPE_TO_OBJ = {
615 native_bt.FIELD_CLASS_TYPE_BOOL: _BoolFieldClass,
616 native_bt.FIELD_CLASS_TYPE_BIT_ARRAY: _BitArrayFieldClass,
617 native_bt.FIELD_CLASS_TYPE_UNSIGNED_INTEGER: _UnsignedIntegerFieldClass,
618 native_bt.FIELD_CLASS_TYPE_SIGNED_INTEGER: _SignedIntegerFieldClass,
619 native_bt.FIELD_CLASS_TYPE_REAL: _RealFieldClass,
620 native_bt.FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: _UnsignedEnumerationFieldClass,
621 native_bt.FIELD_CLASS_TYPE_SIGNED_ENUMERATION: _SignedEnumerationFieldClass,
622 native_bt.FIELD_CLASS_TYPE_STRING: _StringFieldClass,
623 native_bt.FIELD_CLASS_TYPE_STRUCTURE: _StructureFieldClass,
624 native_bt.FIELD_CLASS_TYPE_STATIC_ARRAY: _StaticArrayFieldClass,
625 native_bt.FIELD_CLASS_TYPE_DYNAMIC_ARRAY: _DynamicArrayFieldClass,
626 native_bt.FIELD_CLASS_TYPE_OPTION: _OptionFieldClass,
627 native_bt.FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR: _VariantFieldClassWithoutSelector,
628 native_bt.FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_SELECTOR: _VariantFieldClassWithUnsignedSelector,
629 native_bt.FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_SELECTOR: _VariantFieldClassWithSignedSelector,
630 }
This page took 0.042181 seconds and 5 git commands to generate.