Commit | Line | Data |
---|---|---|
e5aa0be3 PP |
1 | # The MIT License (MIT) |
2 | # | |
4a90140d | 3 | # Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com> |
e5aa0be3 | 4 | # |
1378f213 PP |
5 | # Permission is hereby granted, free of charge, to any person obtaining |
6 | # a copy of this software and associated documentation files (the | |
7 | # "Software"), to deal in the Software without restriction, including | |
8 | # without limitation the rights to use, copy, modify, merge, publish, | |
9 | # distribute, sublicense, and/or sell copies of the Software, and to | |
10 | # permit persons to whom the Software is furnished to do so, subject to | |
11 | # the following conditions: | |
e5aa0be3 | 12 | # |
1378f213 PP |
13 | # The above copyright notice and this permission notice shall be |
14 | # included in all copies or substantial portions of the Software. | |
e5aa0be3 | 15 | # |
1378f213 PP |
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
17 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
18 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
19 | # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
20 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
21 | # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
22 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
e5aa0be3 | 23 | |
4810b707 | 24 | import barectf.version as barectf_version |
7fffc7d1 | 25 | from typing import Optional, Any, FrozenSet, Mapping, Iterator, Set, Union, Callable |
2d55dc7d PP |
26 | import typing |
27 | from barectf.typing import Count, Alignment, _OptStr, Id | |
4810b707 PP |
28 | import collections.abc |
29 | import collections | |
30 | import datetime | |
31 | import enum | |
2d55dc7d | 32 | import uuid as uuidp |
e5aa0be3 PP |
33 | |
34 | ||
4810b707 PP |
35 | @enum.unique |
36 | class ByteOrder(enum.Enum): | |
37 | LITTLE_ENDIAN = 'le' | |
38 | BIG_ENDIAN = 'be' | |
e5aa0be3 PP |
39 | |
40 | ||
4810b707 PP |
41 | class _FieldType: |
42 | @property | |
2d55dc7d | 43 | def alignment(self) -> Alignment: |
4810b707 | 44 | raise NotImplementedError |
a1a610d4 | 45 | |
1960170e PP |
46 | @property |
47 | def size_is_dynamic(self): | |
48 | return False | |
49 | ||
e5aa0be3 | 50 | |
4810b707 | 51 | class _BitArrayFieldType(_FieldType): |
4c91e769 | 52 | def __init__(self, size: Count, alignment: Alignment = Alignment(1)): |
4810b707 | 53 | self._size = size |
4810b707 | 54 | self._alignment = alignment |
e5aa0be3 PP |
55 | |
56 | @property | |
2d55dc7d | 57 | def size(self) -> Count: |
4810b707 | 58 | return self._size |
e5aa0be3 | 59 | |
893854db | 60 | @property |
2d55dc7d | 61 | def alignment(self) -> Alignment: |
4810b707 PP |
62 | return self._alignment |
63 | ||
64 | ||
65 | class DisplayBase(enum.Enum): | |
66 | BINARY = 2 | |
67 | OCTAL = 8 | |
68 | DECIMAL = 10 | |
69 | HEXADECIMAL = 16 | |
70 | ||
71 | ||
72 | class _IntegerFieldType(_BitArrayFieldType): | |
4c91e769 | 73 | def __init__(self, size: Count, alignment: Optional[Alignment] = None, |
2d55dc7d | 74 | preferred_display_base: DisplayBase = DisplayBase.DECIMAL): |
5833e4da PP |
75 | if alignment is None: |
76 | alignment = Alignment(8 if size % 8 == 0 else 1) | |
4810b707 | 77 | |
4c91e769 | 78 | super().__init__(size, alignment) |
4810b707 PP |
79 | self._preferred_display_base = preferred_display_base |
80 | ||
81 | @property | |
2d55dc7d | 82 | def preferred_display_base(self) -> DisplayBase: |
4810b707 PP |
83 | return self._preferred_display_base |
84 | ||
85 | ||
86 | class UnsignedIntegerFieldType(_IntegerFieldType): | |
87 | def __init__(self, *args): | |
88 | super().__init__(*args) | |
89 | self._mapped_clk_type_name = None | |
90 | ||
91 | ||
92 | class SignedIntegerFieldType(_IntegerFieldType): | |
93 | pass | |
94 | ||
95 | ||
96 | class EnumerationFieldTypeMappingRange: | |
2d55dc7d | 97 | def __init__(self, lower: int, upper: int): |
4810b707 PP |
98 | self._lower = lower |
99 | self._upper = upper | |
100 | ||
101 | @property | |
2d55dc7d | 102 | def lower(self) -> int: |
4810b707 PP |
103 | return self._lower |
104 | ||
105 | @property | |
2d55dc7d | 106 | def upper(self) -> int: |
4810b707 PP |
107 | return self._upper |
108 | ||
2d55dc7d | 109 | def __eq__(self, other: Any) -> bool: |
4810b707 PP |
110 | if type(other) is not type(self): |
111 | return False | |
112 | ||
113 | return (self._lower, self._upper) == (other._lower, other._upper) | |
114 | ||
2d55dc7d | 115 | def __hash__(self) -> int: |
4810b707 PP |
116 | return hash((self._lower, self._upper)) |
117 | ||
2d55dc7d | 118 | def contains(self, value: int) -> bool: |
4810b707 PP |
119 | return self._lower <= value <= self._upper |
120 | ||
121 | ||
122 | class EnumerationFieldTypeMapping: | |
2d55dc7d | 123 | def __init__(self, ranges: Set[EnumerationFieldTypeMappingRange]): |
4810b707 PP |
124 | self._ranges = frozenset(ranges) |
125 | ||
126 | @property | |
2d55dc7d | 127 | def ranges(self) -> FrozenSet[EnumerationFieldTypeMappingRange]: |
4810b707 PP |
128 | return self._ranges |
129 | ||
2d55dc7d | 130 | def ranges_contain_value(self, value: int) -> bool: |
4810b707 PP |
131 | return any([rg.contains(value) for rg in self._ranges]) |
132 | ||
133 | ||
2d55dc7d PP |
134 | _EnumFtMappings = Mapping[str, EnumerationFieldTypeMapping] |
135 | ||
136 | ||
4810b707 | 137 | class EnumerationFieldTypeMappings(collections.abc.Mapping): |
2d55dc7d | 138 | def __init__(self, mappings: _EnumFtMappings): |
4810b707 PP |
139 | self._mappings = {label: mapping for label, mapping in mappings.items()} |
140 | ||
2d55dc7d | 141 | def __getitem__(self, key: str) -> EnumerationFieldTypeMapping: |
4810b707 PP |
142 | return self._mappings[key] |
143 | ||
2d55dc7d | 144 | def __iter__(self) -> Iterator[str]: |
4810b707 PP |
145 | return iter(self._mappings) |
146 | ||
2d55dc7d | 147 | def __len__(self) -> int: |
4810b707 | 148 | return len(self._mappings) |
893854db | 149 | |
893854db | 150 | |
4810b707 | 151 | class _EnumerationFieldType(_IntegerFieldType): |
4c91e769 | 152 | def __init__(self, size: Count, alignment: Optional[Alignment] = None, |
2d55dc7d PP |
153 | preferred_display_base: DisplayBase = DisplayBase.DECIMAL, |
154 | mappings: Optional[_EnumFtMappings] = None): | |
4c91e769 | 155 | super().__init__(size, alignment, preferred_display_base) |
4810b707 PP |
156 | self._mappings = EnumerationFieldTypeMappings({}) |
157 | ||
158 | if mappings is not None: | |
159 | self._mappings = EnumerationFieldTypeMappings(mappings) | |
160 | ||
161 | @property | |
2d55dc7d | 162 | def mappings(self) -> EnumerationFieldTypeMappings: |
4810b707 PP |
163 | return self._mappings |
164 | ||
2d55dc7d | 165 | def labels_for_value(self, value: int) -> Set[str]: |
4810b707 PP |
166 | labels = set() |
167 | ||
168 | for label, mapping in self._mappings.items(): | |
169 | if mapping.ranges_contain_value(value): | |
170 | labels.add(label) | |
171 | ||
172 | return labels | |
173 | ||
174 | ||
175 | class UnsignedEnumerationFieldType(_EnumerationFieldType, UnsignedIntegerFieldType): | |
176 | pass | |
177 | ||
178 | ||
179 | class SignedEnumerationFieldType(_EnumerationFieldType, SignedIntegerFieldType): | |
180 | pass | |
181 | ||
182 | ||
183 | class RealFieldType(_BitArrayFieldType): | |
184 | pass | |
185 | ||
186 | ||
187 | class StringFieldType(_FieldType): | |
188 | @property | |
2d55dc7d PP |
189 | def alignment(self) -> Alignment: |
190 | return Alignment(8) | |
4810b707 | 191 | |
1960170e PP |
192 | @property |
193 | def size_is_dynamic(self): | |
194 | return True | |
195 | ||
4810b707 PP |
196 | |
197 | class _ArrayFieldType(_FieldType): | |
2d55dc7d | 198 | def __init__(self, element_field_type: _FieldType): |
4810b707 PP |
199 | self._element_field_type = element_field_type |
200 | ||
201 | @property | |
2d55dc7d | 202 | def element_field_type(self) -> _FieldType: |
4810b707 | 203 | return self._element_field_type |
893854db PP |
204 | |
205 | @property | |
2d55dc7d | 206 | def alignment(self) -> Alignment: |
4810b707 PP |
207 | return self._element_field_type.alignment |
208 | ||
a19472f2 PP |
209 | @property |
210 | def size_is_dynamic(self): | |
211 | return self._element_field_type.size_is_dynamic | |
212 | ||
4810b707 PP |
213 | |
214 | class StaticArrayFieldType(_ArrayFieldType): | |
2d55dc7d | 215 | def __init__(self, length: Count, element_field_type: _FieldType): |
4810b707 PP |
216 | super().__init__(element_field_type) |
217 | self._length = length | |
893854db | 218 | |
893854db | 219 | @property |
2d55dc7d | 220 | def length(self) -> Count: |
4810b707 PP |
221 | return self._length |
222 | ||
223 | ||
224 | class StructureFieldTypeMember: | |
2d55dc7d | 225 | def __init__(self, field_type: _FieldType): |
4810b707 PP |
226 | self._field_type = field_type |
227 | ||
228 | @property | |
2d55dc7d | 229 | def field_type(self) -> _FieldType: |
4810b707 PP |
230 | return self._field_type |
231 | ||
232 | ||
2d55dc7d PP |
233 | _StructFtMembers = Mapping[str, StructureFieldTypeMember] |
234 | ||
235 | ||
4810b707 | 236 | class StructureFieldTypeMembers(collections.abc.Mapping): |
2d55dc7d | 237 | def __init__(self, members: _StructFtMembers): |
4810b707 PP |
238 | self._members = collections.OrderedDict() |
239 | ||
240 | for name, member in members.items(): | |
241 | assert type(member) is StructureFieldTypeMember | |
242 | self._members[name] = member | |
243 | ||
2d55dc7d | 244 | def __getitem__(self, key: str) -> StructureFieldTypeMember: |
4810b707 PP |
245 | return self._members[key] |
246 | ||
2d55dc7d | 247 | def __iter__(self) -> Iterator[str]: |
4810b707 PP |
248 | return iter(self._members) |
249 | ||
2d55dc7d | 250 | def __len__(self) -> int: |
4810b707 PP |
251 | return len(self._members) |
252 | ||
253 | ||
254 | class StructureFieldType(_FieldType): | |
2d55dc7d PP |
255 | def __init__(self, minimum_alignment: Alignment = Alignment(1), |
256 | members: Optional[_StructFtMembers] = None): | |
4810b707 PP |
257 | self._minimum_alignment = minimum_alignment |
258 | self._members = StructureFieldTypeMembers({}) | |
259 | ||
260 | if members is not None: | |
261 | self._members = StructureFieldTypeMembers(members) | |
262 | ||
263 | self._set_alignment() | |
264 | ||
265 | def _set_alignment(self): | |
2d55dc7d | 266 | self._alignment: Alignment = self._minimum_alignment |
4810b707 PP |
267 | |
268 | for member in self._members.values(): | |
269 | if member.field_type.alignment > self._alignment: | |
270 | self._alignment = member.field_type.alignment | |
271 | ||
272 | @property | |
2d55dc7d | 273 | def minimum_alignment(self) -> Alignment: |
4810b707 PP |
274 | return self._minimum_alignment |
275 | ||
276 | @property | |
2d55dc7d | 277 | def alignment(self) -> Alignment: |
4810b707 PP |
278 | return self._alignment |
279 | ||
1960170e PP |
280 | @property |
281 | def size_is_dynamic(self): | |
282 | return any([member.field_type.size_is_dynamic for member in self.members.values()]) | |
283 | ||
4810b707 | 284 | @property |
2d55dc7d | 285 | def members(self) -> StructureFieldTypeMembers: |
4810b707 PP |
286 | return self._members |
287 | ||
288 | ||
289 | class _UniqueByName: | |
2d55dc7d PP |
290 | _name: str |
291 | ||
292 | def __eq__(self, other: Any) -> bool: | |
4810b707 PP |
293 | if type(other) is not type(self): |
294 | return False | |
295 | ||
296 | return self._name == other._name | |
297 | ||
2d55dc7d | 298 | def __lt__(self, other: '_UniqueByName'): |
4810b707 PP |
299 | assert type(self) is type(other) |
300 | return self._name < other._name | |
301 | ||
2d55dc7d | 302 | def __hash__(self) -> int: |
4810b707 PP |
303 | return hash(self._name) |
304 | ||
305 | ||
2d55dc7d PP |
306 | _OptFt = Optional[_FieldType] |
307 | _OptStructFt = Optional[StructureFieldType] | |
308 | LogLevel = typing.NewType('LogLevel', int) | |
309 | ||
310 | ||
4810b707 | 311 | class EventType(_UniqueByName): |
2d55dc7d PP |
312 | def __init__(self, name: str, log_level: Optional[LogLevel] = None, |
313 | specific_context_field_type: _OptStructFt = None, payload_field_type: _OptStructFt = None): | |
314 | self._id: Optional[Id] = None | |
4810b707 PP |
315 | self._name = name |
316 | self._log_level = log_level | |
317 | self._specific_context_field_type = specific_context_field_type | |
318 | self._payload_field_type = payload_field_type | |
319 | ||
320 | @property | |
2d55dc7d | 321 | def id(self) -> Optional[Id]: |
4810b707 PP |
322 | return self._id |
323 | ||
324 | @property | |
2d55dc7d | 325 | def name(self) -> str: |
4810b707 PP |
326 | return self._name |
327 | ||
328 | @property | |
2d55dc7d | 329 | def log_level(self) -> Optional[LogLevel]: |
4810b707 PP |
330 | return self._log_level |
331 | ||
332 | @property | |
2d55dc7d | 333 | def specific_context_field_type(self) -> _OptStructFt: |
4810b707 PP |
334 | return self._specific_context_field_type |
335 | ||
336 | @property | |
2d55dc7d | 337 | def payload_field_type(self) -> _OptStructFt: |
4810b707 PP |
338 | return self._payload_field_type |
339 | ||
340 | ||
341 | class ClockTypeOffset: | |
2d55dc7d | 342 | def __init__(self, seconds: int = 0, cycles: Count = Count(0)): |
4810b707 PP |
343 | self._seconds = seconds |
344 | self._cycles = cycles | |
345 | ||
346 | @property | |
2d55dc7d | 347 | def seconds(self) -> int: |
4810b707 PP |
348 | return self._seconds |
349 | ||
350 | @property | |
2d55dc7d | 351 | def cycles(self) -> Count: |
4810b707 PP |
352 | return self._cycles |
353 | ||
354 | ||
2d55dc7d PP |
355 | _OptUuid = Optional[uuidp.UUID] |
356 | ||
357 | ||
4810b707 | 358 | class ClockType(_UniqueByName): |
2d55dc7d PP |
359 | def __init__(self, name: str, frequency: Count = Count(int(1e9)), uuid: _OptUuid = None, |
360 | description: _OptStr = None, precision: Count = Count(0), | |
361 | offset: Optional[ClockTypeOffset] = None, origin_is_unix_epoch: bool = False): | |
4810b707 PP |
362 | self._name = name |
363 | self._frequency = frequency | |
364 | self._uuid = uuid | |
365 | self._description = description | |
366 | self._precision = precision | |
367 | self._offset = ClockTypeOffset() | |
368 | ||
369 | if offset is not None: | |
370 | self._offset = offset | |
371 | ||
372 | self._origin_is_unix_epoch = origin_is_unix_epoch | |
373 | ||
374 | @property | |
2d55dc7d | 375 | def name(self) -> str: |
4810b707 PP |
376 | return self._name |
377 | ||
378 | @property | |
2d55dc7d | 379 | def frequency(self) -> Count: |
4810b707 PP |
380 | return self._frequency |
381 | ||
382 | @property | |
2d55dc7d | 383 | def uuid(self) -> _OptUuid: |
4810b707 PP |
384 | return self._uuid |
385 | ||
386 | @property | |
2d55dc7d | 387 | def description(self) -> _OptStr: |
4810b707 PP |
388 | return self._description |
389 | ||
390 | @property | |
2d55dc7d | 391 | def precision(self) -> Count: |
4810b707 PP |
392 | return self._precision |
393 | ||
394 | @property | |
2d55dc7d | 395 | def offset(self) -> ClockTypeOffset: |
4810b707 PP |
396 | return self._offset |
397 | ||
398 | @property | |
2d55dc7d | 399 | def origin_is_unix_epoch(self) -> bool: |
4810b707 PP |
400 | return self._origin_is_unix_epoch |
401 | ||
402 | ||
403 | DEFAULT_FIELD_TYPE = 'default' | |
2d55dc7d PP |
404 | _DefaultableUIntFt = Union[str, UnsignedIntegerFieldType] |
405 | _OptDefaultableUIntFt = Optional[_DefaultableUIntFt] | |
406 | _OptUIntFt = Optional[UnsignedIntegerFieldType] | |
4810b707 PP |
407 | |
408 | ||
409 | class StreamTypePacketFeatures: | |
2d55dc7d PP |
410 | def __init__(self, total_size_field_type: _DefaultableUIntFt = DEFAULT_FIELD_TYPE, |
411 | content_size_field_type: _DefaultableUIntFt = DEFAULT_FIELD_TYPE, | |
412 | beginning_time_field_type: _OptDefaultableUIntFt = None, | |
413 | end_time_field_type: _OptDefaultableUIntFt = None, | |
4c91e769 | 414 | discarded_events_counter_field_type: _OptDefaultableUIntFt = None): |
2d55dc7d | 415 | def get_ft(user_ft: _OptDefaultableUIntFt) -> _OptUIntFt: |
4810b707 | 416 | if user_ft == DEFAULT_FIELD_TYPE: |
4c91e769 | 417 | return UnsignedIntegerFieldType(64) |
4810b707 | 418 | |
2d55dc7d | 419 | return typing.cast(_OptUIntFt, user_ft) |
4810b707 PP |
420 | |
421 | self._total_size_field_type = get_ft(total_size_field_type) | |
422 | self._content_size_field_type = get_ft(content_size_field_type) | |
423 | self._beginning_time_field_type = get_ft(beginning_time_field_type) | |
424 | self._end_time_field_type = get_ft(end_time_field_type) | |
425 | self._discarded_events_counter_field_type = get_ft(discarded_events_counter_field_type) | |
426 | ||
427 | @property | |
2d55dc7d | 428 | def total_size_field_type(self) -> _OptUIntFt: |
4810b707 PP |
429 | return self._total_size_field_type |
430 | ||
431 | @property | |
2d55dc7d | 432 | def content_size_field_type(self) -> _OptUIntFt: |
4810b707 PP |
433 | return self._content_size_field_type |
434 | ||
435 | @property | |
2d55dc7d | 436 | def beginning_time_field_type(self) -> _OptUIntFt: |
4810b707 PP |
437 | return self._beginning_time_field_type |
438 | ||
439 | @property | |
2d55dc7d | 440 | def end_time_field_type(self) -> _OptUIntFt: |
4810b707 PP |
441 | return self._end_time_field_type |
442 | ||
443 | @property | |
2d55dc7d | 444 | def discarded_events_counter_field_type(self) -> _OptUIntFt: |
4810b707 PP |
445 | return self._discarded_events_counter_field_type |
446 | ||
447 | ||
448 | class StreamTypeEventFeatures: | |
2d55dc7d | 449 | def __init__(self, type_id_field_type: _OptDefaultableUIntFt = DEFAULT_FIELD_TYPE, |
4c91e769 | 450 | time_field_type: _OptDefaultableUIntFt = None): |
2d55dc7d PP |
451 | def get_ft(user_ft: _OptDefaultableUIntFt) -> _OptUIntFt: |
452 | if user_ft == DEFAULT_FIELD_TYPE: | |
4c91e769 | 453 | return UnsignedIntegerFieldType(64) |
4810b707 | 454 | |
2d55dc7d | 455 | return typing.cast(_OptUIntFt, user_ft) |
4810b707 PP |
456 | |
457 | self._type_id_field_type = get_ft(type_id_field_type) | |
458 | self._time_field_type = get_ft(time_field_type) | |
459 | ||
460 | @property | |
2d55dc7d | 461 | def type_id_field_type(self) -> _OptUIntFt: |
4810b707 PP |
462 | return self._type_id_field_type |
463 | ||
464 | @property | |
2d55dc7d | 465 | def time_field_type(self) -> _OptUIntFt: |
4810b707 PP |
466 | return self._time_field_type |
467 | ||
468 | ||
469 | class StreamTypeFeatures: | |
2d55dc7d | 470 | def __init__(self, packet_features: Optional[StreamTypePacketFeatures] = None, |
4c91e769 | 471 | event_features: Optional[StreamTypeEventFeatures] = None): |
7fffc7d1 | 472 | if packet_features is None: |
4c91e769 | 473 | self._packet_features = StreamTypePacketFeatures() |
7fffc7d1 | 474 | else: |
4810b707 PP |
475 | self._packet_features = packet_features |
476 | ||
7fffc7d1 | 477 | if event_features is None: |
4c91e769 | 478 | self._event_features = StreamTypeEventFeatures() |
7fffc7d1 | 479 | else: |
4810b707 PP |
480 | self._event_features = event_features |
481 | ||
482 | @property | |
2d55dc7d | 483 | def packet_features(self) -> StreamTypePacketFeatures: |
4810b707 PP |
484 | return self._packet_features |
485 | ||
486 | @property | |
2d55dc7d | 487 | def event_features(self) -> StreamTypeEventFeatures: |
4810b707 PP |
488 | return self._event_features |
489 | ||
490 | ||
491 | class StreamType(_UniqueByName): | |
2d55dc7d PP |
492 | def __init__(self, name: str, event_types: Set[EventType], |
493 | default_clock_type: Optional[ClockType] = None, | |
494 | features: Optional[StreamTypeFeatures] = None, | |
495 | packet_context_field_type_extra_members: Optional[_StructFtMembers] = None, | |
496 | event_common_context_field_type: _OptStructFt = None): | |
497 | self._id: Optional[Id] = None | |
4810b707 PP |
498 | self._name = name |
499 | self._default_clock_type = default_clock_type | |
500 | self._event_common_context_field_type = event_common_context_field_type | |
501 | self._event_types = frozenset(event_types) | |
502 | ||
503 | # assign unique IDs | |
504 | for index, ev_type in enumerate(sorted(self._event_types, key=lambda evt: evt.name)): | |
505 | assert ev_type._id is None | |
2d55dc7d | 506 | ev_type._id = Id(index) |
4810b707 | 507 | |
4c91e769 | 508 | self._set_features(features) |
4810b707 PP |
509 | self._packet_context_field_type_extra_members = StructureFieldTypeMembers({}) |
510 | ||
511 | if packet_context_field_type_extra_members is not None: | |
512 | self._packet_context_field_type_extra_members = StructureFieldTypeMembers(packet_context_field_type_extra_members) | |
513 | ||
514 | self._set_pkt_ctx_ft() | |
515 | self._set_ev_header_ft() | |
516 | ||
4c91e769 | 517 | def _set_features(self, features: Optional[StreamTypeFeatures]): |
4810b707 PP |
518 | if features is not None: |
519 | self._features = features | |
2d55dc7d | 520 | return None |
4810b707 PP |
521 | |
522 | ev_time_ft = None | |
523 | pkt_beginning_time_ft = None | |
524 | pkt_end_time_ft = None | |
525 | ||
526 | if self._default_clock_type is not None: | |
527 | # Automatic time field types because the stream type has a | |
528 | # default clock type. | |
529 | ev_time_ft = DEFAULT_FIELD_TYPE | |
530 | pkt_beginning_time_ft = DEFAULT_FIELD_TYPE | |
531 | pkt_end_time_ft = DEFAULT_FIELD_TYPE | |
532 | ||
533 | self._features = StreamTypeFeatures(StreamTypePacketFeatures(beginning_time_field_type=pkt_beginning_time_ft, | |
4c91e769 PP |
534 | end_time_field_type=pkt_end_time_ft), |
535 | StreamTypeEventFeatures(time_field_type=ev_time_ft)) | |
4810b707 | 536 | |
2d55dc7d | 537 | def _set_ft_mapped_clk_type_name(self, ft: Optional[UnsignedIntegerFieldType]): |
4810b707 PP |
538 | if ft is None: |
539 | return | |
540 | ||
541 | if self._default_clock_type is not None: | |
542 | assert isinstance(ft, UnsignedIntegerFieldType) | |
543 | ft._mapped_clk_type_name = self._default_clock_type.name | |
544 | ||
545 | def _set_pkt_ctx_ft(self): | |
2d55dc7d PP |
546 | members = None |
547 | ||
548 | def add_member_if_exists(name: str, ft: _FieldType, set_mapped_clk_type_name: bool = False): | |
4810b707 PP |
549 | nonlocal members |
550 | ||
551 | if ft is not None: | |
552 | if set_mapped_clk_type_name: | |
2d55dc7d | 553 | self._set_ft_mapped_clk_type_name(typing.cast(UnsignedIntegerFieldType, ft)) |
4810b707 PP |
554 | |
555 | members[name] = StructureFieldTypeMember(ft) | |
556 | ||
557 | members = collections.OrderedDict([ | |
558 | ( | |
559 | 'packet_size', | |
560 | StructureFieldTypeMember(self._features.packet_features.total_size_field_type) | |
561 | ), | |
562 | ( | |
563 | 'content_size', | |
564 | StructureFieldTypeMember(self._features.packet_features.content_size_field_type) | |
565 | ) | |
566 | ]) | |
567 | ||
568 | add_member_if_exists('timestamp_begin', | |
569 | self._features.packet_features.beginning_time_field_type, True) | |
570 | add_member_if_exists('timestamp_end', self._features.packet_features.end_time_field_type, | |
571 | True) | |
572 | add_member_if_exists('events_discarded', | |
573 | self._features.packet_features.discarded_events_counter_field_type) | |
574 | ||
575 | if self._packet_context_field_type_extra_members is not None: | |
576 | for name, field_type in self._packet_context_field_type_extra_members.items(): | |
577 | assert name not in members | |
578 | members[name] = field_type | |
579 | ||
580 | self._pkt_ctx_ft = StructureFieldType(8, members) | |
581 | ||
582 | def _set_ev_header_ft(self): | |
583 | members = collections.OrderedDict() | |
584 | ||
585 | if self._features.event_features.type_id_field_type is not None: | |
586 | members['id'] = StructureFieldTypeMember(self._features.event_features.type_id_field_type) | |
587 | ||
588 | if self._features.event_features.time_field_type is not None: | |
589 | ft = self._features.event_features.time_field_type | |
590 | self._set_ft_mapped_clk_type_name(ft) | |
591 | members['timestamp'] = StructureFieldTypeMember(ft) | |
592 | ||
593 | self._ev_header_ft = StructureFieldType(8, members) | |
594 | ||
595 | @property | |
2d55dc7d | 596 | def id(self) -> Optional[Id]: |
4810b707 PP |
597 | return self._id |
598 | ||
599 | @property | |
2d55dc7d | 600 | def name(self) -> str: |
4810b707 PP |
601 | return self._name |
602 | ||
603 | @property | |
2d55dc7d | 604 | def default_clock_type(self) -> Optional[ClockType]: |
4810b707 PP |
605 | return self._default_clock_type |
606 | ||
607 | @property | |
2d55dc7d | 608 | def features(self) -> StreamTypeFeatures: |
4810b707 PP |
609 | return self._features |
610 | ||
611 | @property | |
2d55dc7d | 612 | def packet_context_field_type_extra_members(self) -> StructureFieldTypeMembers: |
4810b707 PP |
613 | return self._packet_context_field_type_extra_members |
614 | ||
615 | @property | |
2d55dc7d | 616 | def event_common_context_field_type(self) -> _OptStructFt: |
4810b707 PP |
617 | return self._event_common_context_field_type |
618 | ||
619 | @property | |
2d55dc7d | 620 | def event_types(self) -> FrozenSet[EventType]: |
4810b707 PP |
621 | return self._event_types |
622 | ||
623 | ||
2d55dc7d PP |
624 | _OptUuidFt = Optional[Union[str, StaticArrayFieldType]] |
625 | ||
626 | ||
4810b707 | 627 | class TraceTypeFeatures: |
2d55dc7d PP |
628 | def __init__(self, magic_field_type: _OptDefaultableUIntFt = DEFAULT_FIELD_TYPE, |
629 | uuid_field_type: _OptUuidFt = None, | |
4c91e769 | 630 | stream_type_id_field_type: _OptDefaultableUIntFt = DEFAULT_FIELD_TYPE): |
7fffc7d1 PP |
631 | def get_field_type(user_ft: Optional[Union[str, _FieldType]], |
632 | create_default_ft: Callable[[], _FieldType]) -> _OptFt: | |
2d55dc7d | 633 | if user_ft == DEFAULT_FIELD_TYPE: |
7fffc7d1 | 634 | return create_default_ft() |
4810b707 | 635 | |
2d55dc7d | 636 | return typing.cast(_OptFt, user_ft) |
4810b707 | 637 | |
7fffc7d1 | 638 | def create_default_magic_ft(): |
4c91e769 | 639 | return UnsignedIntegerFieldType(32) |
7fffc7d1 PP |
640 | |
641 | def create_default_uuid_ft(): | |
4c91e769 | 642 | return StaticArrayFieldType(Count(16), UnsignedIntegerFieldType(8)) |
7fffc7d1 PP |
643 | |
644 | def create_default_stream_type_id_ft(): | |
4c91e769 | 645 | return UnsignedIntegerFieldType(64) |
7fffc7d1 PP |
646 | |
647 | self._magic_field_type = typing.cast(_OptUIntFt, get_field_type(magic_field_type, create_default_magic_ft)) | |
648 | self._uuid_field_type = typing.cast(Optional[StaticArrayFieldType], | |
649 | get_field_type(uuid_field_type, create_default_uuid_ft)) | |
650 | self._stream_type_id_field_type = typing.cast(_OptUIntFt, | |
651 | get_field_type(stream_type_id_field_type, | |
652 | create_default_stream_type_id_ft)) | |
4810b707 PP |
653 | |
654 | @property | |
2d55dc7d | 655 | def magic_field_type(self) -> _OptUIntFt: |
4810b707 PP |
656 | return self._magic_field_type |
657 | ||
658 | @property | |
2d55dc7d | 659 | def uuid_field_type(self) -> Optional[StaticArrayFieldType]: |
4810b707 PP |
660 | return self._uuid_field_type |
661 | ||
662 | @property | |
2d55dc7d | 663 | def stream_type_id_field_type(self) -> _OptUIntFt: |
4810b707 PP |
664 | return self._stream_type_id_field_type |
665 | ||
666 | ||
667 | class TraceType: | |
7fffc7d1 | 668 | def __init__(self, stream_types: Set[StreamType], uuid: _OptUuid = None, |
4c91e769 | 669 | features: Optional[TraceTypeFeatures] = None): |
4810b707 PP |
670 | self._stream_types = frozenset(stream_types) |
671 | ||
672 | # assign unique IDs | |
673 | for index, stream_type in enumerate(sorted(self._stream_types, key=lambda st: st.name)): | |
674 | assert stream_type._id is None | |
2d55dc7d | 675 | stream_type._id = Id(index) |
4810b707 PP |
676 | |
677 | self._uuid = uuid | |
4c91e769 | 678 | self._set_features(features) |
4810b707 | 679 | self._set_pkt_header_ft() |
4810b707 | 680 | |
4c91e769 | 681 | def _set_features(self, features: Optional[TraceTypeFeatures]): |
4810b707 PP |
682 | if features is not None: |
683 | self._features = features | |
684 | return | |
685 | ||
686 | # automatic UUID field type because the trace type has a UUID | |
687 | uuid_ft = None if self._uuid is None else DEFAULT_FIELD_TYPE | |
4c91e769 | 688 | self._features = TraceTypeFeatures(uuid_field_type=uuid_ft) |
4810b707 PP |
689 | |
690 | def _set_pkt_header_ft(self): | |
2d55dc7d PP |
691 | members = collections.OrderedDict() |
692 | ||
693 | def add_member_if_exists(name: str, ft: _OptFt): | |
4810b707 PP |
694 | nonlocal members |
695 | ||
2d55dc7d PP |
696 | if ft is not None: |
697 | members[name] = StructureFieldTypeMember(ft) | |
4810b707 | 698 | |
4810b707 PP |
699 | add_member_if_exists('magic', self._features.magic_field_type) |
700 | add_member_if_exists('uuid', self._features.uuid_field_type) | |
701 | add_member_if_exists('stream_id', self._features.stream_type_id_field_type) | |
702 | self._pkt_header_ft = StructureFieldType(8, members) | |
703 | ||
4810b707 | 704 | @property |
2d55dc7d | 705 | def uuid(self) -> _OptUuid: |
4810b707 PP |
706 | return self._uuid |
707 | ||
708 | @property | |
2d55dc7d | 709 | def stream_types(self) -> FrozenSet[StreamType]: |
4810b707 PP |
710 | return self._stream_types |
711 | ||
2d55dc7d | 712 | def stream_type(self, name: str) -> Optional[StreamType]: |
4810b707 PP |
713 | for cand_stream_type in self._stream_types: |
714 | if cand_stream_type.name == name: | |
715 | return cand_stream_type | |
716 | ||
2d55dc7d PP |
717 | return None |
718 | ||
4810b707 | 719 | @property |
2d55dc7d | 720 | def features(self) -> TraceTypeFeatures: |
4810b707 PP |
721 | return self._features |
722 | ||
de49021e PP |
723 | @property |
724 | def clock_types(self) -> Set[ClockType]: | |
725 | clk_types = set() | |
726 | ||
727 | for stream_type in self._stream_types: | |
728 | if stream_type.default_clock_type is not None: | |
729 | clk_types.add(stream_type.default_clock_type) | |
730 | ||
731 | return clk_types | |
732 | ||
4810b707 | 733 | |
2d55dc7d PP |
734 | _EnvEntry = Union[str, int] |
735 | _EnvEntries = Mapping[str, _EnvEntry] | |
736 | ||
737 | ||
4810b707 | 738 | class TraceEnvironment(collections.abc.Mapping): |
2d55dc7d | 739 | def __init__(self, environment: _EnvEntries): |
4810b707 PP |
740 | self._env = {name: value for name, value in environment.items()} |
741 | ||
2d55dc7d | 742 | def __getitem__(self, key: str) -> _EnvEntry: |
4810b707 PP |
743 | return self._env[key] |
744 | ||
2d55dc7d | 745 | def __iter__(self) -> Iterator[str]: |
4810b707 PP |
746 | return iter(self._env) |
747 | ||
2d55dc7d | 748 | def __len__(self) -> int: |
4810b707 PP |
749 | return len(self._env) |
750 | ||
751 | ||
752 | class Trace: | |
2d55dc7d | 753 | def __init__(self, type: TraceType, environment: Optional[_EnvEntries] = None): |
4810b707 PP |
754 | self._type = type |
755 | self._set_env(environment) | |
756 | ||
2d55dc7d | 757 | def _set_env(self, environment: Optional[_EnvEntries]): |
4810b707 PP |
758 | init_env = collections.OrderedDict([ |
759 | ('domain', 'bare'), | |
760 | ('tracer_name', 'barectf'), | |
761 | ('tracer_major', barectf_version.__major_version__), | |
762 | ('tracer_minor', barectf_version.__minor_version__), | |
763 | ('tracer_patch', barectf_version.__patch_version__), | |
764 | ('barectf_gen_date', str(datetime.datetime.now().isoformat())), | |
765 | ]) | |
766 | ||
767 | if environment is None: | |
768 | environment = {} | |
769 | ||
770 | init_env.update(environment) | |
2d55dc7d | 771 | self._env = TraceEnvironment(typing.cast(_EnvEntries, init_env)) |
4810b707 PP |
772 | |
773 | @property | |
2d55dc7d | 774 | def type(self) -> TraceType: |
4810b707 PP |
775 | return self._type |
776 | ||
777 | @property | |
2d55dc7d | 778 | def environment(self) -> TraceEnvironment: |
4810b707 PP |
779 | return self._env |
780 | ||
781 | ||
2d55dc7d PP |
782 | _ClkTypeCTypes = Mapping[ClockType, str] |
783 | ||
784 | ||
4810b707 | 785 | class ClockTypeCTypes(collections.abc.Mapping): |
2d55dc7d | 786 | def __init__(self, c_types: _ClkTypeCTypes): |
4810b707 PP |
787 | self._c_types = {clk_type: c_type for clk_type, c_type in c_types.items()} |
788 | ||
2d55dc7d | 789 | def __getitem__(self, key: ClockType) -> str: |
4810b707 PP |
790 | return self._c_types[key] |
791 | ||
2d55dc7d | 792 | def __iter__(self) -> Iterator[ClockType]: |
4810b707 PP |
793 | return iter(self._c_types) |
794 | ||
2d55dc7d | 795 | def __len__(self) -> int: |
4810b707 PP |
796 | return len(self._c_types) |
797 | ||
798 | ||
799 | class ConfigurationCodeGenerationHeaderOptions: | |
2d55dc7d PP |
800 | def __init__(self, identifier_prefix_definition: bool = False, |
801 | default_stream_type_name_definition: bool = False): | |
4810b707 PP |
802 | self._identifier_prefix_definition = identifier_prefix_definition |
803 | self._default_stream_type_name_definition = default_stream_type_name_definition | |
804 | ||
805 | @property | |
2d55dc7d | 806 | def identifier_prefix_definition(self) -> bool: |
4810b707 PP |
807 | return self._identifier_prefix_definition |
808 | ||
809 | @property | |
2d55dc7d | 810 | def default_stream_type_name_definition(self) -> bool: |
4810b707 PP |
811 | return self._default_stream_type_name_definition |
812 | ||
813 | ||
814 | class ConfigurationCodeGenerationOptions: | |
2d55dc7d PP |
815 | def __init__(self, identifier_prefix: str = 'barectf_', file_name_prefix: str = 'barectf', |
816 | default_stream_type: Optional[StreamType] = None, | |
817 | header_options: Optional[ConfigurationCodeGenerationHeaderOptions] = None, | |
818 | clock_type_c_types: Optional[_ClkTypeCTypes] = None): | |
4810b707 PP |
819 | self._identifier_prefix = identifier_prefix |
820 | self._file_name_prefix = file_name_prefix | |
821 | self._default_stream_type = default_stream_type | |
822 | ||
823 | self._header_options = ConfigurationCodeGenerationHeaderOptions() | |
824 | ||
825 | if header_options is not None: | |
826 | self._header_options = header_options | |
827 | ||
828 | self._clock_type_c_types = ClockTypeCTypes({}) | |
829 | ||
830 | if clock_type_c_types is not None: | |
831 | self._clock_type_c_types = ClockTypeCTypes(clock_type_c_types) | |
832 | ||
833 | @property | |
2d55dc7d | 834 | def identifier_prefix(self) -> str: |
4810b707 PP |
835 | return self._identifier_prefix |
836 | ||
837 | @property | |
2d55dc7d | 838 | def file_name_prefix(self) -> str: |
4810b707 PP |
839 | return self._file_name_prefix |
840 | ||
841 | @property | |
2d55dc7d | 842 | def default_stream_type(self) -> Optional[StreamType]: |
4810b707 PP |
843 | return self._default_stream_type |
844 | ||
845 | @property | |
2d55dc7d | 846 | def header_options(self) -> ConfigurationCodeGenerationHeaderOptions: |
4810b707 PP |
847 | return self._header_options |
848 | ||
849 | @property | |
2d55dc7d | 850 | def clock_type_c_types(self) -> ClockTypeCTypes: |
4810b707 PP |
851 | return self._clock_type_c_types |
852 | ||
853 | ||
854 | class ConfigurationOptions: | |
2d55dc7d PP |
855 | def __init__(self, |
856 | code_generation_options: Optional[ConfigurationCodeGenerationOptions] = None): | |
4810b707 PP |
857 | self._code_generation_options = ConfigurationCodeGenerationOptions() |
858 | ||
859 | if code_generation_options is not None: | |
860 | self._code_generation_options = code_generation_options | |
861 | ||
862 | @property | |
2d55dc7d | 863 | def code_generation_options(self) -> ConfigurationCodeGenerationOptions: |
4810b707 PP |
864 | return self._code_generation_options |
865 | ||
866 | ||
867 | class Configuration: | |
7fffc7d1 PP |
868 | def __init__(self, trace: Trace, target_byte_order: ByteOrder, |
869 | options: Optional[ConfigurationOptions] = None): | |
4810b707 PP |
870 | self._trace = trace |
871 | self._options = ConfigurationOptions() | |
7fffc7d1 | 872 | self._target_byte_order = target_byte_order |
4810b707 PP |
873 | |
874 | if options is not None: | |
875 | self._options = options | |
876 | ||
877 | clk_type_c_types = self._options.code_generation_options.clock_type_c_types | |
878 | ||
879 | for stream_type in trace.type.stream_types: | |
880 | def_clk_type = stream_type.default_clock_type | |
881 | ||
882 | if def_clk_type is None: | |
883 | continue | |
884 | ||
885 | if def_clk_type not in clk_type_c_types: | |
886 | clk_type_c_types._c_types[def_clk_type] = 'uint32_t' | |
887 | ||
888 | @property | |
2d55dc7d | 889 | def trace(self) -> Trace: |
4810b707 PP |
890 | return self._trace |
891 | ||
7fffc7d1 PP |
892 | @property |
893 | def target_byte_order(self): | |
894 | return self._target_byte_order | |
895 | ||
4810b707 | 896 | @property |
2d55dc7d | 897 | def options(self) -> ConfigurationOptions: |
4810b707 | 898 | return self._options |