Commit | Line | Data |
---|---|---|
0235b0db | 1 | # SPDX-License-Identifier: MIT |
81447b5b | 2 | # |
811644b8 | 3 | # Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com> |
81447b5b PP |
4 | |
5 | from bt2 import native_bt, object, utils | |
3fb99a22 | 6 | from bt2 import field_class as bt2_field_class |
81447b5b PP |
7 | import collections.abc |
8 | import functools | |
9 | import numbers | |
10 | import math | |
81447b5b PP |
11 | |
12 | ||
f0a42b33 FD |
13 | def _create_field_from_ptr_template( |
14 | object_map, ptr, owner_ptr, owner_get_ref, owner_put_ref | |
15 | ): | |
16 | ||
2ae9f48c | 17 | field_class_ptr = native_bt.field_borrow_class_const(ptr) |
2ae9f48c | 18 | typeid = native_bt.field_class_get_type(field_class_ptr) |
f0a42b33 | 19 | field = object_map[typeid]._create_from_ptr_and_get_ref( |
cfbd7cf3 FD |
20 | ptr, owner_ptr, owner_get_ref, owner_put_ref |
21 | ) | |
81447b5b PP |
22 | return field |
23 | ||
24 | ||
f0a42b33 FD |
25 | def _create_field_from_ptr(ptr, owner_ptr, owner_get_ref, owner_put_ref): |
26 | return _create_field_from_ptr_template( | |
27 | _TYPE_ID_TO_OBJ, ptr, owner_ptr, owner_get_ref, owner_put_ref | |
28 | ) | |
29 | ||
30 | ||
31 | def _create_field_from_const_ptr(ptr, owner_ptr, owner_get_ref, owner_put_ref): | |
32 | return _create_field_from_ptr_template( | |
33 | _TYPE_ID_TO_CONST_OBJ, ptr, owner_ptr, owner_get_ref, owner_put_ref | |
34 | ) | |
35 | ||
36 | ||
cec0261d PP |
37 | # Get the "effective" field of `field`. If `field` is a variant, return |
38 | # the currently selected field. If `field` is an option, return the | |
39 | # content field. If `field` is of any other type, return `field` | |
1eccc498 | 40 | # directly. |
81447b5b | 41 | |
cfbd7cf3 | 42 | |
1eccc498 | 43 | def _get_leaf_field(field): |
f0a42b33 | 44 | if isinstance(field, _VariantFieldConst): |
cec0261d | 45 | return _get_leaf_field(field.selected_option) |
1eccc498 | 46 | |
f0a42b33 | 47 | if isinstance(field, _OptionFieldConst): |
cec0261d PP |
48 | return _get_leaf_field(field.field) |
49 | ||
50 | return field | |
81447b5b | 51 | |
e1c6bebd | 52 | |
f0a42b33 FD |
53 | class _FieldConst(object._UniqueObject): |
54 | _create_field_from_ptr = staticmethod(_create_field_from_const_ptr) | |
55 | _create_field_class_from_ptr_and_get_ref = staticmethod( | |
56 | bt2_field_class._create_field_class_from_const_ptr_and_get_ref | |
57 | ) | |
58 | _borrow_class_ptr = staticmethod(native_bt.field_borrow_class_const) | |
59 | ||
1eccc498 | 60 | def __eq__(self, other): |
e1c6bebd JG |
61 | other = _get_leaf_field(other) |
62 | return self._spec_eq(other) | |
63 | ||
81447b5b | 64 | @property |
d8e2073c | 65 | def cls(self): |
f0a42b33 | 66 | field_class_ptr = self._borrow_class_ptr(self._ptr) |
838a5a52 | 67 | assert field_class_ptr is not None |
f0a42b33 | 68 | return self._create_field_class_from_ptr_and_get_ref(field_class_ptr) |
81447b5b | 69 | |
12bf0d88 JG |
70 | def _repr(self): |
71 | raise NotImplementedError | |
72 | ||
73 | def __repr__(self): | |
1eccc498 | 74 | return self._repr() |
12bf0d88 | 75 | |
81447b5b | 76 | |
f0a42b33 FD |
77 | class _Field(_FieldConst): |
78 | _create_field_from_ptr = staticmethod(_create_field_from_ptr) | |
79 | _create_field_class_from_ptr_and_get_ref = staticmethod( | |
80 | bt2_field_class._create_field_class_from_ptr_and_get_ref | |
81 | ) | |
82 | _borrow_class_ptr = staticmethod(native_bt.field_borrow_class) | |
83 | ||
84 | ||
85 | class _BitArrayFieldConst(_FieldConst): | |
86 | _NAME = 'Const bit array' | |
ead8c3d4 PP |
87 | |
88 | @property | |
89 | def value_as_integer(self): | |
90 | return native_bt.field_bit_array_get_value_as_integer(self._ptr) | |
91 | ||
ead8c3d4 PP |
92 | def _spec_eq(self, other): |
93 | if type(other) is not type(self): | |
94 | return False | |
95 | ||
96 | return self.value_as_integer == other.value_as_integer | |
97 | ||
98 | def _repr(self): | |
99 | return repr(self.value_as_integer) | |
100 | ||
101 | def __str__(self): | |
102 | return str(self.value_as_integer) | |
103 | ||
104 | def __len__(self): | |
d8e2073c | 105 | return self.cls.length |
ead8c3d4 PP |
106 | |
107 | ||
f0a42b33 FD |
108 | class _BitArrayField(_BitArrayFieldConst, _Field): |
109 | _NAME = 'Bit array' | |
110 | ||
111 | def _value_as_integer(self, value): | |
112 | utils._check_uint64(value) | |
113 | native_bt.field_bit_array_set_value_as_integer(self._ptr, value) | |
114 | ||
115 | value_as_integer = property( | |
116 | fget=_BitArrayFieldConst.value_as_integer.fget, fset=_value_as_integer | |
117 | ) | |
118 | ||
119 | ||
81447b5b | 120 | @functools.total_ordering |
f0a42b33 | 121 | class _NumericFieldConst(_FieldConst): |
81447b5b PP |
122 | @staticmethod |
123 | def _extract_value(other): | |
f0a42b33 | 124 | if isinstance(other, _BoolFieldConst) or isinstance(other, bool): |
aae30e61 | 125 | return bool(other) |
81447b5b PP |
126 | |
127 | if isinstance(other, numbers.Integral): | |
128 | return int(other) | |
129 | ||
130 | if isinstance(other, numbers.Real): | |
131 | return float(other) | |
132 | ||
133 | if isinstance(other, numbers.Complex): | |
134 | return complex(other) | |
135 | ||
cfbd7cf3 FD |
136 | raise TypeError( |
137 | "'{}' object is not a number object".format(other.__class__.__name__) | |
138 | ) | |
81447b5b PP |
139 | |
140 | def __int__(self): | |
e1c6bebd | 141 | return int(self._value) |
81447b5b PP |
142 | |
143 | def __float__(self): | |
e1c6bebd | 144 | return float(self._value) |
81447b5b | 145 | |
12bf0d88 | 146 | def _repr(self): |
5abb9e33 | 147 | return repr(self._value) |
81447b5b PP |
148 | |
149 | def __lt__(self, other): | |
150 | if not isinstance(other, numbers.Number): | |
cfbd7cf3 FD |
151 | raise TypeError( |
152 | 'unorderable types: {}() < {}()'.format( | |
153 | self.__class__.__name__, other.__class__.__name__ | |
154 | ) | |
155 | ) | |
81447b5b | 156 | |
09a926c1 | 157 | return self._value < self._extract_value(other) |
81447b5b | 158 | |
e1c6bebd | 159 | def _spec_eq(self, other): |
f11ed062 PP |
160 | try: |
161 | return self._value == self._extract_value(other) | |
4c4935bf | 162 | except Exception: |
f11ed062 | 163 | return False |
81447b5b | 164 | |
dda659b3 FD |
165 | def __hash__(self): |
166 | return hash(self._value) | |
167 | ||
81447b5b | 168 | def __rmod__(self, other): |
e1c6bebd | 169 | return self._extract_value(other) % self._value |
81447b5b PP |
170 | |
171 | def __mod__(self, other): | |
e1c6bebd | 172 | return self._value % self._extract_value(other) |
81447b5b PP |
173 | |
174 | def __rfloordiv__(self, other): | |
e1c6bebd | 175 | return self._extract_value(other) // self._value |
81447b5b PP |
176 | |
177 | def __floordiv__(self, other): | |
e1c6bebd | 178 | return self._value // self._extract_value(other) |
81447b5b PP |
179 | |
180 | def __round__(self, ndigits=None): | |
181 | if ndigits is None: | |
e1c6bebd | 182 | return round(self._value) |
81447b5b | 183 | else: |
e1c6bebd | 184 | return round(self._value, ndigits) |
81447b5b PP |
185 | |
186 | def __ceil__(self): | |
e1c6bebd | 187 | return math.ceil(self._value) |
81447b5b PP |
188 | |
189 | def __floor__(self): | |
e1c6bebd | 190 | return math.floor(self._value) |
81447b5b PP |
191 | |
192 | def __trunc__(self): | |
e1c6bebd | 193 | return int(self._value) |
81447b5b PP |
194 | |
195 | def __abs__(self): | |
e1c6bebd | 196 | return abs(self._value) |
81447b5b PP |
197 | |
198 | def __add__(self, other): | |
e1c6bebd | 199 | return self._value + self._extract_value(other) |
81447b5b PP |
200 | |
201 | def __radd__(self, other): | |
202 | return self.__add__(other) | |
203 | ||
204 | def __neg__(self): | |
e1c6bebd | 205 | return -self._value |
81447b5b PP |
206 | |
207 | def __pos__(self): | |
e1c6bebd | 208 | return +self._value |
81447b5b PP |
209 | |
210 | def __mul__(self, other): | |
e1c6bebd | 211 | return self._value * self._extract_value(other) |
81447b5b PP |
212 | |
213 | def __rmul__(self, other): | |
214 | return self.__mul__(other) | |
215 | ||
216 | def __truediv__(self, other): | |
e1c6bebd | 217 | return self._value / self._extract_value(other) |
81447b5b PP |
218 | |
219 | def __rtruediv__(self, other): | |
e1c6bebd | 220 | return self._extract_value(other) / self._value |
81447b5b PP |
221 | |
222 | def __pow__(self, exponent): | |
e1c6bebd | 223 | return self._value ** self._extract_value(exponent) |
81447b5b PP |
224 | |
225 | def __rpow__(self, base): | |
e1c6bebd | 226 | return self._extract_value(base) ** self._value |
81447b5b | 227 | |
81447b5b | 228 | |
f0a42b33 | 229 | class _NumericField(_NumericFieldConst, _Field): |
dda659b3 FD |
230 | def __hash__(self): |
231 | # Non const field are not hashable as their value may be modified | |
232 | # without changing the underlying Python object. | |
233 | raise TypeError('unhashable type: \'{}\''.format(self._NAME)) | |
f0a42b33 FD |
234 | |
235 | ||
236 | class _IntegralFieldConst(_NumericFieldConst, numbers.Integral): | |
81447b5b | 237 | def __lshift__(self, other): |
e1c6bebd | 238 | return self._value << self._extract_value(other) |
81447b5b PP |
239 | |
240 | def __rlshift__(self, other): | |
e1c6bebd | 241 | return self._extract_value(other) << self._value |
81447b5b PP |
242 | |
243 | def __rshift__(self, other): | |
e1c6bebd | 244 | return self._value >> self._extract_value(other) |
81447b5b PP |
245 | |
246 | def __rrshift__(self, other): | |
e1c6bebd | 247 | return self._extract_value(other) >> self._value |
81447b5b PP |
248 | |
249 | def __and__(self, other): | |
e1c6bebd | 250 | return self._value & self._extract_value(other) |
81447b5b PP |
251 | |
252 | def __rand__(self, other): | |
e1c6bebd | 253 | return self._extract_value(other) & self._value |
81447b5b PP |
254 | |
255 | def __xor__(self, other): | |
e1c6bebd | 256 | return self._value ^ self._extract_value(other) |
81447b5b PP |
257 | |
258 | def __rxor__(self, other): | |
e1c6bebd | 259 | return self._extract_value(other) ^ self._value |
81447b5b PP |
260 | |
261 | def __or__(self, other): | |
e1c6bebd | 262 | return self._value | self._extract_value(other) |
81447b5b PP |
263 | |
264 | def __ror__(self, other): | |
e1c6bebd | 265 | return self._extract_value(other) | self._value |
81447b5b PP |
266 | |
267 | def __invert__(self): | |
e1c6bebd | 268 | return ~self._value |
81447b5b | 269 | |
81447b5b | 270 | |
f0a42b33 FD |
271 | class _IntegralField(_IntegralFieldConst, _NumericField): |
272 | pass | |
273 | ||
274 | ||
275 | class _BoolFieldConst(_IntegralFieldConst, _FieldConst): | |
276 | _NAME = 'Const boolean' | |
aae30e61 PP |
277 | |
278 | def __bool__(self): | |
279 | return self._value | |
280 | ||
f0a42b33 FD |
281 | @classmethod |
282 | def _value_to_bool(cls, value): | |
283 | if isinstance(value, _BoolFieldConst): | |
aae30e61 PP |
284 | value = value._value |
285 | ||
286 | if not isinstance(value, bool): | |
287 | raise TypeError( | |
f0a42b33 | 288 | "'{}' object is not a 'bool', '_BoolFieldConst', or '_BoolField' object".format( |
aae30e61 PP |
289 | value.__class__ |
290 | ) | |
291 | ) | |
292 | ||
293 | return value | |
294 | ||
295 | @property | |
296 | def _value(self): | |
297 | return bool(native_bt.field_bool_get_value(self._ptr)) | |
298 | ||
f0a42b33 FD |
299 | |
300 | class _BoolField(_BoolFieldConst, _IntegralField, _Field): | |
301 | _NAME = 'Boolean' | |
302 | ||
aae30e61 PP |
303 | def _set_value(self, value): |
304 | value = self._value_to_bool(value) | |
305 | native_bt.field_bool_set_value(self._ptr, value) | |
306 | ||
307 | value = property(fset=_set_value) | |
308 | ||
309 | ||
f0a42b33 | 310 | class _IntegerFieldConst(_IntegralFieldConst, _FieldConst): |
81447b5b PP |
311 | pass |
312 | ||
313 | ||
f0a42b33 | 314 | class _IntegerField(_IntegerFieldConst, _IntegralField, _Field): |
1198c635 FD |
315 | def _check_range(self, value): |
316 | if not (value >= self._lower_bound and value <= self._upper_bound): | |
317 | raise ValueError( | |
318 | "Value {} is outside valid range [{}, {}]".format( | |
319 | value, self._lower_bound, self._upper_bound | |
320 | ) | |
321 | ) | |
f0a42b33 FD |
322 | |
323 | ||
324 | class _UnsignedIntegerFieldConst(_IntegerFieldConst, _FieldConst): | |
325 | _NAME = 'Const unsigned integer' | |
1eccc498 | 326 | |
f0a42b33 FD |
327 | @classmethod |
328 | def _value_to_int(cls, value): | |
25bb9bab PP |
329 | if not isinstance(value, numbers.Integral): |
330 | raise TypeError('expecting an integral number object') | |
81447b5b | 331 | |
1198c635 | 332 | return int(value) |
81447b5b PP |
333 | |
334 | @property | |
e1c6bebd | 335 | def _value(self): |
9c08c816 | 336 | return native_bt.field_integer_unsigned_get_value(self._ptr) |
81447b5b | 337 | |
f0a42b33 FD |
338 | |
339 | class _UnsignedIntegerField(_UnsignedIntegerFieldConst, _IntegerField, _Field): | |
340 | _NAME = 'Unsigned integer' | |
341 | ||
2ae9f48c SM |
342 | def _set_value(self, value): |
343 | value = self._value_to_int(value) | |
1198c635 FD |
344 | |
345 | self._check_range(value) | |
346 | ||
9c08c816 | 347 | native_bt.field_integer_unsigned_set_value(self._ptr, value) |
2ae9f48c SM |
348 | |
349 | value = property(fset=_set_value) | |
350 | ||
1198c635 FD |
351 | @property |
352 | def _lower_bound(self): | |
353 | return 0 | |
354 | ||
355 | @property | |
356 | def _upper_bound(self): | |
768f9bcb | 357 | return (2**self.cls.field_value_range) - 1 |
1198c635 | 358 | |
2ae9f48c | 359 | |
f0a42b33 FD |
360 | class _SignedIntegerFieldConst(_IntegerFieldConst, _FieldConst): |
361 | _NAME = 'Const signed integer' | |
1eccc498 | 362 | |
f0a42b33 FD |
363 | @classmethod |
364 | def _value_to_int(cls, value): | |
25bb9bab PP |
365 | if not isinstance(value, numbers.Integral): |
366 | raise TypeError('expecting an integral number object') | |
e1c6bebd | 367 | |
1198c635 | 368 | return int(value) |
81447b5b | 369 | |
2ae9f48c SM |
370 | @property |
371 | def _value(self): | |
9c08c816 | 372 | return native_bt.field_integer_signed_get_value(self._ptr) |
2ae9f48c | 373 | |
f0a42b33 FD |
374 | |
375 | class _SignedIntegerField(_SignedIntegerFieldConst, _IntegerField, _Field): | |
376 | _NAME = 'Signed integer' | |
377 | ||
e1c6bebd | 378 | def _set_value(self, value): |
81447b5b | 379 | value = self._value_to_int(value) |
1198c635 FD |
380 | |
381 | self._check_range(value) | |
382 | ||
9c08c816 | 383 | native_bt.field_integer_signed_set_value(self._ptr, value) |
81447b5b | 384 | |
e1c6bebd | 385 | value = property(fset=_set_value) |
81447b5b | 386 | |
1198c635 FD |
387 | @property |
388 | def _lower_bound(self): | |
389 | return -1 * (2 ** (self.cls.field_value_range - 1)) | |
390 | ||
391 | @property | |
392 | def _upper_bound(self): | |
393 | return (2 ** (self.cls.field_value_range - 1)) - 1 | |
394 | ||
0b03f63e | 395 | |
f0a42b33 FD |
396 | class _RealFieldConst(_NumericFieldConst, numbers.Real): |
397 | _NAME = 'Const real' | |
81447b5b | 398 | |
f0a42b33 FD |
399 | @classmethod |
400 | def _value_to_float(cls, value): | |
81447b5b PP |
401 | if not isinstance(value, numbers.Real): |
402 | raise TypeError("expecting a real number object") | |
403 | ||
404 | return float(value) | |
405 | ||
fe4df857 FD |
406 | |
407 | class _SinglePrecisionRealFieldConst(_RealFieldConst): | |
408 | _NAME = 'Const single-precision real' | |
409 | ||
410 | @property | |
411 | def _value(self): | |
412 | return native_bt.field_real_single_precision_get_value(self._ptr) | |
413 | ||
414 | ||
415 | class _DoublePrecisionRealFieldConst(_RealFieldConst): | |
416 | _NAME = 'Const double-precision real' | |
417 | ||
81447b5b | 418 | @property |
e1c6bebd | 419 | def _value(self): |
fe4df857 | 420 | return native_bt.field_real_double_precision_get_value(self._ptr) |
81447b5b | 421 | |
f0a42b33 FD |
422 | |
423 | class _RealField(_RealFieldConst, _NumericField): | |
424 | _NAME = 'Real' | |
425 | ||
fe4df857 FD |
426 | |
427 | class _SinglePrecisionRealField(_SinglePrecisionRealFieldConst, _RealField): | |
428 | _NAME = 'Single-precision real' | |
429 | ||
430 | def _set_value(self, value): | |
431 | value = self._value_to_float(value) | |
432 | native_bt.field_real_single_precision_set_value(self._ptr, value) | |
433 | ||
434 | value = property(fset=_set_value) | |
435 | ||
436 | ||
437 | class _DoublePrecisionRealField(_DoublePrecisionRealFieldConst, _RealField): | |
438 | _NAME = 'Double-precision real' | |
439 | ||
e1c6bebd | 440 | def _set_value(self, value): |
81447b5b | 441 | value = self._value_to_float(value) |
fe4df857 | 442 | native_bt.field_real_double_precision_set_value(self._ptr, value) |
81447b5b | 443 | |
e1c6bebd | 444 | value = property(fset=_set_value) |
81447b5b | 445 | |
0b03f63e | 446 | |
f0a42b33 | 447 | class _EnumerationFieldConst(_IntegerFieldConst): |
1eccc498 SM |
448 | def _repr(self): |
449 | return '{} ({})'.format(self._value, ', '.join(self.labels)) | |
81447b5b PP |
450 | |
451 | @property | |
1eccc498 | 452 | def labels(self): |
d24d5663 | 453 | status, labels = self._get_mapping_labels(self._ptr) |
cfbd7cf3 | 454 | utils._handle_func_status(status, "cannot get label for enumeration field") |
81447b5b | 455 | |
1eccc498 SM |
456 | assert labels is not None |
457 | return labels | |
81447b5b | 458 | |
4addd228 | 459 | |
f0a42b33 FD |
460 | class _EnumerationField(_EnumerationFieldConst, _IntegerField): |
461 | pass | |
462 | ||
463 | ||
464 | class _UnsignedEnumerationFieldConst( | |
465 | _EnumerationFieldConst, _UnsignedIntegerFieldConst | |
466 | ): | |
467 | _NAME = 'Const unsigned Enumeration' | |
cfbd7cf3 | 468 | _get_mapping_labels = staticmethod( |
9c08c816 | 469 | native_bt.field_enumeration_unsigned_get_mapping_labels |
cfbd7cf3 | 470 | ) |
e1c6bebd | 471 | |
e1c6bebd | 472 | |
f0a42b33 FD |
473 | class _UnsignedEnumerationField( |
474 | _UnsignedEnumerationFieldConst, _EnumerationField, _UnsignedIntegerField | |
475 | ): | |
476 | _NAME = 'Unsigned enumeration' | |
477 | ||
478 | ||
479 | class _SignedEnumerationFieldConst(_EnumerationFieldConst, _SignedIntegerFieldConst): | |
480 | _NAME = 'Const signed Enumeration' | |
cfbd7cf3 | 481 | _get_mapping_labels = staticmethod( |
9c08c816 | 482 | native_bt.field_enumeration_signed_get_mapping_labels |
cfbd7cf3 | 483 | ) |
81447b5b PP |
484 | |
485 | ||
f0a42b33 FD |
486 | class _SignedEnumerationField( |
487 | _SignedEnumerationFieldConst, _EnumerationField, _SignedIntegerField | |
488 | ): | |
489 | _NAME = 'Signed enumeration' | |
490 | ||
491 | ||
81447b5b | 492 | @functools.total_ordering |
f0a42b33 FD |
493 | class _StringFieldConst(_FieldConst): |
494 | _NAME = 'Const string' | |
81447b5b | 495 | |
f0a42b33 FD |
496 | @classmethod |
497 | def _value_to_str(cls, value): | |
498 | if isinstance(value, _StringFieldConst): | |
e1c6bebd | 499 | value = value._value |
81447b5b PP |
500 | |
501 | if not isinstance(value, str): | |
502 | raise TypeError("expecting a 'str' object") | |
503 | ||
504 | return value | |
505 | ||
506 | @property | |
e1c6bebd | 507 | def _value(self): |
1eccc498 | 508 | return native_bt.field_string_get_value(self._ptr) |
81447b5b | 509 | |
e1c6bebd | 510 | def _spec_eq(self, other): |
81447b5b | 511 | try: |
f11ed062 | 512 | return self._value == self._value_to_str(other) |
4c4935bf | 513 | except Exception: |
81447b5b PP |
514 | return False |
515 | ||
81447b5b | 516 | def __lt__(self, other): |
e1c6bebd | 517 | return self._value < self._value_to_str(other) |
81447b5b PP |
518 | |
519 | def __bool__(self): | |
e1c6bebd | 520 | return bool(self._value) |
81447b5b | 521 | |
dda659b3 FD |
522 | def __hash__(self): |
523 | return hash(self._value) | |
524 | ||
12bf0d88 | 525 | def _repr(self): |
d623d2e9 JG |
526 | return repr(self._value) |
527 | ||
81447b5b | 528 | def __str__(self): |
1eccc498 | 529 | return str(self._value) |
81447b5b PP |
530 | |
531 | def __getitem__(self, index): | |
e1c6bebd | 532 | return self._value[index] |
81447b5b PP |
533 | |
534 | def __len__(self): | |
1eccc498 | 535 | return native_bt.field_string_get_length(self._ptr) |
81447b5b | 536 | |
f0a42b33 FD |
537 | |
538 | class _StringField(_StringFieldConst, _Field): | |
539 | _NAME = 'String' | |
540 | ||
541 | def _set_value(self, value): | |
542 | value = self._value_to_str(value) | |
543 | native_bt.field_string_set_value(self._ptr, value) | |
544 | ||
545 | value = property(fset=_set_value) | |
546 | ||
81447b5b PP |
547 | def __iadd__(self, value): |
548 | value = self._value_to_str(value) | |
d24d5663 | 549 | status = native_bt.field_string_append(self._ptr, value) |
cfbd7cf3 FD |
550 | utils._handle_func_status( |
551 | status, "cannot append to string field object's value" | |
552 | ) | |
81447b5b PP |
553 | return self |
554 | ||
dda659b3 FD |
555 | def __hash__(self): |
556 | # Non const field are not hashable as their value may be modified | |
557 | # without changing the underlying Python object. | |
558 | raise TypeError('unhashable type: \'{}\''.format(self._NAME)) | |
559 | ||
81447b5b | 560 | |
f0a42b33 | 561 | class _ContainerFieldConst(_FieldConst): |
81447b5b PP |
562 | def __bool__(self): |
563 | return len(self) != 0 | |
564 | ||
f0a42b33 FD |
565 | def _count(self): |
566 | return len(self.cls) | |
567 | ||
81447b5b PP |
568 | def __len__(self): |
569 | count = self._count() | |
1eccc498 | 570 | assert count >= 0 |
81447b5b PP |
571 | return count |
572 | ||
573 | def __delitem__(self, index): | |
574 | raise NotImplementedError | |
575 | ||
f0a42b33 FD |
576 | def __setitem__(self, index, value): |
577 | raise TypeError( | |
578 | '\'{}\' object does not support item assignment'.format(self.__class__) | |
579 | ) | |
81447b5b | 580 | |
81447b5b | 581 | |
f0a42b33 FD |
582 | class _ContainerField(_ContainerFieldConst, _Field): |
583 | pass | |
81447b5b | 584 | |
81447b5b | 585 | |
f0a42b33 FD |
586 | class _StructureFieldConst(_ContainerFieldConst, collections.abc.Mapping): |
587 | _NAME = 'Const structure' | |
588 | _borrow_member_field_ptr_by_index = staticmethod( | |
589 | native_bt.field_structure_borrow_member_field_by_index_const | |
590 | ) | |
591 | _borrow_member_field_ptr_by_name = staticmethod( | |
592 | native_bt.field_structure_borrow_member_field_by_name_const | |
593 | ) | |
594 | ||
595 | def _count(self): | |
596 | return len(self.cls) | |
81447b5b | 597 | |
81447b5b PP |
598 | def __iter__(self): |
599 | # same name iterator | |
d8e2073c | 600 | return iter(self.cls) |
81447b5b | 601 | |
e1c6bebd | 602 | def _spec_eq(self, other): |
f11ed062 PP |
603 | if not isinstance(other, collections.abc.Mapping): |
604 | return False | |
81447b5b | 605 | |
f11ed062 PP |
606 | if len(self) != len(other): |
607 | # early mismatch | |
608 | return False | |
81447b5b | 609 | |
f11ed062 PP |
610 | for self_key in self: |
611 | if self_key not in other: | |
612 | return False | |
81447b5b | 613 | |
f11ed062 PP |
614 | if self[self_key] != other[self_key]: |
615 | return False | |
e1c6bebd | 616 | |
f11ed062 | 617 | return True |
81447b5b | 618 | |
12bf0d88 | 619 | def _repr(self): |
ac7e2dc6 JG |
620 | items = ['{}: {}'.format(repr(k), repr(v)) for k, v in self.items()] |
621 | return '{{{}}}'.format(', '.join(items)) | |
622 | ||
1eccc498 SM |
623 | def __getitem__(self, key): |
624 | utils._check_str(key) | |
f0a42b33 | 625 | field_ptr = self._borrow_member_field_ptr_by_name(self._ptr, key) |
0b03f63e | 626 | |
1eccc498 SM |
627 | if field_ptr is None: |
628 | raise KeyError(key) | |
81447b5b | 629 | |
f0a42b33 | 630 | return self._create_field_from_ptr( |
cfbd7cf3 FD |
631 | field_ptr, self._owner_ptr, self._owner_get_ref, self._owner_put_ref |
632 | ) | |
811644b8 | 633 | |
1eccc498 SM |
634 | def member_at_index(self, index): |
635 | utils._check_uint64(index) | |
811644b8 | 636 | |
1eccc498 SM |
637 | if index >= len(self): |
638 | raise IndexError | |
f0a42b33 | 639 | field_ptr = self._borrow_member_field_ptr_by_index(self._ptr, index) |
1eccc498 | 640 | assert field_ptr is not None |
f0a42b33 | 641 | return self._create_field_from_ptr( |
cfbd7cf3 FD |
642 | field_ptr, self._owner_ptr, self._owner_get_ref, self._owner_put_ref |
643 | ) | |
1eccc498 SM |
644 | |
645 | ||
f0a42b33 FD |
646 | class _StructureField( |
647 | _StructureFieldConst, _ContainerField, collections.abc.MutableMapping | |
648 | ): | |
649 | _NAME = 'Structure' | |
650 | _borrow_member_field_ptr_by_index = staticmethod( | |
651 | native_bt.field_structure_borrow_member_field_by_index | |
652 | ) | |
653 | _borrow_member_field_ptr_by_name = staticmethod( | |
654 | native_bt.field_structure_borrow_member_field_by_name | |
655 | ) | |
656 | ||
657 | def __setitem__(self, key, value): | |
658 | # raises if key is somehow invalid | |
659 | field = self[key] | |
660 | ||
661 | # the field's property does the appropriate conversion or raises | |
662 | # the appropriate exception | |
663 | field.value = value | |
664 | ||
665 | def _set_value(self, values): | |
666 | try: | |
667 | for key, value in values.items(): | |
668 | self[key].value = value | |
669 | except Exception: | |
670 | raise | |
671 | ||
672 | value = property(fset=_set_value) | |
673 | ||
674 | ||
675 | class _OptionFieldConst(_FieldConst): | |
676 | _NAME = 'Const option' | |
677 | _borrow_field_ptr = staticmethod(native_bt.field_option_borrow_field_const) | |
cec0261d PP |
678 | |
679 | @property | |
680 | def field(self): | |
f0a42b33 | 681 | field_ptr = self._borrow_field_ptr(self._ptr) |
cec0261d PP |
682 | |
683 | if field_ptr is None: | |
684 | return | |
685 | ||
f0a42b33 | 686 | return self._create_field_from_ptr( |
cec0261d PP |
687 | field_ptr, self._owner_ptr, self._owner_get_ref, self._owner_put_ref |
688 | ) | |
689 | ||
690 | @property | |
691 | def has_field(self): | |
692 | return self.field is not None | |
693 | ||
cec0261d PP |
694 | def _spec_eq(self, other): |
695 | return _get_leaf_field(self) == other | |
696 | ||
697 | def __bool__(self): | |
698 | return self.has_field | |
699 | ||
700 | def __str__(self): | |
701 | return str(self.field) | |
702 | ||
703 | def _repr(self): | |
704 | return repr(self.field) | |
705 | ||
f0a42b33 FD |
706 | |
707 | class _OptionField(_OptionFieldConst, _Field): | |
708 | _NAME = 'Option' | |
709 | _borrow_field_ptr = staticmethod(native_bt.field_option_borrow_field) | |
710 | ||
711 | def _has_field(self, value): | |
712 | utils._check_bool(value) | |
713 | native_bt.field_option_set_has_field(self._ptr, value) | |
714 | ||
715 | has_field = property(fget=_OptionFieldConst.has_field.fget, fset=_has_field) | |
716 | ||
cec0261d PP |
717 | def _set_value(self, value): |
718 | self.has_field = True | |
719 | field = self.field | |
720 | assert field is not None | |
721 | field.value = value | |
722 | ||
723 | value = property(fset=_set_value) | |
724 | ||
725 | ||
f0a42b33 FD |
726 | class _VariantFieldConst(_ContainerFieldConst, _FieldConst): |
727 | _NAME = 'Const variant' | |
728 | _borrow_selected_option_field_ptr = staticmethod( | |
729 | native_bt.field_variant_borrow_selected_option_field_const | |
730 | ) | |
81447b5b | 731 | |
2b9aa00b FD |
732 | def _count(self): |
733 | return len(self.cls) | |
734 | ||
81447b5b | 735 | @property |
1eccc498 | 736 | def selected_option_index(self): |
7b4311c1 | 737 | return native_bt.field_variant_get_selected_option_index(self._ptr) |
81447b5b | 738 | |
1eccc498 SM |
739 | @property |
740 | def selected_option(self): | |
5ae9f1bf SM |
741 | # TODO: Is there a way to check if the variant field has a selected_option, |
742 | # so we can raise an exception instead of hitting a pre-condition check? | |
743 | # If there is something, that check should be added to selected_option_index too. | |
f0a42b33 | 744 | field_ptr = self._borrow_selected_option_field_ptr(self._ptr) |
81447b5b | 745 | |
f0a42b33 | 746 | return self._create_field_from_ptr( |
cfbd7cf3 FD |
747 | field_ptr, self._owner_ptr, self._owner_get_ref, self._owner_put_ref |
748 | ) | |
81447b5b | 749 | |
e1c6bebd | 750 | def _spec_eq(self, other): |
f11ed062 | 751 | return _get_leaf_field(self) == other |
811644b8 PP |
752 | |
753 | def __bool__(self): | |
1eccc498 | 754 | raise NotImplementedError |
81447b5b | 755 | |
12bf0d88 | 756 | def __str__(self): |
1eccc498 | 757 | return str(self.selected_option) |
12bf0d88 JG |
758 | |
759 | def _repr(self): | |
1eccc498 | 760 | return repr(self.selected_option) |
e1c6bebd | 761 | |
f0a42b33 FD |
762 | |
763 | class _VariantField(_VariantFieldConst, _ContainerField, _Field): | |
764 | _NAME = 'Variant' | |
765 | _borrow_selected_option_field_ptr = staticmethod( | |
766 | native_bt.field_variant_borrow_selected_option_field | |
767 | ) | |
768 | ||
769 | def _selected_option_index(self, index): | |
770 | if index < 0 or index >= len(self): | |
771 | raise IndexError('{} field object index is out of range'.format(self._NAME)) | |
772 | ||
7b4311c1 | 773 | native_bt.field_variant_select_option_by_index(self._ptr, index) |
f0a42b33 FD |
774 | |
775 | selected_option_index = property( | |
776 | fget=_VariantFieldConst.selected_option_index.fget, fset=_selected_option_index | |
777 | ) | |
778 | ||
e1c6bebd | 779 | def _set_value(self, value): |
1eccc498 | 780 | self.selected_option.value = value |
e1c6bebd JG |
781 | |
782 | value = property(fset=_set_value) | |
81447b5b | 783 | |
0b03f63e | 784 | |
f0a42b33 FD |
785 | class _ArrayFieldConst(_ContainerFieldConst, _FieldConst, collections.abc.Sequence): |
786 | _borrow_element_field_ptr_by_index = staticmethod( | |
787 | native_bt.field_array_borrow_element_field_by_index_const | |
788 | ) | |
789 | ||
1eccc498 SM |
790 | def _get_length(self): |
791 | return native_bt.field_array_get_length(self._ptr) | |
792 | ||
793 | length = property(fget=_get_length) | |
794 | ||
81447b5b PP |
795 | def __getitem__(self, index): |
796 | if not isinstance(index, numbers.Integral): | |
cfbd7cf3 FD |
797 | raise TypeError( |
798 | "'{}' is not an integral number object: invalid index".format( | |
799 | index.__class__.__name__ | |
800 | ) | |
801 | ) | |
81447b5b PP |
802 | |
803 | index = int(index) | |
804 | ||
805 | if index < 0 or index >= len(self): | |
806 | raise IndexError('{} field object index is out of range'.format(self._NAME)) | |
807 | ||
f0a42b33 | 808 | field_ptr = self._borrow_element_field_ptr_by_index(self._ptr, index) |
cfbd7cf3 | 809 | assert field_ptr |
f0a42b33 | 810 | return self._create_field_from_ptr( |
cfbd7cf3 FD |
811 | field_ptr, self._owner_ptr, self._owner_get_ref, self._owner_put_ref |
812 | ) | |
81447b5b | 813 | |
81447b5b PP |
814 | def insert(self, index, value): |
815 | raise NotImplementedError | |
816 | ||
e1c6bebd | 817 | def _spec_eq(self, other): |
f11ed062 PP |
818 | if not isinstance(other, collections.abc.Sequence): |
819 | return False | |
7c54e2e7 | 820 | |
f11ed062 PP |
821 | if len(self) != len(other): |
822 | # early mismatch | |
e1c6bebd | 823 | return False |
7c54e2e7 | 824 | |
f11ed062 PP |
825 | for self_elem, other_elem in zip(self, other): |
826 | if self_elem != other_elem: | |
827 | return False | |
828 | ||
829 | return True | |
830 | ||
12bf0d88 | 831 | def _repr(self): |
2bc21382 JG |
832 | return '[{}]'.format(', '.join([repr(v) for v in self])) |
833 | ||
81447b5b | 834 | |
f0a42b33 FD |
835 | class _ArrayField( |
836 | _ArrayFieldConst, _ContainerField, _Field, collections.abc.MutableSequence | |
837 | ): | |
838 | _borrow_element_field_ptr_by_index = staticmethod( | |
839 | native_bt.field_array_borrow_element_field_by_index | |
840 | ) | |
841 | ||
842 | def __setitem__(self, index, value): | |
843 | # raises if index is somehow invalid | |
844 | field = self[index] | |
845 | ||
846 | if not isinstance(field, (_NumericField, _StringField)): | |
847 | raise TypeError('can only set the value of a number or string field') | |
848 | ||
849 | # the field's property does the appropriate conversion or raises | |
850 | # the appropriate exception | |
851 | field.value = value | |
852 | ||
853 | ||
854 | class _StaticArrayFieldConst(_ArrayFieldConst, _FieldConst): | |
855 | _NAME = 'Const static array' | |
81447b5b PP |
856 | |
857 | def _count(self): | |
1eccc498 | 858 | return native_bt.field_array_get_length(self._ptr) |
81447b5b | 859 | |
f0a42b33 FD |
860 | |
861 | class _StaticArrayField(_StaticArrayFieldConst, _ArrayField, _Field): | |
862 | _NAME = 'Static array' | |
863 | ||
e1c6bebd JG |
864 | def _set_value(self, values): |
865 | if len(self) != len(values): | |
74695c0d SM |
866 | raise ValueError( |
867 | 'expected length of value ({}) and array field ({}) to match'.format( | |
868 | len(values), len(self) | |
869 | ) | |
870 | ) | |
e1c6bebd | 871 | |
1eccc498 SM |
872 | for index, value in enumerate(values): |
873 | if value is not None: | |
874 | self[index].value = value | |
e1c6bebd JG |
875 | |
876 | value = property(fset=_set_value) | |
877 | ||
81447b5b | 878 | |
f0a42b33 FD |
879 | class _DynamicArrayFieldConst(_ArrayFieldConst, _FieldConst): |
880 | _NAME = 'Const dynamic array' | |
81447b5b PP |
881 | |
882 | def _count(self): | |
1eccc498 | 883 | return self.length |
81447b5b | 884 | |
f0a42b33 FD |
885 | |
886 | class _DynamicArrayField(_DynamicArrayFieldConst, _ArrayField, _Field): | |
887 | _NAME = 'Dynamic array' | |
888 | ||
1eccc498 SM |
889 | def _set_length(self, length): |
890 | utils._check_uint64(length) | |
9c08c816 | 891 | status = native_bt.field_array_dynamic_set_length(self._ptr, length) |
d24d5663 | 892 | utils._handle_func_status(status, "cannot set dynamic array length") |
81447b5b | 893 | |
1eccc498 | 894 | length = property(fget=_ArrayField._get_length, fset=_set_length) |
81447b5b | 895 | |
e1c6bebd | 896 | def _set_value(self, values): |
1eccc498 SM |
897 | if len(values) != self.length: |
898 | self.length = len(values) | |
e1c6bebd | 899 | |
1eccc498 SM |
900 | for index, value in enumerate(values): |
901 | if value is not None: | |
902 | self[index].value = value | |
e1c6bebd JG |
903 | |
904 | value = property(fset=_set_value) | |
81447b5b | 905 | |
0b03f63e | 906 | |
f0a42b33 FD |
907 | _TYPE_ID_TO_CONST_OBJ = { |
908 | native_bt.FIELD_CLASS_TYPE_BOOL: _BoolFieldConst, | |
909 | native_bt.FIELD_CLASS_TYPE_BIT_ARRAY: _BitArrayFieldConst, | |
910 | native_bt.FIELD_CLASS_TYPE_UNSIGNED_INTEGER: _UnsignedIntegerFieldConst, | |
911 | native_bt.FIELD_CLASS_TYPE_SIGNED_INTEGER: _SignedIntegerFieldConst, | |
fe4df857 FD |
912 | native_bt.FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL: _SinglePrecisionRealFieldConst, |
913 | native_bt.FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL: _DoublePrecisionRealFieldConst, | |
f0a42b33 FD |
914 | native_bt.FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: _UnsignedEnumerationFieldConst, |
915 | native_bt.FIELD_CLASS_TYPE_SIGNED_ENUMERATION: _SignedEnumerationFieldConst, | |
916 | native_bt.FIELD_CLASS_TYPE_STRING: _StringFieldConst, | |
917 | native_bt.FIELD_CLASS_TYPE_STRUCTURE: _StructureFieldConst, | |
918 | native_bt.FIELD_CLASS_TYPE_STATIC_ARRAY: _StaticArrayFieldConst, | |
81b8fa44 PP |
919 | native_bt.FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD: _DynamicArrayFieldConst, |
920 | native_bt.FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD: _DynamicArrayFieldConst, | |
de821fe5 PP |
921 | native_bt.FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD: _OptionFieldConst, |
922 | native_bt.FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD: _OptionFieldConst, | |
923 | native_bt.FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD: _OptionFieldConst, | |
924 | native_bt.FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD: _OptionFieldConst, | |
925 | native_bt.FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD: _VariantFieldConst, | |
926 | native_bt.FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD: _VariantFieldConst, | |
927 | native_bt.FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD: _VariantFieldConst, | |
f0a42b33 FD |
928 | } |
929 | ||
81447b5b | 930 | _TYPE_ID_TO_OBJ = { |
aae30e61 | 931 | native_bt.FIELD_CLASS_TYPE_BOOL: _BoolField, |
ead8c3d4 | 932 | native_bt.FIELD_CLASS_TYPE_BIT_ARRAY: _BitArrayField, |
2ae9f48c SM |
933 | native_bt.FIELD_CLASS_TYPE_UNSIGNED_INTEGER: _UnsignedIntegerField, |
934 | native_bt.FIELD_CLASS_TYPE_SIGNED_INTEGER: _SignedIntegerField, | |
fe4df857 FD |
935 | native_bt.FIELD_CLASS_TYPE_SINGLE_PRECISION_REAL: _SinglePrecisionRealField, |
936 | native_bt.FIELD_CLASS_TYPE_DOUBLE_PRECISION_REAL: _DoublePrecisionRealField, | |
1eccc498 SM |
937 | native_bt.FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: _UnsignedEnumerationField, |
938 | native_bt.FIELD_CLASS_TYPE_SIGNED_ENUMERATION: _SignedEnumerationField, | |
2ae9f48c SM |
939 | native_bt.FIELD_CLASS_TYPE_STRING: _StringField, |
940 | native_bt.FIELD_CLASS_TYPE_STRUCTURE: _StructureField, | |
1eccc498 | 941 | native_bt.FIELD_CLASS_TYPE_STATIC_ARRAY: _StaticArrayField, |
81b8fa44 PP |
942 | native_bt.FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITHOUT_LENGTH_FIELD: _DynamicArrayField, |
943 | native_bt.FIELD_CLASS_TYPE_DYNAMIC_ARRAY_WITH_LENGTH_FIELD: _DynamicArrayField, | |
de821fe5 PP |
944 | native_bt.FIELD_CLASS_TYPE_OPTION_WITHOUT_SELECTOR_FIELD: _OptionField, |
945 | native_bt.FIELD_CLASS_TYPE_OPTION_WITH_BOOL_SELECTOR_FIELD: _OptionField, | |
946 | native_bt.FIELD_CLASS_TYPE_OPTION_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD: _OptionField, | |
947 | native_bt.FIELD_CLASS_TYPE_OPTION_WITH_SIGNED_INTEGER_SELECTOR_FIELD: _OptionField, | |
948 | native_bt.FIELD_CLASS_TYPE_VARIANT_WITHOUT_SELECTOR_FIELD: _VariantField, | |
949 | native_bt.FIELD_CLASS_TYPE_VARIANT_WITH_UNSIGNED_INTEGER_SELECTOR_FIELD: _VariantField, | |
950 | native_bt.FIELD_CLASS_TYPE_VARIANT_WITH_SIGNED_INTEGER_SELECTOR_FIELD: _VariantField, | |
81447b5b | 951 | } |