1 # The MIT License (MIT)
3 # Copyright (c) 2014-2020 Philippe Proulx <pproulx@efficios.com>
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:
13 # The above copyright notice and this permission notice shall be
14 # included in all copies or substantial portions of the Software.
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.
24 import barectf
.template
as barectf_template
25 import barectf
.config
as barectf_config
29 from typing
import List
, Optional
, Mapping
, Callable
, Any
, Set
, Tuple
31 from barectf
.typing
import Count
, Alignment
34 # A tuple containing serialization and size computation function
35 # templates for a given operation.
36 _OpTemplates
= collections
.namedtuple('_OpTemplates', ['serialize', 'size'])
39 # Abstract base class of any operation within source code.
45 # * A list of names which, when joined with `_`, form the generic
46 # C source variable name.
48 # * A level: how deep this operation is within the operation tree.
50 # * Serialization and size computation templates to generate the
51 # operation's source code for those functions.
53 def __init__(self
, ft
: barectf_config
._FieldType
, names
: List
[str], level
: Count
,
54 templates
: _OpTemplates
):
56 self
._names
= copy
.copy(names
)
58 self
._templates
= templates
61 def ft(self
) -> barectf_config
._FieldType
:
65 def names(self
) -> List
[str]:
69 def level(self
) -> Count
:
73 def top_name(self
) -> str:
74 return self
._names
[-1]
76 def _render_template(self
, templ
: barectf_template
._Template
, **kwargs
) -> str:
77 return templ
.render(op
=self
, root_ft_prefixes
=_RootFtPrefixes
,
78 root_ft_prefix_names
=_ROOT_FT_PREFIX_NAMES
, **kwargs
)
80 def serialize_str(self
, **kwargs
) -> str:
81 return self
._render
_template
(self
._templates
.serialize
, **kwargs
)
83 def size_str(self
, **kwargs
) -> str:
84 return self
._render
_template
(self
._templates
.size
, **kwargs
)
89 # A compound operation contains a list of suboperations (leaf or
92 # Get the suboperations of a compound operation with its `subops`
95 # The templates of a compound operation handles its suboperations.
96 class _CompoundOp(_Op
):
97 def __init__(self
, ft
: barectf_config
._FieldType
, names
: List
[str], level
: Count
,
98 templates
: _OpTemplates
, subops
: List
[Any
] = None):
99 super().__init
__(ft
, names
, level
, templates
)
100 self
._subops
= subops
107 # Leaf operation (abstract class).
112 # An "align" operation.
113 class _AlignOp(_LeafOp
):
114 def __init__(self
, ft
: barectf_config
._FieldType
, names
: List
[str], level
: Count
,
115 templates
: _OpTemplates
, value
: Alignment
):
116 super().__init
__(ft
, names
, level
, templates
)
120 def value(self
) -> Alignment
:
124 # A "write" operation.
125 class _WriteOp(_LeafOp
):
126 def __init__(self
, ft
: barectf_config
._FieldType
, names
: List
[str], level
: Count
,
127 templates
: _OpTemplates
, offset_in_byte
: Optional
[Count
]):
128 super().__init
__(ft
, names
, level
, templates
)
129 assert offset_in_byte
is None or (offset_in_byte
>= 0 and offset_in_byte
< 8)
130 self
._offset
_in
_byte
= offset_in_byte
133 def offset_in_byte(self
) -> Optional
[Count
]:
134 return self
._offset
_in
_byte
137 _SpecSerializeWriteTemplates
= Mapping
[str, barectf_template
._Template
]
140 # An operation builder.
142 # Such a builder is closely connected to a `_CodeGen` object using it to
143 # find generic templates.
145 # Call build_for_root_ft() to make an operation builder create a
146 # compound operation for a given root structure field type, recursively,
149 def __init__(self
, cg
: '_CodeGen'):
150 self
._names
: List
[str] = []
151 self
._level
= Count(0)
152 self
._offset
_in
_byte
: Optional
[Count
] = None
155 # Whether or not we're within an array operation.
158 return self
._level
> 0
160 # Creates and returns an operation for the root structure field type
163 # `spec_serialize_write_templates` is a mapping of first level
164 # member names to specialized serialization "write" templates.
165 def build_for_root_ft(self
, ft
: barectf_config
.StructureFieldType
, name
: str,
166 spec_serialize_write_templates
: Optional
[_SpecSerializeWriteTemplates
] = None) -> _CompoundOp
:
167 assert ft
is not None
169 if spec_serialize_write_templates
is None:
170 spec_serialize_write_templates
= {}
172 assert type(ft
) is barectf_config
.StructureFieldType
173 assert len(self
._names
) == 0
174 assert self
._level
== 0
175 ops
= self
._build
_for
_ft
(ft
, name
, spec_serialize_write_templates
)
177 assert type(ops
[0]) is _CompoundOp
178 return typing
.cast(_CompoundOp
, ops
[0])
180 # Creates and returns the operation(s) for a given field type `ft`
183 # See build_for_root_ft() for `spec_serialize_write_templates`.
184 def _build_for_ft(self
, ft
: barectf_config
._FieldType
, name
: str,
185 spec_serialize_write_templates
: _SpecSerializeWriteTemplates
) -> List
[_Op
]:
186 def top_name() -> str:
187 return self
._names
[-1]
189 # Creates and returns a "write" operation for the field type
192 # This function considers `spec_serialize_write_templates` to
193 # override generic templates.
194 def create_write_op(ft
: barectf_config
._FieldType
) -> _WriteOp
:
195 assert type(ft
) is not barectf_config
.StructureFieldType
196 offset_in_byte
= self
._offset
_in
_byte
198 if isinstance(ft
, barectf_config
._BitArrayFieldType
) and self
._offset
_in
_byte
is not None:
199 self
._offset
_in
_byte
= Count((self
._offset
_in
_byte
+ ft
.size
) % 8)
201 serialize_write_templ
: Optional
[barectf_template
._Template
] = None
203 if len(self
._names
) == 2:
204 serialize_write_templ
= spec_serialize_write_templates
.get(top_name())
206 if serialize_write_templ
is None:
207 if isinstance(ft
, barectf_config
._IntegerFieldType
):
208 serialize_write_templ
= self
._cg
._serialize
_write
_int
_statements
_templ
209 elif type(ft
) is barectf_config
.RealFieldType
:
210 serialize_write_templ
= self
._cg
._serialize
_write
_real
_statements
_templ
212 assert type(ft
) is barectf_config
.StringFieldType
213 serialize_write_templ
= self
._cg
._serialize
_write
_string
_statements
_templ
215 size_write_templ
= None
217 if isinstance(ft
, barectf_config
._BitArrayFieldType
):
218 size_write_templ
= self
._cg
._size
_write
_bit
_array
_statements
_templ
219 elif type(ft
) is barectf_config
.StringFieldType
:
220 size_write_templ
= self
._cg
._size
_write
_string
_statements
_templ
222 return _WriteOp(ft
, self
._names
, self
._level
,
223 _OpTemplates(serialize_write_templ
, size_write_templ
), offset_in_byte
)
225 # Creates and returns an "align" operation for the field type
228 # This function updates the builder's state.
229 def try_create_align_op(alignment
: Alignment
, ft
: barectf_config
._FieldType
) -> Optional
[_AlignOp
]:
230 def align(v
: Count
, alignment
: Alignment
) -> Count
:
231 return Count((v
+ (alignment
- 1)) & -alignment
)
233 if self
._offset
_in
_byte
is None and alignment
% 8 == 0:
234 self
._offset
_in
_byte
= Count(0)
237 self
._offset
_in
_byte
= None
238 elif self
._offset
_in
_byte
is not None:
239 self
._offset
_in
_byte
= Count(align(self
._offset
_in
_byte
, alignment
) % 8)
242 return _AlignOp(ft
, self
._names
, self
._level
,
243 _OpTemplates(self
._cg
._serialize
_align
_statements
_templ
,
244 self
._cg
._size
_align
_statements
_templ
),
249 # Returns whether or not `ft` is a compound field type.
250 def ft_is_compound(ft
: barectf_config
._FieldType
) -> bool:
251 return isinstance(ft
, (barectf_config
.StructureFieldType
, barectf_config
.StaticArrayFieldType
))
253 # push field type's name to the builder's name stack initially
254 self
._names
.append(name
)
256 # operations to return
259 if type(ft
) is barectf_config
.StringFieldType
or self
._names
== [_RootFtPrefixes
.PH
, 'uuid']:
260 # strings and UUID array are always byte-aligned
261 op
= try_create_align_op(Alignment(8), ft
)
266 ops
.append(create_write_op(ft
))
268 if ft_is_compound(ft
):
269 self
._offset
_in
_byte
= None
271 init_align_op
= try_create_align_op(ft
.alignment
, ft
)
272 subops
: List
[_Op
] = []
274 if type(ft
) is barectf_config
.StructureFieldType
:
275 ft
= typing
.cast(barectf_config
.StructureFieldType
, ft
)
277 if init_align_op
is not None:
278 # Append structure field's alignment as a
281 # This is not strictly needed (could be appended to
282 # `ops`), but the properties of `_DsOps` and
283 # `_ErOps` offer a single (structure field type)
285 subops
.append(init_align_op
)
287 # append suboperations for each member
288 for member_name
, member
in ft
.members
.items():
289 subops
+= self
._build
_for
_ft
(member
.field_type
, member_name
,
290 spec_serialize_write_templates
)
292 # create structure field's compound operation
293 ops
.append(_CompoundOp(ft
, self
._names
, self
._level
,
294 _OpTemplates(self
._cg
._serialize
_write
_struct
_statements
_templ
,
295 self
._cg
._size
_write
_struct
_statements
_templ
),
297 elif isinstance(ft
, barectf_config
._ArrayFieldType
):
298 ft
= typing
.cast(barectf_config
._ArrayFieldType
, ft
)
299 assert ft
.alignment
== 1 or init_align_op
is not None
301 if init_align_op
is not None:
302 ops
.append(init_align_op
)
304 # append element's suboperations
305 self
._level
= Count(self
._level
+ 1)
306 subops
+= self
._build
_for
_ft
(ft
.element_field_type
,
307 f
'[{_loop_var_name(Count(self._level - 1))}]',
308 spec_serialize_write_templates
)
309 self
._level
= Count(self
._level
- 1)
311 # select the right templates
312 if type(ft
) is barectf_config
.StaticArrayFieldType
:
313 templates
= _OpTemplates(self
._cg
._serialize
_write
_static
_array
_statements
_templ
,
314 self
._cg
._size
_write
_static
_array
_statements
_templ
)
316 assert type(ft
) is barectf_config
.DynamicArrayFieldType
317 templates
= _OpTemplates(self
._cg
._serialize
_write
_dynamic
_array
_statements
_templ
,
318 self
._cg
._size
_write
_dynamic
_array
_statements
_templ
)
320 # create array field's compound operation
321 ops
.append(_CompoundOp(ft
, self
._names
, self
._level
, templates
, subops
))
323 # leaf field: align + write
324 if init_align_op
is not None:
325 ops
.append(init_align_op
)
327 ops
.append(create_write_op(ft
))
329 # exiting for this field type: pop its name
335 _OptCompoundOp
= Optional
[_CompoundOp
]
338 # The operations for an event record.
340 # The available operations are:
342 # * Specific context operation.
343 # * Payload operation.
345 def __init__(self
, spec_ctx_op
: _OptCompoundOp
, payload_op
: _OptCompoundOp
):
346 self
._spec
_ctx
_op
= spec_ctx_op
347 self
._payload
_op
= payload_op
350 def spec_ctx_op(self
) -> _OptCompoundOp
:
351 return self
._spec
_ctx
_op
354 def payload_op(self
) -> _OptCompoundOp
:
355 return self
._payload
_op
358 _ErOpsMap
= Mapping
[barectf_config
.EventRecordType
, _ErOps
]
361 # The operations for a data stream.
363 # The available operations are:
365 # * Packet header operation.
366 # * Packet context operation.
367 # * Event record header operation.
368 # * Event record common context operation.
369 # * Event record operations (`_ErOps`).
371 def __init__(self
, pkt_header_op
: _OptCompoundOp
, pkt_ctx_op
: _CompoundOp
,
372 er_header_op
: _OptCompoundOp
, er_common_ctx_op
: _OptCompoundOp
, er_ops
: _ErOpsMap
):
373 self
._pkt
_header
_op
= pkt_header_op
374 self
._pkt
_ctx
_op
= pkt_ctx_op
375 self
._er
_header
_op
= er_header_op
376 self
._er
_common
_ctx
_op
= er_common_ctx_op
377 self
._er
_ops
= er_ops
380 def pkt_header_op(self
) -> _OptCompoundOp
:
381 return self
._pkt
_header
_op
384 def pkt_ctx_op(self
) -> _CompoundOp
:
385 return self
._pkt
_ctx
_op
388 def er_header_op(self
) -> _OptCompoundOp
:
389 return self
._er
_header
_op
392 def er_common_ctx_op(self
) -> _OptCompoundOp
:
393 return self
._er
_common
_ctx
_op
396 def er_ops(self
) -> _ErOpsMap
:
400 # The C variable name prefixes for the six kinds of root field types.
401 class _RootFtPrefixes
:
410 # The human-readable names of the `_RootFtPrefixes` members.
411 _ROOT_FT_PREFIX_NAMES
= {
412 _RootFtPrefixes
.PH
: 'packet header',
413 _RootFtPrefixes
.PC
: 'packet context',
414 _RootFtPrefixes
.ERH
: 'event record header',
415 _RootFtPrefixes
.ERCC
: 'event record common context',
416 _RootFtPrefixes
.SC
: 'specific context',
417 _RootFtPrefixes
.P
: 'payload',
421 # A named function parameter for a given field type.
422 _FtParam
= collections
.namedtuple('_FtParam', ['ft', 'name'])
425 # C type abstract base class.
427 def __init__(self
, is_const
: bool):
428 self
._is
_const
= is_const
431 def is_const(self
) -> bool:
432 return self
._is
_const
436 class _ArithCType(_CType
):
437 def __init__(self
, name
: str, is_const
: bool):
438 super().__init
__(is_const
)
442 def name(self
) -> str:
445 def __str__(self
) -> str:
446 return f
'{"const " if self._is_const else ""}{self._name}'
450 class _PointerCType(_CType
):
451 def __init__(self
, pointed_c_type
: _CType
, is_const
: bool):
452 super().__init
__(is_const
)
453 self
._pointed
_c
_type
= pointed_c_type
456 def pointed_c_type(self
) -> _CType
:
457 return self
._pointed
_c
_type
459 def __str__(self
) -> str:
460 s
= str(self
._pointed
_c
_type
)
462 if not s
.endswith('*'):
473 # Returns the name of a loop variable given a nesting level `level`.
474 def _loop_var_name(level
: Count
) -> str:
478 return f
'k{level - 2}'
481 # A C code generator.
483 # Such a code generator can generate:
485 # * The bitfield header (gen_bitfield_header()).
486 # * The public header (gen_header()).
487 # * The source code (gen_src()).
489 def __init__(self
, cfg
: barectf_config
.Configuration
):
491 self
._iden
_prefix
= cfg
.options
.code_generation_options
.identifier_prefix
492 self
._templ
_filters
: Mapping
[str, Callable
[..., Any
]] = {
493 'ft_c_type': self
._ft
_c
_type
,
494 'open_func_params_str': self
._open
_func
_params
_str
,
495 'trace_func_params_str': self
._trace
_func
_params
_str
,
496 'serialize_er_common_ctx_func_params_str': self
._serialize
_er
_common
_ctx
_func
_params
_str
,
497 'loop_var_name': _loop_var_name
,
498 'op_src_var_name': self
._op
_src
_var
_name
,
500 self
._func
_proto
_params
_templ
= self
._create
_template
('func-proto-params.j2')
501 self
._serialize
_align
_statements
_templ
= self
._create
_template
('serialize-align-statements.j2')
502 self
._serialize
_write
_int
_statements
_templ
= self
._create
_template
('serialize-write-int-statements.j2')
503 self
._serialize
_write
_real
_statements
_templ
= self
._create
_template
('serialize-write-real-statements.j2')
504 self
._serialize
_write
_string
_statements
_templ
= self
._create
_template
('serialize-write-string-statements.j2')
505 self
._serialize
_write
_struct
_statements
_templ
= self
._create
_template
('serialize-write-struct-statements.j2')
506 self
._serialize
_write
_static
_array
_statements
_templ
= self
._create
_template
('serialize-write-static-array-statements.j2')
507 self
._serialize
_write
_dynamic
_array
_statements
_templ
= self
._create
_template
('serialize-write-dynamic-array-statements.j2')
508 self
._serialize
_write
_magic
_statements
_templ
= self
._create
_template
('serialize-write-magic-statements.j2')
509 self
._serialize
_write
_uuid
_statements
_templ
= self
._create
_template
('serialize-write-uuid-statements.j2')
510 self
._serialize
_write
_dst
_id
_statements
_templ
= self
._create
_template
('serialize-write-dst-id-statements.j2')
511 self
._serialize
_write
_timestamp
_statements
_templ
= self
._create
_template
('serialize-write-timestamp-statements.j2')
512 self
._serialize
_write
_packet
_size
_statements
_templ
= self
._create
_template
('serialize-write-packet-size-statements.j2')
513 self
._serialize
_write
_skip
_save
_statements
_templ
= self
._create
_template
('serialize-write-skip-save-statements.j2')
514 self
._serialize
_write
_ert
_id
_statements
_templ
= self
._create
_template
('serialize-write-ert-id-statements.j2')
515 self
._size
_align
_statements
_templ
= self
._create
_template
('size-align-statements.j2')
516 self
._size
_write
_bit
_array
_statements
_templ
= self
._create
_template
('size-write-bit-array-statements.j2')
517 self
._size
_write
_string
_statements
_templ
= self
._create
_template
('size-write-string-statements.j2')
518 self
._size
_write
_struct
_statements
_templ
= self
._create
_template
('size-write-struct-statements.j2')
519 self
._size
_write
_static
_array
_statements
_templ
= self
._create
_template
('size-write-static-array-statements.j2')
520 self
._size
_write
_dynamic
_array
_statements
_templ
= self
._create
_template
('size-write-dynamic-array-statements.j2')
522 # Creates and returns a template named `name` which is a file
523 # template if `is_file_template` is `True`.
525 # `name` is the file name, including the `.j2` extension, within the
528 # Such a template has the filters custom filters
529 # `self._templ_filters`.
530 def _create_template_base(self
, name
: str,
531 is_file_template
: bool) -> barectf_template
._Template
:
532 return barectf_template
._Template
(f
'c/{name}', is_file_template
, self
._cfg
,
535 # Creates and returns a non-file template named `name`.
537 # See _create_template_base() for `name`.
538 def _create_template(self
, name
: str) -> barectf_template
._Template
:
539 return self
._create
_template
_base
(name
, False)
541 # Creates and returns a file template named `name`.
543 # See _create_template_base() for `name`.
544 def _create_file_template(self
, name
: str) -> barectf_template
._Template
:
545 return self
._create
_template
_base
(name
, True)
547 # Trace type of this code generator's barectf configuration.
549 def _trace_type(self
) -> barectf_config
.TraceType
:
550 return self
._cfg
.trace
.type
552 # Returns the name of a source variable for the operation `op`.
553 def _op_src_var_name(self
, op
: _LeafOp
) -> str:
556 for index
, name
in enumerate(op
.names
):
557 if index
> 0 and not name
.startswith('['):
564 # Returns the C type for the field type `ft`, making it `const` if
565 # `is_const` is `True`.
566 def _ft_c_type(self
, ft
: barectf_config
._FieldType
, is_const
: bool = False):
567 if isinstance(ft
, barectf_config
._IntegerFieldType
):
568 ft
= typing
.cast(barectf_config
._IntegerFieldType
, ft
)
569 sign_prefix
= 'u' if isinstance(ft
, barectf_config
.UnsignedIntegerFieldType
) else ''
581 return _ArithCType(f
'{sign_prefix}int{sz}_t', is_const
)
582 elif type(ft
) is barectf_config
.RealFieldType
:
583 ft
= typing
.cast(barectf_config
.RealFieldType
, ft
)
585 if ft
.size
== 32 and ft
.alignment
== 32:
587 elif ft
.size
== 64 and ft
.alignment
== 64:
592 return _ArithCType(s
, is_const
)
593 elif type(ft
) is barectf_config
.StringFieldType
:
594 return _PointerCType(_ArithCType('char', True), is_const
)
596 assert isinstance(ft
, barectf_config
._ArrayFieldType
)
597 ft
= typing
.cast(barectf_config
._ArrayFieldType
, ft
)
598 return _PointerCType(self
._ft
_c
_type
(ft
.element_field_type
, True), is_const
)
600 # Returns the function prototype parameters for the members of the
601 # root structure field type `root_ft`.
603 # Each parameter has the prefix `name_prefix` followed with `_`.
605 # Members of which the name is in `exclude_set` are excluded.
606 def _proto_params_str(self
, root_ft
: Optional
[barectf_config
.StructureFieldType
],
607 name_prefix
: str, const_params
: bool,
608 exclude_set
: Optional
[Set
[str]] = None, only_dyn
: bool = False) -> str:
612 if exclude_set
is None:
617 for member_name
, member
in root_ft
.members
.items():
618 if member_name
in exclude_set
:
621 is_dyn
= member
.field_type
.size_is_dynamic
623 if isinstance(member
.field_type
, barectf_config
.UnsignedIntegerFieldType
):
624 ft
= typing
.cast(barectf_config
.UnsignedIntegerFieldType
, member
.field_type
)
625 is_dyn
= is_dyn
or ft
._is
_len
627 if only_dyn
and not is_dyn
:
630 params
.append(_FtParam(member
.field_type
, member_name
))
632 return self
._func
_proto
_params
_templ
.render(params
=params
, prefix
=name_prefix
,
633 const_params
=const_params
)
635 # Returns the packet opening function prototype parameters for the
636 # data stream type `dst`.
637 def _open_func_params_str(self
, dst
: barectf_config
.DataStreamType
, const_params
: bool) -> str:
639 parts
.append(self
._proto
_params
_str
(self
._trace
_type
._pkt
_header
_ft
, _RootFtPrefixes
.PH
,
640 const_params
, {'magic', 'stream_id', 'uuid'}))
649 parts
.append(self
._proto
_params
_str
(dst
._pkt
_ctx
_ft
, _RootFtPrefixes
.PC
, const_params
,
651 return ''.join(parts
)
653 # Returns the tracing function prototype parameters for the data
654 # stream and event record types `ds_er_types`.
655 def _trace_func_params_str(self
, ds_er_types
: Tuple
[barectf_config
.DataStreamType
,
656 barectf_config
.EventRecordType
],
657 const_params
: bool, only_dyn
: bool = False):
662 if dst
._er
_header
_ft
is not None:
663 parts
.append(self
._proto
_params
_str
(dst
._er
_header
_ft
, _RootFtPrefixes
.ERH
,
664 const_params
, {'id', 'timestamp'},
667 if dst
.event_record_common_context_field_type
is not None:
668 parts
.append(self
._proto
_params
_str
(dst
.event_record_common_context_field_type
,
669 _RootFtPrefixes
.ERCC
, const_params
,
672 if ert
.specific_context_field_type
is not None:
673 parts
.append(self
._proto
_params
_str
(ert
.specific_context_field_type
,
674 _RootFtPrefixes
.SC
, const_params
,
677 if ert
.payload_field_type
is not None:
678 parts
.append(self
._proto
_params
_str
(ert
.payload_field_type
, _RootFtPrefixes
.P
,
679 const_params
, only_dyn
=only_dyn
))
681 return ''.join(parts
)
683 # Returns the event record common context serialization function
684 # prototype parameters for the data stream type `dst`.
685 def _serialize_er_common_ctx_func_params_str(self
, dst
: barectf_config
.DataStreamType
,
686 const_params
: bool) -> str:
687 return self
._proto
_params
_str
(dst
.event_record_common_context_field_type
,
688 _RootFtPrefixes
.ERCC
, const_params
)
690 # Generates the bitfield header file contents.
691 def gen_bitfield_header(self
) -> str:
692 return self
._create
_file
_template
('bitfield.h.j2').render()
694 # Generates the public header file contents.
695 def gen_header(self
) -> str:
696 return self
._create
_file
_template
('barectf.h.j2').render(root_ft_prefixes
=_RootFtPrefixes
)
698 # Generates the source code file contents.
699 def gen_src(self
, header_file_name
: str, bitfield_header_file_name
: str) -> str:
700 # Creates and returns the operations for all the data stream and
701 # for all their event records.
702 def create_ds_ops() -> Mapping
[barectf_config
.DataStreamType
, _DsOps
]:
705 for dst
in self
._trace
_type
.data_stream_types
:
707 builder
= _OpBuilder(self
)
708 pkt_header_ft
= self
._trace
_type
._pkt
_header
_ft
710 # packet header operations
711 if pkt_header_ft
is not None:
712 spec_serialize_write_templates
= {
713 'magic': self
._serialize
_write
_magic
_statements
_templ
,
714 'uuid': self
._serialize
_write
_uuid
_statements
_templ
,
715 'stream_id': self
._serialize
_write
_dst
_id
_statements
_templ
,
717 pkt_header_op
= builder
.build_for_root_ft(pkt_header_ft
,
719 spec_serialize_write_templates
)
721 # packet context operation
722 spec_serialize_write_templates
= {
723 'timestamp_begin': self
._serialize
_write
_timestamp
_statements
_templ
,
724 'packet_size': self
._serialize
_write
_packet
_size
_statements
_templ
,
725 'timestamp_end': self
._serialize
_write
_skip
_save
_statements
_templ
,
726 'events_discarded': self
._serialize
_write
_skip
_save
_statements
_templ
,
727 'content_size': self
._serialize
_write
_skip
_save
_statements
_templ
,
729 pkt_ctx_op
= builder
.build_for_root_ft(dst
._pkt
_ctx
_ft
, _RootFtPrefixes
.PC
,
730 spec_serialize_write_templates
)
732 # event record header operation
733 builder
= _OpBuilder(self
)
736 if dst
._er
_header
_ft
is not None:
737 spec_serialize_write_templates
= {
738 'timestamp': self
._serialize
_write
_timestamp
_statements
_templ
,
739 'id': self
._serialize
_write
_ert
_id
_statements
_templ
,
741 er_header_op
= builder
.build_for_root_ft(dst
._er
_header
_ft
, _RootFtPrefixes
.ERH
,
742 spec_serialize_write_templates
)
744 # event record common context operation
745 er_common_ctx_op
= None
747 if dst
.event_record_common_context_field_type
is not None:
748 er_common_ctx_op
= builder
.build_for_root_ft(dst
.event_record_common_context_field_type
,
749 _RootFtPrefixes
.ERCC
)
751 # operations specific to each event record type
754 for ert
in dst
.event_record_types
:
755 ev_builder
= copy
.copy(builder
)
757 # specific context operation
760 if ert
.specific_context_field_type
is not None:
761 spec_ctx_op
= ev_builder
.build_for_root_ft(ert
.specific_context_field_type
,
767 if ert
.payload_field_type
is not None:
768 payload_op
= ev_builder
.build_for_root_ft(ert
.payload_field_type
,
771 er_ops
[ert
] = _ErOps(spec_ctx_op
, payload_op
)
773 ds_ops
[dst
] = _DsOps(pkt_header_op
, pkt_ctx_op
, er_header_op
, er_common_ctx_op
,
778 # Returns the "write" operation for the packet context member
779 # named `member_name` within the data stream type `dst`.
780 def ds_op_pkt_ctx_op(dst
: barectf_config
.DataStreamType
, member_name
: str) -> _Op
:
783 for op
in ds_ops
[dst
].pkt_ctx_op
.subops
:
784 if op
.top_name
== member_name
and type(op
) is _WriteOp
:
788 assert ret_op
is not None
789 return typing
.cast(_Op
, ret_op
)
791 ds_ops
= create_ds_ops()
792 c_src
= self
._create
_file
_template
('barectf.c.j2').render(header_file_name
=header_file_name
,
793 bitfield_header_file_name
=bitfield_header_file_name
,
794 root_ft_prefixes
=_RootFtPrefixes
,
795 root_ft_prefix_names
=_ROOT_FT_PREFIX_NAMES
,
797 ds_op_pkt_ctx_op
=ds_op_pkt_ctx_op
)
799 # Jinja 2 makes it hard to have multiple contiguous blocks
800 # delimited with empty lines when using a for loop, while not
801 # also having an empty line at the end.
803 # Therefore, we often get this rendered pattern:
816 # It's ugly, so fix it here.
817 return re
.sub(r
'(\n)\s*\n(\s*})', r
'\1\2', c_src
)