summaryrefslogtreecommitdiff
path: root/src/bin/eolian_mono/eolian/mono/struct_definition.hh
diff options
context:
space:
mode:
authorVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-03-25 17:14:32 -0300
committerVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-03-26 16:43:25 -0300
commitb530b871bc003af3413c470f116f8a068bde04a0 (patch)
tree9eae8e2f8e75e1c3defc8fb9efe28011e82c7ebd /src/bin/eolian_mono/eolian/mono/struct_definition.hh
parent762ae45f056e8358e06d4c1843ae83c97691c774 (diff)
eolian_csharp: hide struct native representation inside the managed struct
Summary: Rework the struct binding generator to declare the native struct nested inside the managed one. This way native structs are less likely to cause confusion; for example with an IDE that supports automatic completion. Get rid of struct conversion class methods in favor of using (the already generated) implicit conversion operators. Depends on D8469 Reviewers: segfaultxavi, lauromoura, felipealmeida Reviewed By: lauromoura Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D8470
Diffstat (limited to 'src/bin/eolian_mono/eolian/mono/struct_definition.hh')
-rw-r--r--src/bin/eolian_mono/eolian/mono/struct_definition.hh392
1 files changed, 166 insertions, 226 deletions
diff --git a/src/bin/eolian_mono/eolian/mono/struct_definition.hh b/src/bin/eolian_mono/eolian/mono/struct_definition.hh
index ea379c67ff..35f772554f 100644
--- a/src/bin/eolian_mono/eolian/mono/struct_definition.hh
+++ b/src/bin/eolian_mono/eolian/mono/struct_definition.hh
@@ -21,177 +21,15 @@ inline std::string binding_struct_name(attributes::struct_def const& struct_)
21 return name_helpers::typedecl_managed_name(struct_); 21 return name_helpers::typedecl_managed_name(struct_);
22} 22}
23 23
24inline std::string binding_struct_internal_name(attributes::struct_def const& struct_) 24inline std::string struct_internal_decl_name()
25{ 25{
26 return binding_struct_name(struct_) + "_StructInternal"; 26 return "NativeStruct";
27} 27}
28 28
29struct struct_definition_generator 29inline std::string binding_struct_internal_name(attributes::struct_def const& struct_)
30{
31 template <typename OutputIterator, typename Context>
32 bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const
33 {
34 EINA_CXX_DOM_LOG_DBG(eolian_mono::domain) << "struct_definition_generator: " << struct_.cxx_name << std::endl;
35 auto const& indent = current_indentation(context);
36 if(!as_generator(documentation).generate(sink, struct_, context))
37 return false;
38 if(!as_generator
39 (
40 indent << "[StructLayout(LayoutKind.Sequential)]\n"
41 << indent << "public struct " << string << "\n"
42 << indent << "{\n"
43 )
44 .generate(sink, binding_struct_name(struct_), context))
45 return false;
46
47 // iterate struct fields
48 for (auto const& field : struct_.fields)
49 {
50 auto field_name = field.name;
51 field_name[0] = std::toupper(field_name[0]); // Hack to allow 'static' as a field name
52 if (!as_generator
53 (
54 indent << scope_tab << documentation
55 << indent << scope_tab << "public " << type << " " << string << ";\n"
56 )
57 .generate(sink, std::make_tuple(field, field.type, name_helpers::to_field_name(field.name)), context))
58 return false;
59 }
60
61 auto struct_name = binding_struct_name(struct_);
62
63 // Check whether this is an extern struct without declared fields in .eo file and generate a
64 // placeholder field if positive.
65 // Mono's JIT is picky when generating function pointer for delegates with empty structs, leading to
66 // those 'mini-amd64.c condition fields not met' crashes.
67 if (struct_.fields.size() == 0)
68 {
69 if (!as_generator(indent << scope_tab << "///<summary>Placeholder field</summary>\n"
70 << indent << scope_tab << "public IntPtr field;\n").generate(sink, nullptr, context))
71 return false;
72 }
73 else
74 {
75 // Constructor with default parameters for easy struct initialization
76 if(!as_generator(
77 indent << scope_tab << "///<summary>Constructor for " << string << ".</summary>\n"
78 << indent << scope_tab << "public " << string << "(\n"
79 << ((indent << scope_tab << scope_tab << field_argument_default) % ",\n")
80 << indent << scope_tab << ")\n"
81 << indent << scope_tab << "{\n"
82 << *(indent << scope_tab << scope_tab << field_argument_assignment << ";\n")
83 << indent << scope_tab << "}\n\n")
84 .generate(sink, std::make_tuple(struct_name, struct_name, struct_.fields, struct_.fields), context))
85 return false;
86 }
87
88 if(!as_generator(
89 indent << scope_tab << "public static implicit operator " << struct_name << "(IntPtr ptr)\n"
90 << indent << scope_tab << "{\n"
91 << indent << scope_tab << scope_tab << "var tmp = (" << struct_name << "_StructInternal)Marshal.PtrToStructure(ptr, typeof(" << struct_name << "_StructInternal));\n"
92 << indent << scope_tab << scope_tab << "return " << struct_name << "_StructConversion.ToManaged(tmp);\n"
93 << indent << scope_tab << "}\n\n"
94 ).generate(sink, attributes::unused, context))
95 return false;
96
97
98 if(!as_generator(indent << "}\n\n").generate(sink, attributes::unused, context)) return false;
99
100 return true;
101 }
102} const struct_definition {};
103
104
105struct struct_internal_definition_generator
106{ 30{
107 template <typename OutputIterator, typename Context> 31 return binding_struct_name(struct_) + "." + struct_internal_decl_name();
108 bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const 32}
109 {
110 auto const& indent = current_indentation(context);
111 if (!as_generator
112 (
113 indent << "///<summary>Internal wrapper for struct " << string << ".</summary>\n"
114 << indent << "[StructLayout(LayoutKind.Sequential)]\n"
115 << indent << "public struct " << string << "\n"
116 << indent << "{\n"
117 )
118 .generate(sink, std::make_tuple<>(binding_struct_name(struct_), binding_struct_internal_name(struct_)), context))
119 return false;
120
121 // iterate struct fields
122 for (auto const& field : struct_.fields)
123 {
124 auto field_name = name_helpers::to_field_name(field.name);
125 auto klass = efl::eina::get<attributes::klass_name>(&field.type.original_type);
126 auto regular = efl::eina::get<attributes::regular_type_def>(&field.type.original_type);
127
128 if (klass
129 || (regular && (regular->base_type == "string"
130 || regular->base_type == "mstring"
131 || regular->base_type == "stringshare"
132 || regular->base_type == "any_value_ptr")))
133 {
134 if (!as_generator(indent << scope_tab << "///<summary>Internal wrapper for field " << field_name << "</summary>\n"
135 << indent << scope_tab << "public System.IntPtr " << field_name << ";\n")
136 .generate(sink, nullptr, context))
137 return false;
138 }
139 else if (regular && !(regular->base_qualifier & efl::eolian::grammar::attributes::qualifier_info::is_ref)
140 && regular->base_type == "bool")
141 {
142 if (!as_generator(indent << scope_tab << "///<summary>Internal wrapper for field " << field_name << "</summary>\n"
143 << indent << scope_tab << "public System.Byte " << field_name << ";\n")
144 .generate(sink, nullptr, context))
145 return false;
146 }
147 else if (regular && !(regular->base_qualifier & efl::eolian::grammar::attributes::qualifier_info::is_ref)
148 && regular->base_type == "char")
149 {
150 if (!as_generator(indent << scope_tab << "///<summary>Internal wrapper for field " << field_name << "</summary>\n"
151 << indent << scope_tab << "public System.Byte " << field_name << ";\n")
152 .generate(sink, nullptr, context))
153 return false;
154 }
155 else if (!as_generator(indent << scope_tab << eolian_mono::marshall_annotation(false) << "\n"
156 << indent << scope_tab << "public " << eolian_mono::marshall_type(false) << " " << string << ";\n")
157 .generate(sink, std::make_tuple(field.type, field.type, field_name), context))
158 return false;
159 }
160
161 // Check whether this is an extern struct without declared fields in .eo file and generate a
162 // placeholder field if positive.
163 // Mono's JIT is picky when generating function pointer for delegates with empty structs, leading to
164 // those 'mini-amd64.c condition fields not met' crashes.
165 if (struct_.fields.size() == 0)
166 {
167 if (!as_generator(indent << scope_tab << "internal IntPtr field;\n").generate(sink, nullptr, context))
168 return false;
169 }
170
171 auto external_name = binding_struct_name(struct_);
172 auto internal_name = binding_struct_internal_name(struct_);
173
174 if(!as_generator(
175 indent << scope_tab << "///<summary>Implicit conversion to the internal/marshalling representation.</summary>\n"
176 << indent << scope_tab << "public static implicit operator " << string << "(" << string << " struct_)\n"
177 << indent << scope_tab << "{\n"
178 << indent << scope_tab << scope_tab << "return " << string << "_StructConversion.ToManaged(struct_);\n"
179 << indent << scope_tab << "}\n\n"
180 << indent << scope_tab << "///<summary>Implicit conversion to the managed representation.</summary>\n"
181 << indent << scope_tab << "public static implicit operator " << string << "(" << string << " struct_)\n"
182 << indent << scope_tab << "{\n"
183 << indent << scope_tab << scope_tab << "return " << string << "_StructConversion.ToInternal(struct_);\n"
184 << indent << scope_tab << "}\n\n"
185 ).generate(sink, std::make_tuple(external_name, internal_name, external_name,
186 internal_name, external_name, external_name), context))
187 return false;
188
189 if(!as_generator(indent << "}\n\n").generate(sink, attributes::unused, context)) return false;
190
191 return true;
192 }
193} const struct_internal_definition {};
194
195 33
196// Conversors generation // 34// Conversors generation //
197 35
@@ -236,8 +74,8 @@ struct to_internal_field_convert_generator
236 else if (helpers::need_struct_conversion(regular)) 74 else if (helpers::need_struct_conversion(regular))
237 { 75 {
238 if (!as_generator( 76 if (!as_generator(
239 indent << scope_tab << scope_tab << "_internal_struct." << string << " = " << type << "_StructConversion.ToInternal(_external_struct." << string << ");\n") 77 indent << scope_tab << scope_tab << "_internal_struct." << string << " = _external_struct." << string << ";\n")
240 .generate(sink, std::make_tuple(field_name, field.type, field_name), context)) 78 .generate(sink, std::make_tuple(field_name, field_name), context))
241 return false; 79 return false;
242 } 80 }
243 else if (regular && (regular->base_type == "string" || regular->base_type == "mstring")) 81 else if (regular && (regular->base_type == "string" || regular->base_type == "mstring"))
@@ -361,8 +199,8 @@ struct to_external_field_convert_generator
361 else if (helpers::need_struct_conversion(regular)) 199 else if (helpers::need_struct_conversion(regular))
362 { 200 {
363 if (!as_generator( 201 if (!as_generator(
364 indent << scope_tab << scope_tab << "_external_struct." << string << " = " << type << "_StructConversion.ToManaged(_internal_struct." << string << ");\n") 202 indent << scope_tab << scope_tab << "_external_struct." << string << " = _internal_struct." << string << ";\n")
365 .generate(sink, std::make_tuple(field_name, field.type, field_name), context)) 203 .generate(sink, std::make_tuple(field_name, field_name), context))
366 return false; 204 return false;
367 } 205 }
368 else if (regular && (regular->base_type == "string" || regular->base_type == "mstring" || regular->base_type == "stringshare")) 206 else if (regular && (regular->base_type == "string" || regular->base_type == "mstring" || regular->base_type == "stringshare"))
@@ -421,34 +259,84 @@ struct to_external_field_convert_generator
421 } 259 }
422} const to_external_field_convert {}; 260} const to_external_field_convert {};
423 261
424struct struct_binding_conversion_functions_generator 262// Internal Struct //
263
264struct struct_internal_definition_generator
425{ 265{
426 template <typename OutputIterator, typename Context> 266 template <typename OutputIterator, typename Context>
427 bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const 267 bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const
428 { 268 {
429 auto const& indent = current_indentation(context); 269 auto const& indent = current_indentation(context);
430
431 // Open conversion class
432 if (!as_generator 270 if (!as_generator
433 ( 271 (
434 indent << "/// <summary>Conversion class for struct " << name_helpers::typedecl_managed_name(struct_) << "</summary>\n" 272 indent << "///<summary>Internal wrapper for struct " << string << ".</summary>\n"
435 << indent << "public static class " << name_helpers::typedecl_managed_name(struct_) << "_StructConversion\n" 273 << indent << "[StructLayout(LayoutKind.Sequential)]\n"
274 << indent << "public struct " << string << "\n"
436 << indent << "{\n" 275 << indent << "{\n"
437 ) 276 )
438 .generate(sink, nullptr, context)) 277 .generate(sink, std::make_tuple<>(binding_struct_name(struct_), struct_internal_decl_name()), context))
439 return false; 278 return false;
440 279
280 // iterate struct fields
281 for (auto const& field : struct_.fields)
282 {
283 auto field_name = name_helpers::to_field_name(field.name);
284 auto klass = efl::eina::get<attributes::klass_name>(&field.type.original_type);
285 auto regular = efl::eina::get<attributes::regular_type_def>(&field.type.original_type);
286
287 if (klass
288 || (regular && (regular->base_type == "string"
289 || regular->base_type == "mstring"
290 || regular->base_type == "stringshare"
291 || regular->base_type == "any_value_ptr")))
292 {
293 if (!as_generator(indent << scope_tab << "///<summary>Internal wrapper for field " << field_name << "</summary>\n"
294 << indent << scope_tab << "public System.IntPtr " << field_name << ";\n")
295 .generate(sink, nullptr, context))
296 return false;
297 }
298 else if (regular && !(regular->base_qualifier & efl::eolian::grammar::attributes::qualifier_info::is_ref)
299 && regular->base_type == "bool")
300 {
301 if (!as_generator(indent << scope_tab << "///<summary>Internal wrapper for field " << field_name << "</summary>\n"
302 << indent << scope_tab << "public System.Byte " << field_name << ";\n")
303 .generate(sink, nullptr, context))
304 return false;
305 }
306 else if (regular && !(regular->base_qualifier & efl::eolian::grammar::attributes::qualifier_info::is_ref)
307 && regular->base_type == "char")
308 {
309 if (!as_generator(indent << scope_tab << "///<summary>Internal wrapper for field " << field_name << "</summary>\n"
310 << indent << scope_tab << "public System.Byte " << field_name << ";\n")
311 .generate(sink, nullptr, context))
312 return false;
313 }
314 else if (!as_generator(indent << scope_tab << eolian_mono::marshall_annotation(false) << "\n"
315 << indent << scope_tab << "public " << eolian_mono::marshall_type(false) << " " << string << ";\n")
316 .generate(sink, std::make_tuple(field.type, field.type, field_name), context))
317 return false;
318 }
319
320 // Check whether this is an extern struct without declared fields in .eo file and generate a
321 // placeholder field if positive.
322 // Mono's JIT is picky when generating function pointer for delegates with empty structs, leading to
323 // those 'mini-amd64.c condition fields not met' crashes.
324 if (struct_.fields.size() == 0)
325 {
326 if (!as_generator(indent << scope_tab << "internal IntPtr field;\n").generate(sink, nullptr, context))
327 return false;
328 }
329
330 auto external_name = binding_struct_name(struct_);
331 auto internal_name = binding_struct_internal_name(struct_);
332
441 // to internal 333 // to internal
442 if (!as_generator 334 if (!as_generator(
443 ( 335 indent << scope_tab << "///<summary>Implicit conversion to the internal/marshalling representation.</summary>\n"
444 indent << scope_tab << "internal static " << string << " ToInternal(" << string << " _external_struct)\n" 336 << indent << scope_tab << "public static implicit operator " << string << "(" << string << " _external_struct)\n"
445 << indent << scope_tab << "{\n" 337 << indent << scope_tab << "{\n"
446 << indent << scope_tab << scope_tab << "var _internal_struct = new " << string << "();\n" 338 << indent << scope_tab << scope_tab << "var _internal_struct = new " << string << "();\n"
447 ) 339 ).generate(sink, std::make_tuple(internal_name, external_name, internal_name), context))
448 .generate(sink, std::make_tuple(binding_struct_internal_name(struct_)
449 , binding_struct_name(struct_)
450 , binding_struct_internal_name(struct_)
451 ), context))
452 return false; 340 return false;
453 341
454 for (auto const& field : struct_.fields) 342 for (auto const& field : struct_.fields)
@@ -457,25 +345,17 @@ struct struct_binding_conversion_functions_generator
457 return false; 345 return false;
458 } 346 }
459 347
460 if (!as_generator 348 if (!as_generator(indent << scope_tab << scope_tab << "return _internal_struct;\n"
461 ( 349 << indent << scope_tab << "}\n\n").generate(sink, nullptr, context))
462 indent << scope_tab << scope_tab << "return _internal_struct;\n"
463 << indent << scope_tab << "}\n\n"
464 )
465 .generate(sink, attributes::unused, context))
466 return false; 350 return false;
467 351
468 // to external 352 // to managed
469 if (!as_generator 353 if (!as_generator(
470 ( 354 indent << scope_tab << "///<summary>Implicit conversion to the managed representation.</summary>\n"
471 indent << scope_tab << "internal static " << string << " ToManaged(" << string << " _internal_struct)\n" 355 << indent << scope_tab << "public static implicit operator " << string << "(" << string << " _internal_struct)\n"
472 << indent << scope_tab << "{\n" 356 << indent << scope_tab << "{\n"
473 << indent << scope_tab << scope_tab << "var _external_struct = new " << string << "();\n" 357 << indent << scope_tab << scope_tab << "var _external_struct = new " << string << "();\n"
474 ) 358 ).generate(sink, std::make_tuple(external_name, internal_name, external_name), context))
475 .generate(sink, std::make_tuple(binding_struct_name(struct_)
476 , binding_struct_internal_name(struct_)
477 , binding_struct_name(struct_)
478 ), context))
479 return false; 359 return false;
480 360
481 for (auto const& field : struct_.fields) 361 for (auto const& field : struct_.fields)
@@ -484,21 +364,95 @@ struct struct_binding_conversion_functions_generator
484 return false; 364 return false;
485 } 365 }
486 366
487 if (!as_generator 367 if (!as_generator(indent << scope_tab << scope_tab << "return _external_struct;\n"
488 ( 368 << indent << scope_tab << "}\n\n").generate(sink, nullptr, context))
489 indent << scope_tab << scope_tab << "return _external_struct;\n" 369 return false;
490 << indent << scope_tab << "}\n\n" 370
371 // close internal class
372 if(!as_generator(indent << "}\n\n").generate(sink, attributes::unused, context)) return false;
373
374 return true;
375 }
376} const struct_internal_definition {};
377
378// Managed Struct //
379
380struct struct_definition_generator
381{
382 template <typename OutputIterator, typename Context>
383 bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const
384 {
385 EINA_CXX_DOM_LOG_DBG(eolian_mono::domain) << "struct_definition_generator: " << struct_.cxx_name << std::endl;
386 auto const& indent = current_indentation(context);
387 if(!as_generator(documentation).generate(sink, struct_, context))
388 return false;
389 if(!as_generator
390 (
391 indent << "[StructLayout(LayoutKind.Sequential)]\n"
392 << indent << "public struct " << string << "\n"
393 << indent << "{\n"
491 ) 394 )
492 .generate(sink, attributes::unused, context)) 395 .generate(sink, binding_struct_name(struct_), context))
396 return false;
397
398 // iterate struct fields
399 for (auto const& field : struct_.fields)
400 {
401 auto field_name = field.name;
402 field_name[0] = std::toupper(field_name[0]); // Hack to allow 'static' as a field name
403 if (!as_generator
404 (
405 indent << scope_tab << documentation
406 << indent << scope_tab << "public " << type << " " << string << ";\n"
407 )
408 .generate(sink, std::make_tuple(field, field.type, name_helpers::to_field_name(field.name)), context))
409 return false;
410 }
411
412 auto struct_name = binding_struct_name(struct_);
413
414 // Check whether this is an extern struct without declared fields in .eo file and generate a
415 // placeholder field if positive.
416 // Mono's JIT is picky when generating function pointer for delegates with empty structs, leading to
417 // those 'mini-amd64.c condition fields not met' crashes.
418 if (struct_.fields.size() == 0)
419 {
420 if (!as_generator(indent << scope_tab << "///<summary>Placeholder field</summary>\n"
421 << indent << scope_tab << "public IntPtr field;\n").generate(sink, nullptr, context))
422 return false;
423 }
424 else
425 {
426 // Constructor with default parameters for easy struct initialization
427 if(!as_generator(
428 indent << scope_tab << "///<summary>Constructor for " << string << ".</summary>\n"
429 << indent << scope_tab << "public " << string << "(\n"
430 << ((indent << scope_tab << scope_tab << field_argument_default) % ",\n")
431 << indent << scope_tab << ")\n"
432 << indent << scope_tab << "{\n"
433 << *(indent << scope_tab << scope_tab << field_argument_assignment << ";\n")
434 << indent << scope_tab << "}\n\n")
435 .generate(sink, std::make_tuple(struct_name, struct_name, struct_.fields, struct_.fields), context))
436 return false;
437 }
438
439 if(!as_generator(
440 indent << scope_tab << "public static implicit operator " << struct_name << "(IntPtr ptr)\n"
441 << indent << scope_tab << "{\n"
442 << indent << scope_tab << scope_tab << "var tmp = (" << struct_name << ".NativeStruct)Marshal.PtrToStructure(ptr, typeof(" << struct_name << ".NativeStruct));\n"
443 << indent << scope_tab << scope_tab << "return tmp;\n"
444 << indent << scope_tab << "}\n\n"
445 ).generate(sink, attributes::unused, context))
493 return false; 446 return false;
494 447
495 // Close conversion class 448 if (!struct_internal_definition.generate(sink, struct_, change_indentation(indent.inc(), context)))
496 if (!as_generator(indent << "}\n\n").generate(sink, attributes::unused, context))
497 return false; 449 return false;
498 450
451 if(!as_generator(indent << "}\n\n").generate(sink, attributes::unused, context)) return false;
452
499 return true; 453 return true;
500 } 454 }
501} const struct_binding_conversion_functions {}; 455} const struct_definition {};
502 456
503struct struct_entities_generator 457struct struct_entities_generator
504{ 458{
@@ -514,12 +468,6 @@ struct struct_entities_generator
514 if (!struct_definition.generate(sink, struct_, context)) 468 if (!struct_definition.generate(sink, struct_, context))
515 return false; 469 return false;
516 470
517 if (!struct_internal_definition.generate(sink, struct_, context))
518 return false;
519
520 if (!struct_binding_conversion_functions.generate(sink, struct_, context))
521 return false;
522
523 return name_helpers::close_namespaces(sink, struct_.namespaces, context); 471 return name_helpers::close_namespaces(sink, struct_.namespaces, context);
524 472
525 } 473 }
@@ -550,11 +498,6 @@ template <>
550struct is_generator< ::eolian_mono::to_external_field_convert_generator> : std::true_type {}; 498struct is_generator< ::eolian_mono::to_external_field_convert_generator> : std::true_type {};
551 499
552template <> 500template <>
553struct is_eager_generator< ::eolian_mono::struct_binding_conversion_functions_generator> : std::true_type {};
554template <>
555struct is_generator< ::eolian_mono::struct_binding_conversion_functions_generator> : std::true_type {};
556
557template <>
558struct is_eager_generator< ::eolian_mono::struct_entities_generator> : std::true_type {}; 501struct is_eager_generator< ::eolian_mono::struct_entities_generator> : std::true_type {};
559template <> 502template <>
560struct is_generator< ::eolian_mono::struct_entities_generator> : std::true_type {}; 503struct is_generator< ::eolian_mono::struct_entities_generator> : std::true_type {};
@@ -573,9 +516,6 @@ template <>
573struct attributes_needed< ::eolian_mono::to_external_field_convert_generator> : std::integral_constant<int, 1> {}; 516struct attributes_needed< ::eolian_mono::to_external_field_convert_generator> : std::integral_constant<int, 1> {};
574 517
575template <> 518template <>
576struct attributes_needed< ::eolian_mono::struct_binding_conversion_functions_generator> : std::integral_constant<int, 1> {};
577
578template <>
579struct attributes_needed< ::eolian_mono::struct_entities_generator> : std::integral_constant<int, 1> {}; 519struct attributes_needed< ::eolian_mono::struct_entities_generator> : std::integral_constant<int, 1> {};
580} 520}
581 521