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