1"""Tests for UnionType support in codegen (CppTypePlanner + CppTypeEmitter)."""
5from pathlib
import Path
12 """Helper: run the planner + emitter on a type table and return the header."""
15 with tempfile.TemporaryDirectory()
as tmpdir:
16 emitter.write_header(Path(tmpdir), system_name)
17 return (Path(tmpdir) /
"types.h").read_text()
21 """Find the generated SegmentedMessageData subclass name for a window.
23 Auto-names compose `{into_name}_{window_name}`, so locate the helper by its
24 trailing window-name suffix instead of hard-coding the full identifier.
27 rf
"struct (\S*{re.escape(window_name_suffix)}) "
28 r": public esi::SegmentedMessageData", hdr)
29 assert match, f
"Window helper for '*{window_name_suffix}' not found in:\n{hdr}"
34 """A simple union with two scalar fields produces a C++ union."""
35 uint8 = types.UIntType(
"ui8", 8)
36 uint16 = types.UIntType(
"ui16", 16)
37 union_t = types.UnionType(
"!hw.union<a: ui8, b: ui16>", [(
"a", uint8),
41 assert "union " in hdr
42 assert '_ESI_ID = "!hw.union<a: ui8, b: ui16>"' in hdr
45 assert "struct _union_a_ui8_b_ui16_a" in hdr
46 assert "uint8_t _pad[1]" in hdr
47 assert "uint8_t a;" in hdr
49 pad_pos = hdr.index(
"uint8_t _pad[1]")
50 field_a_pos = hdr.index(
"uint8_t a;")
51 assert pad_pos < field_a_pos
53 assert "uint16_t b;" in hdr
55 wrapper_pos = hdr.index(
"struct _union_a_ui8_b_ui16_a")
56 union_pos = hdr.index(
"union ")
57 assert wrapper_pos < union_pos
59 union_body = hdr[union_pos:]
60 assert union_body.index(
"a;") < union_body.index(
"b;")
62 assert "_union_a_ui8_b_ui16_a a;" in union_body
66 """A union containing a struct field emits the struct before the union."""
67 uint8 = types.UIntType(
"ui8", 8)
68 uint16 = types.UIntType(
"ui16", 16)
69 inner = types.StructType(
"!hw.struct<x: ui8, y: ui8>", [(
"x", uint8),
71 union_t = types.UnionType(
"!hw.union<header: ui16, data: !s>",
72 [(
"header", uint16), (
"data", inner)])
76 struct_pos = hdr.index(
"struct _struct")
77 union_pos = hdr.index(
"union ")
78 assert struct_pos < union_pos
82 assert "_pad" not in hdr
86 """Unions are properly ordered with respect to struct dependencies."""
87 uint8 = types.UIntType(
"ui8", 8)
88 s1 = types.StructType(
"!hw.struct<p: ui8>", [(
"p", uint8)])
89 s2 = types.StructType(
"!hw.struct<q: ui8>", [(
"q", uint8)])
90 union_t = types.UnionType(
"!hw.union<a: !s1, b: !s2>", [(
"a", s1), (
"b", s2)])
93 union_pos = hdr.index(
"union ")
95 for keyword
in [
"struct _struct_p_ui8",
"struct _struct_q_ui8"]:
97 assert hdr.index(keyword) < union_pos
101 """A struct with a union field emits the union before the struct."""
102 uint8 = types.UIntType(
"ui8", 8)
103 uint16 = types.UIntType(
"ui16", 16)
104 union_t = types.UnionType(
"!hw.union<a: ui8, b: ui16>", [(
"a", uint8),
106 outer = types.StructType(
"!hw.struct<tag: ui8, data: !u>",
107 [(
"tag", uint8), (
"data", union_t)])
110 assert "union " in hdr
113 wrapper_pos = hdr.index(
"struct _union")
114 union_pos = hdr.index(
"union ")
115 struct_pos = hdr.index(
"struct _struct")
116 assert wrapper_pos < union_pos < struct_pos
120 """The planner auto-generates deterministic names for unions."""
121 uint8 = types.UIntType(
"ui8", 8)
122 union_t = types.UnionType(
"!hw.union<x: ui8>", [(
"x", uint8)])
125 assert union_t
in planner.type_id_map
126 name = planner.type_id_map[union_t]
127 assert name.startswith(
"_union")
131 """A TypeAlias wrapping a union emits the union then a using alias."""
132 uint8 = types.UIntType(
"ui8", 8)
133 uint16 = types.UIntType(
"ui16", 16)
134 union_t = types.UnionType(
"!hw.union<a: ui8, b: ui16>", [(
"a", uint8),
136 alias = types.TypeAlias(
"!hw.typealias<MyUnion>",
"MyUnion", union_t)
139 assert "union " in hdr
140 assert "using MyUnion" in hdr
144 """Integrals of the same width don't need padding wrappers."""
145 uint16 = types.UIntType(
"ui16", 16)
146 sint16 = types.SIntType(
"si16", 16)
147 union_t = types.UnionType(
"!hw.union<a: ui16, b: si16>", [(
"a", uint16),
151 assert "union " in hdr
152 assert "_pad" not in hdr
154 union_body = hdr[hdr.index(
"union "):]
155 assert "uint16_t a;" in union_body
156 assert "int16_t b;" in union_body
160 """Union fields are emitted in declaration order, not reversed."""
161 uint8 = types.UIntType(
"ui8", 8)
162 sint16 = types.SIntType(
"si16", 16)
163 uint32 = types.UIntType(
"ui32", 32)
164 union_t = types.UnionType(
"!hw.union<z: ui8, m: si16, a: ui32>",
165 [(
"z", uint8), (
"m", sint16), (
"a", uint32)])
169 assert "_pad[3]" in hdr
170 assert "_pad[2]" in hdr
172 z_pad = hdr.index(
"_pad[3]")
173 z_field = hdr.index(
"uint8_t z;")
174 assert z_pad < z_field
175 m_pad = hdr.index(
"_pad[2]")
176 m_field = hdr.index(
"int16_t m;")
177 assert m_pad < m_field
179 union_body = hdr[hdr.index(
"union "):]
180 z_pos = union_body.index(
" z;")
181 m_pos = union_body.index(
" m;")
182 a_pos = union_body.index(
" a;")
183 assert z_pos < m_pos < a_pos
185 assert "uint32_t a;" in union_body
187 assert "_union_z_ui8_m_si16_a_ui32_z z;" in union_body
188 assert "_union_z_ui8_m_si16_a_ui32_m m;" in union_body
192 """Bulk-encoded list windows emit a SegmentedMessageData helper."""
193 uint16 = types.UIntType(
"ui16", 16)
194 uint32 = types.UIntType(
"ui32", 32)
195 coord_struct_id =
"!hw.struct<x: ui32, y: ui32>"
197 f
"!hw.typealias<@esi_runtime_codegen::@Coord, {coord_struct_id}>")
198 coord_list_id = f
"!esi.list<{coord_alias_id}>"
200 f
"!hw.struct<x_translation: ui32, y_translation: ui32, coords: "
203 "!hw.struct<x_translation: ui32, y_translation: ui32, coords_count: "
205 data_struct_id = f
"!hw.struct<coords: !hw.array<1x{coord_alias_id}>>"
206 lowered_id = f
"!hw.union<header: {header_struct_id}, data: {data_struct_id}>"
207 serial_args_id = (f
'!esi.window<"serial_coord_args", {arg_struct_id}, '
208 '[<"header", [<"x_translation">, <"y_translation">, '
209 '<"coords" countWidth 16>]>, <"data", [<"coords", 1>]>]>')
211 coord_inner = types.StructType(coord_struct_id, [(
"x", uint32),
213 coord = types.TypeAlias(coord_alias_id,
"Coord", coord_inner)
214 coord_list = types.ListType(coord_list_id, coord)
215 arg_struct = types.StructType(arg_struct_id, [(
"x_translation", uint32),
216 (
"y_translation", uint32),
217 (
"coords", coord_list)])
218 header_struct = types.StructType(header_struct_id, [(
"x_translation", uint32),
219 (
"y_translation", uint32),
220 (
"coords_count", uint16)])
221 data_struct = types.StructType(
223 [(
"coords", types.ArrayType(f
"!hw.array<1x{coord_alias_id}>", coord, 1))],
225 lowered = types.UnionType(lowered_id, [(
"header", header_struct),
226 (
"data", data_struct)])
227 serial_args = types.WindowType(
228 serial_args_id,
"serial_coord_args", arg_struct, lowered, [
229 types.WindowType.Frame(
232 types.WindowType.Field(
"x_translation", 0, 0),
233 types.WindowType.Field(
"y_translation", 0, 0),
234 types.WindowType.Field(
"coords", 0, 16),
237 types.WindowType.Frame(
239 [types.WindowType.Field(
"coords", 1, 0)],
244 assert "Unsupported type" not in hdr
246 assert f
"struct {win_name} : public esi::SegmentedMessageData" in hdr
247 assert "using value_type = Coord;" in hdr
248 assert "using count_type = uint16_t;" in hdr
249 assert "count_type coords_count;" in hdr
250 assert "uint8_t _pad[2];" in hdr
251 assert "Coord coords;" in hdr
252 assert hdr.index(
"struct data_frame {") < hdr.index(
253 "private:\n#pragma pack(push, 1)\n struct header_frame {")
254 assert "std::vector<data_frame> data_frames;" in hdr
255 assert "esi::Segment segment(size_t idx) const override" in hdr
256 assert "footer.coords_count = 0;" in hdr
257 assert "const std::vector<value_type> &coords" in hdr
258 assert "void construct(uint32_t x_translation, uint32_t y_translation, std::vector<data_frame> frames)" in hdr
259 assert "construct(x_translation, y_translation, std::move(frames));" in hdr
260 assert "auto &frame = frames.emplace_back();" in hdr
261 assert "for (const auto &element : coords) {" in hdr
262 assert "frame.coords = element;" in hdr
265 assert f
'_ESI_ID = "{arg_struct_id}"' in hdr
266 escaped_serial_args_id = serial_args_id.replace(
'"',
'\\"')
267 assert f
'_ESI_WINDOW_ID = "{escaped_serial_args_id}"' in hdr
268 assert f
'throw std::out_of_range("{win_name}: invalid segment index")' in hdr
270 assert "uint32_t x_translation() const { return header.x_translation; }" in hdr
271 assert "uint32_t y_translation() const { return header.y_translation; }" in hdr
272 assert "size_t coords_count() const { return data_frames.size(); }" in hdr
274 assert "return std::views::transform(data_frames, &data_frame::coords);" in hdr
275 assert "std::vector<value_type> coords_vector() const" in hdr
276 assert "out.push_back(frame.coords);" in hdr
280 """Headers pad out to the data frame width for count-only windows."""
281 uint16 = types.UIntType(
"ui16", 16)
282 uint32 = types.UIntType(
"ui32", 32)
283 element_id =
"!hw.struct<x: ui32, y: ui32>"
284 list_id = f
"!esi.list<{element_id}>"
285 arg_struct_id = f
"!hw.struct<coords: {list_id}>"
286 header_struct_id =
"!hw.struct<coords_count: ui16>"
287 data_struct_id = f
"!hw.struct<coords: !hw.array<1x{element_id}>>"
288 lowered_id = f
"!hw.union<header: {header_struct_id}, data: {data_struct_id}>"
289 window_id = (f
'!esi.window<"coords_only", {arg_struct_id}, '
290 '[<"header", [<"coords" countWidth 16>]>, '
291 '<"data", [<"coords", 1>]>]>')
293 element = types.StructType(element_id, [(
"x", uint32), (
"y", uint32)])
294 coord_list = types.ListType(list_id, element)
295 arg_struct = types.StructType(arg_struct_id, [(
"coords", coord_list)])
296 header_struct = types.StructType(header_struct_id, [(
"coords_count", uint16)])
297 data_struct = types.StructType(
299 [(
"coords", types.ArrayType(f
"!hw.array<1x{element_id}>", element, 1))],
301 lowered = types.UnionType(lowered_id, [(
"header", header_struct),
302 (
"data", data_struct)])
303 window = types.WindowType(window_id,
"coords_only", arg_struct, lowered, [
304 types.WindowType.Frame(
"header",
305 [types.WindowType.Field(
"coords", 0, 16)]),
306 types.WindowType.Frame(
"data", [types.WindowType.Field(
"coords", 1, 0)]),
311 assert f
"struct {win_name} : public esi::SegmentedMessageData" in hdr
312 assert "struct header_frame {\n uint8_t _pad[6];\n count_type coords_count;\n };" in hdr
313 assert "header_frame footer{};" in hdr
314 assert "void construct(std::vector<data_frame> frames)" in hdr
318 """Window helpers copy array header fields and array-valued elements."""
319 uint8 = types.UIntType(
"ui8", 8)
320 uint16 = types.UIntType(
"ui16", 16)
321 header_array_id =
"!hw.array<2xui16>"
322 value_array_id =
"!hw.array<4xui8>"
323 list_id = f
"!esi.list<{value_array_id}>"
325 f
"!hw.struct<header_words: {header_array_id}, payloads: {list_id}>")
327 f
"!hw.struct<header_words: {header_array_id}, payloads_count: ui16>")
328 data_struct_id = f
"!hw.struct<payloads: !hw.array<1x{value_array_id}>>"
329 lowered_id = f
"!hw.union<header: {header_struct_id}, data: {data_struct_id}>"
330 window_id = (f
'!esi.window<"array_payloads", {arg_struct_id}, '
331 '[<"header", [<"header_words">, <"payloads" countWidth 16>]>, '
332 '<"data", [<"payloads", 1>]>]>')
334 header_array = types.ArrayType(header_array_id, uint16, 2)
335 value_array = types.ArrayType(value_array_id, uint8, 4)
336 payload_list = types.ListType(list_id, value_array)
337 arg_struct = types.StructType(arg_struct_id, [(
"header_words", header_array),
338 (
"payloads", payload_list)])
339 header_struct = types.StructType(header_struct_id,
340 [(
"header_words", header_array),
341 (
"payloads_count", uint16)])
342 data_struct = types.StructType(
345 types.ArrayType(f
"!hw.array<1x{value_array_id}>", value_array, 1))],
347 lowered = types.UnionType(lowered_id, [(
"header", header_struct),
348 (
"data", data_struct)])
349 window = types.WindowType(window_id,
"array_payloads", arg_struct, lowered, [
350 types.WindowType.Frame(
353 types.WindowType.Field(
"header_words", 0, 0),
354 types.WindowType.Field(
"payloads", 0, 16),
357 types.WindowType.Frame(
359 [types.WindowType.Field(
"payloads", 1, 0)],
364 assert "#include <array>" in hdr
366 assert f
"struct {win_name} : public esi::SegmentedMessageData" in hdr
368 assert "using value_type = std::array<uint8_t, 4>;" in hdr
369 assert "using count_type = uint16_t;" in hdr
371 assert "std::array<uint16_t, 2> header_words;" in hdr
372 assert "std::array<uint8_t, 4> payloads;" in hdr
374 assert f
"{win_name}(const std::array<uint16_t, 2> &header_words, const std::vector<value_type> &payloads)" in hdr
375 assert "void construct(const std::array<uint16_t, 2> &header_words, std::vector<data_frame> frames)" in hdr
377 assert "header.header_words = header_words;" in hdr
378 assert "frame.payloads = element;" in hdr
379 assert f
'throw std::out_of_range("{win_name}: invalid segment index")' in hdr
381 assert "const std::array<uint16_t, 2> &header_words() const { return header.header_words; }" in hdr
385 assert "return std::views::transform(data_frames, &data_frame::payloads);" in hdr
386 assert "std::vector<value_type> payloads_vector() const" in hdr
387 assert "out.push_back(frame.payloads);" in hdr
391 """Struct-typed data fields use a pointer-to-member projection, not a lambda.
393 Even if the struct contains a non-byte-aligned (bit-field) member, the data
394 field itself is a struct type, which is byte-aligned and supports
395 pointer-to-member projection.
397 sint3 = types.SIntType(
"si3", 3)
398 uint16 = types.UIntType(
"ui16", 16)
399 list_id = f
"!esi.list<!hw.struct<v: si3>>"
400 elem_id =
"!hw.struct<v: si3>"
401 elem_struct = types.StructType(elem_id, [(
"v", sint3)])
402 elem_list = types.ListType(list_id, elem_struct)
403 arg_struct_id = f
"!hw.struct<items: {list_id}>"
404 arg_struct = types.StructType(arg_struct_id, [(
"items", elem_list)])
405 header_struct_id =
"!hw.struct<items_count: ui16>"
406 header_struct = types.StructType(header_struct_id, [(
"items_count", uint16)])
407 data_struct_id = f
"!hw.struct<items: !hw.array<1x{elem_id}>>"
408 data_struct = types.StructType(
410 [(
"items", types.ArrayType(f
"!hw.array<1x{elem_id}>", elem_struct, 1))],
413 f
"!hw.union<header: {header_struct_id}, data: {data_struct_id}>")
414 lowered = types.UnionType(lowered_id, [(
"header", header_struct),
415 (
"data", data_struct)])
416 window_id = (f
'!esi.window<"bitfield_items", {arg_struct_id}, '
417 '[<"header", [<"items" countWidth 16>]>, '
418 '<"data", [<"items", 1>]>]>')
419 window = types.WindowType(window_id,
"bitfield_items", arg_struct, lowered, [
420 types.WindowType.Frame(
"header",
421 [types.WindowType.Field(
"items", 0, 16)]),
422 types.WindowType.Frame(
"data", [types.WindowType.Field(
"items", 1, 0)]),
427 assert f
"struct {win_name} : public esi::SegmentedMessageData" in hdr
430 assert "return std::views::transform(data_frames, &data_frame::items);" in hdr
431 assert "[](const data_frame &f) { return f.items; }" not in hdr
432 assert "std::vector<value_type> items_vector() const" in hdr
436 """A window data field that is itself a non-byte-aligned int uses a lambda projection."""
437 uint3 = types.UIntType(
"ui3", 3)
438 uint16 = types.UIntType(
"ui16", 16)
440 list_id =
"!esi.list<ui3>"
441 elem_list = types.ListType(list_id, uint3)
442 arg_struct_id = f
"!hw.struct<vals: {list_id}>"
443 arg_struct = types.StructType(arg_struct_id, [(
"vals", elem_list)])
444 header_struct_id =
"!hw.struct<vals_count: ui16>"
445 header_struct = types.StructType(header_struct_id, [(
"vals_count", uint16)])
446 data_struct_id =
"!hw.struct<vals: !hw.array<1xui3>>"
447 data_struct = types.StructType(
449 [(
"vals", types.ArrayType(
"!hw.array<1xui3>", uint3, 1))],
452 f
"!hw.union<header: {header_struct_id}, data: {data_struct_id}>")
453 lowered = types.UnionType(lowered_id, [(
"header", header_struct),
454 (
"data", data_struct)])
455 window_id = (f
'!esi.window<"bitval_window", {arg_struct_id}, '
456 '[<"header", [<"vals" countWidth 16>]>, '
457 '<"data", [<"vals", 1>]>]>')
458 window = types.WindowType(window_id,
"bitval_window", arg_struct, lowered, [
459 types.WindowType.Frame(
"header", [types.WindowType.Field(
"vals", 0, 16)]),
460 types.WindowType.Frame(
"data", [types.WindowType.Field(
"vals", 1, 0)]),
465 assert f
"struct {win_name} : public esi::SegmentedMessageData" in hdr
468 assert "[](const data_frame &f) { return f.vals; }" in hdr
469 assert "&data_frame::vals" not in hdr
470 assert "std::vector<value_type> vals_vector() const" in hdr
474 """Each packed struct gets a `static_assert` pinning its `sizeof`."""
475 uint16 = types.UIntType(
"ui16", 16)
476 sint8 = types.SIntType(
"si8", 8)
477 s = types.StructType(
"!hw.struct<a: ui16, b: si8>", [(
"a", uint16),
482 assert "static_assert(sizeof(_struct_a_ui16_b_si8) == 3," in hdr
483 assert "packed layout does not match manifest size" in hdr
487 """Unions and their padding wrapper structs each get a size assert."""
488 uint8 = types.UIntType(
"ui8", 8)
489 uint16 = types.UIntType(
"ui16", 16)
490 union_t = types.UnionType(
"!hw.union<a: ui8, b: ui16>", [(
"a", uint8),
495 assert "static_assert(sizeof(_union_a_ui8_b_ui16) == 2," in hdr
497 assert "static_assert(sizeof(_union_a_ui8_b_ui16_a) == 2," in hdr
501 """Both `data_frame` and `header_frame` get size asserts inside the window."""
502 uint16 = types.UIntType(
"ui16", 16)
503 uint32 = types.UIntType(
"ui32", 32)
504 element_id =
"!hw.struct<x: ui32, y: ui32>"
505 list_id = f
"!esi.list<{element_id}>"
506 arg_struct_id = f
"!hw.struct<coords: {list_id}>"
507 header_struct_id =
"!hw.struct<coords_count: ui16>"
508 data_struct_id = f
"!hw.struct<coords: !hw.array<1x{element_id}>>"
509 lowered_id = f
"!hw.union<header: {header_struct_id}, data: {data_struct_id}>"
510 window_id = (f
'!esi.window<"coords_only", {arg_struct_id}, '
511 '[<"header", [<"coords" countWidth 16>]>, '
512 '<"data", [<"coords", 1>]>]>')
514 element = types.StructType(element_id, [(
"x", uint32), (
"y", uint32)])
515 coord_list = types.ListType(list_id, element)
516 arg_struct = types.StructType(arg_struct_id, [(
"coords", coord_list)])
517 header_struct = types.StructType(header_struct_id, [(
"coords_count", uint16)])
518 data_struct = types.StructType(
520 [(
"coords", types.ArrayType(f
"!hw.array<1x{element_id}>", element, 1))],
522 lowered = types.UnionType(lowered_id, [(
"header", header_struct),
523 (
"data", data_struct)])
524 window = types.WindowType(window_id,
"coords_only", arg_struct, lowered, [
525 types.WindowType.Frame(
"header",
526 [types.WindowType.Field(
"coords", 0, 16)]),
527 types.WindowType.Frame(
"data", [types.WindowType.Field(
"coords", 1, 0)]),
532 assert "static_assert(sizeof(data_frame) == 8," in hdr
533 assert "static_assert(sizeof(header_frame) == 8," in hdr
537 """Structs containing an `!esi.any` field have no static size, so no assert."""
538 uint8 = types.UIntType(
"ui8", 8)
539 any_t = types.AnyType(
"!esi.any")
540 s = types.StructType(
"!hw.struct<tag: ui8, data: !esi.any>",
541 [(
"tag", uint8), (
"data", any_t)])
545 assert "struct _struct_tag_ui8_data__esi_any" in hdr
546 assert "static_assert(sizeof(_struct_tag_ui8_data__esi_any)" not in hdr
550 """Void-typed struct fields are commented out so the header stays valid C++.
552 `void x;` is not a valid C++ field declaration. The codegen must instead
553 emit `// void x;` and exclude the field from the generated constructor.
555 uint8 = types.UIntType(
"ui8", 8)
556 void_t = types.VoidType(
"!esi.void")
557 s = types.StructType(
558 "!hw.struct<valid: ui8, client_data: void>",
559 [(
"valid", uint8), (
"client_data", void_t)],
564 assert re.search(
r"^\s*void\s+\w+;", hdr, re.M)
is None, hdr
566 assert "// void client_data;" in hdr
568 assert "uint8_t valid" in hdr
571 ctor_match = re.search(
r"_struct_[^\s(]*\(([^)]*)\) :", hdr)
572 assert ctor_match, f
"Constructor not found in:\n{hdr}"
573 ctor_params = ctor_match.group(1)
574 assert "client_data" not in ctor_params
575 assert "valid" in ctor_params
579 assert "static_assert(sizeof(_struct_valid_ui8_client_data__esi_void) == 1," \
584 """Void-typed union members are commented out and skip wrapper generation."""
585 uint16 = types.UIntType(
"ui16", 16)
586 void_t = types.VoidType(
"!esi.void")
588 "!hw.union<a: ui16, b: void>",
589 [(
"a", uint16), (
"b", void_t)],
595 assert re.search(
r"^\s*void\s+\w+;", hdr, re.M)
is None, hdr
596 assert "// void b;" in hdr
598 assert "_union_a_ui16_b__esi_void_b" not in hdr
600 union_body = hdr[hdr.index(
"union "):]
601 assert "uint16_t a;" in union_body
605 """An outer struct containing an inner struct with a void field must use
606 the inner struct's effective (post-void-elimination) size in its size
607 assertion, not the manifest's wire-format size.
609 uint8 = types.UIntType(
"ui8", 8)
610 uint64 = types.UIntType(
"ui64", 64)
611 void_t = types.VoidType(
"!esi.void")
612 inner = types.StructType(
613 "!hw.struct<valid: ui8, client_data: void>",
614 [(
"valid", uint8), (
"client_data", void_t)],
616 outer = types.StructType(
617 "!hw.struct<address: ui64, tag: ui8, "
618 "data: !hw.struct<valid: ui8, client_data: void>>",
619 [(
"address", uint64), (
"tag", uint8), (
"data", inner)],
624 assert "static_assert(sizeof(_struct_valid_ui8_client_data__esi_void) == 1," \
629 outer_assert = re.search(
630 r"static_assert\(sizeof\(_struct_address_ui64_tag_ui8_data_[^)]+\) == (\d+),",
633 assert outer_assert, f
"Outer size assertion not found in:\n{hdr}"
634 assert outer_assert.group(1) ==
"10", \
635 f
"Expected outer struct size 10, got {outer_assert.group(1)}"
639 """A struct whose fields are all void collapses to `void` everywhere.
641 The all-void inner struct must not be emitted at all, and an outer struct
642 that references it must comment out that field and exclude it from the
643 generated constructor.
645 uint8 = types.UIntType(
"ui8", 8)
646 uint64 = types.UIntType(
"ui64", 64)
647 void_t = types.VoidType(
"!esi.void")
648 inner = types.StructType(
649 "!hw.struct<a: void, b: void>",
650 [(
"a", void_t), (
"b", void_t)],
652 outer = types.StructType(
653 "!hw.struct<address: ui64, tag: ui8, "
654 "data: !hw.struct<a: void, b: void>>",
655 [(
"address", uint64), (
"tag", uint8), (
"data", inner)],
660 assert "struct _struct_a__esi_void_b__esi_void" not in hdr
662 assert "// void data;" in hdr
664 assert re.search(
r"^\s*void\s+\w+;", hdr, re.M)
is None, hdr
666 outer_ctor = re.search(
667 r"_struct_address_ui64_tag_ui8_data_[^\s(]*\(([^)]*)\) :", hdr)
668 assert outer_ctor, f
"Outer constructor not found in:\n{hdr}"
669 assert "data" not in outer_ctor.group(1)
672 outer_assert = re.search(
673 r"static_assert\(sizeof\(_struct_address_ui64_tag_ui8_data_[^)]+\) "
677 assert outer_assert, f
"Outer size assertion not found in:\n{hdr}"
678 assert outer_assert.group(1) ==
"9", \
679 f
"Expected outer struct size 9, got {outer_assert.group(1)}"
683 """Structs that embed a WindowType field (e.g. DMA transport wrappers like
684 {valid: i8, client_data: <window>}) should not be emitted because the C++
685 window helper is a variable-size multi-frame container whose sizeof cannot
686 match the manifest's compact frame bit-width."""
687 uint8 = types.UIntType(
"ui8", 8)
688 uint16 = types.UIntType(
"ui16", 16)
689 uint32 = types.UIntType(
"ui32", 32)
692 list_t = types.ListType(
"!esi.list<ui32>", uint32)
693 into_struct = types.StructType(
"!hw.struct<data: !esi.list<ui32>>",
695 header_struct = types.StructType(
"!hw.struct<data_count: ui16>",
696 [(
"data_count", uint16)])
697 data_struct = types.StructType(
"!hw.struct<data: ui32>", [(
"data", uint32)])
698 lowered = types.UnionType(
699 "!hw.union<header: !hw.struct<data_count: ui16>, "
700 "data: !hw.struct<data: ui32>>",
701 [(
"header", header_struct), (
"data", data_struct)],
703 window = types.WindowType(
704 '!esi.window<"test_win", !hw.struct<data: !esi.list<ui32>>, '
705 '[<"header", [<"data" countWidth 16>]>, <"data", [<"data", 1>]>]>',
710 types.WindowType.Frame(
"header",
711 [types.WindowType.Field(
"data", 0, 16)]),
712 types.WindowType.Frame(
"data",
713 [types.WindowType.Field(
"data", 1, 0)]),
718 dma_wrapper = types.StructType(
719 "!hw.struct<valid: i8, client_data: !the_window>",
720 [(
"valid", uint8), (
"client_data", window)],
723 uint64 = types.UIntType(
"ui64", 64)
724 outer_wrapper = types.StructType(
725 "!hw.struct<address: ui64, tag: ui8, data: !dma_wrapper>",
726 [(
"address", uint64), (
"tag", uint8), (
"data", dma_wrapper)],
732 assert "esi::SegmentedMessageData" in hdr
735 assert "struct _struct_valid" not in hdr, \
736 "DMA wrapper struct with window field should not be emitted"
737 assert "struct _struct_address" not in hdr, \
738 "Outer struct nesting a window-containing struct should not be emitted"
742 alias = types.TypeAlias(
"!hw.typealias<@dma_wrap>",
"DmaWrap", dma_wrapper)
744 assert "using DmaWrap" not in hdr2, \
745 "Alias of a window-containing struct should not be emitted"
test_windowed_list_arrays_in_header_and_value_type()
test_size_assert_skipped_for_unbounded_struct()
test_windowed_list_struct_element_data_uses_pointer_to_member()
test_union_field_order_preserved()
test_union_with_struct_field()
_window_struct_name(hdr, window_name_suffix)
_generate_header(type_table, system_name="test_ns")
test_size_assert_emitted_for_window_frames()
test_windowed_list_bulk_message_wrapper()
test_union_ordering_among_structs()
test_size_assert_emitted_for_union_and_wrappers()
test_union_planner_naming()
test_nested_struct_with_void_field_size_assert()
test_windowed_list_bitfield_scalar_data_uses_lambda()
test_struct_containing_window_is_skipped()
test_union_with_void_field_commented_out()
test_struct_with_void_field_commented_out()
test_all_void_struct_collapses_to_void()
test_union_same_width_integrals()
test_windowed_list_header_padding_matches_frame_width()
test_size_assert_emitted_for_struct()