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