1 /*
2 * Copyright 2019 by its authors. See AUTHORS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #ifndef EOLIAN_MONO_STRUCT_DEFINITION_HH
17 #define EOLIAN_MONO_STRUCT_DEFINITION_HH
18
19 #include "grammar/generator.hpp"
20 #include "grammar/klass_def.hpp"
21 #include "grammar/indentation.hpp"
22 #include "grammar/list.hpp"
23 #include "grammar/alternative.hpp"
24 #include "grammar/attribute_reorder.hpp"
25 #include "name_helpers.hh"
26 #include "helpers.hh"
27 #include "type.hh"
28 #include "using_decl.hh"
29 #include "documentation.hh"
30 #include "struct_fields.hh"
31 #include "blacklist.hh"
32 #include "culture_info.hh"
33
34 namespace eolian_mono {
35
binding_struct_name(attributes::struct_def const & struct_)36 inline std::string binding_struct_name(attributes::struct_def const& struct_)
37 {
38 return name_helpers::typedecl_managed_name(struct_);
39 }
40
struct_internal_decl_name()41 inline std::string struct_internal_decl_name()
42 {
43 return "NativeStruct";
44 }
45
binding_struct_internal_name(attributes::struct_def const & struct_)46 inline std::string binding_struct_internal_name(attributes::struct_def const& struct_)
47 {
48 return binding_struct_name(struct_) + "." + struct_internal_decl_name();
49 }
50
51 // Conversors generation //
52
53 struct to_internal_field_convert_generator
54 {
55 template <typename OutputIterator, typename Context>
generateeolian_mono::to_internal_field_convert_generator56 bool generate(OutputIterator sink, attributes::struct_field_def const& field, Context const& context) const
57 {
58 auto const& indent = current_indentation(context);
59 auto field_name = name_helpers::to_field_name(field.name);
60 // FIXME Replace need_struct_conversion(regular) with need_struct_conversion(type)
61 auto regular = efl::eina::get<attributes::regular_type_def>(&field.type.original_type);
62 auto klass = efl::eina::get<attributes::klass_name>(&field.type.original_type);
63 auto complex = efl::eina::get<attributes::complex_type_def>(&field.type.original_type);
64
65 if (klass)
66 {
67 if (!as_generator(
68 indent << scope_tab << scope_tab << "_internal_struct." << string << " = _external_struct." << string << "?.NativeHandle ?? System.IntPtr.Zero;\n")
69 .generate(sink, std::make_tuple(field_name, field_name), context))
70 return false;
71 }
72 else if ((complex && (complex->outer.base_type == "array")))
73 {
74 if (!as_generator(
75 indent << scope_tab << scope_tab << "_internal_struct." << string << " = Efl.Eo.Globals.IListToNativeArray(_external_struct." << string << ", " << (field.type.has_own ? "true" : "false") << ");\n")
76 .generate(sink, std::make_tuple(field_name, field_name), context))
77 return false;
78 }
79 else if ((complex && (complex->outer.base_type == "list")))
80 {
81 if (!as_generator(
82 indent << scope_tab << scope_tab << "_internal_struct." << string << " = Efl.Eo.Globals.IListToNativeList(_external_struct." << string << ", " << (field.type.has_own ? "true" : "false") << ");\n")
83 .generate(sink, std::make_tuple(field_name, field_name), context))
84 return false;
85 }
86 else if ((complex && (complex->outer.base_type == "iterator")))
87 {
88 if (!as_generator(
89 indent << scope_tab << scope_tab << "_internal_struct." << string << " = Efl.Eo.Globals.IEnumerableToIterator(_external_struct." << string << ", " << (field.type.has_own ? "true" : "false") << ");\n")
90 .generate(sink, std::make_tuple(field_name, field_name), context))
91 return false;
92 }
93 else if ((complex && (complex->outer.base_type == "accessor")))
94 {
95 if (!as_generator(
96 indent << scope_tab << scope_tab << "_internal_struct." << string << " = Efl.Eo.Globals.IEnumerableToAccessor(_external_struct." << string << ", " << (field.type.has_own ? "true" : "false") << ");\n")
97 .generate(sink, std::make_tuple(field_name, field_name), context))
98 return false;
99 }
100 else if ((complex && (complex->outer.base_type == "hash"))
101 || field.type.c_type == "Eina_Binbuf *" || field.type.c_type == "const Eina_Binbuf *")
102 {
103 // Always assumes pointer
104 if (!as_generator(
105 indent << scope_tab << scope_tab << "_internal_struct." << string << " = _external_struct." << string << ".Handle;\n")
106 .generate(sink, std::make_tuple(field_name, field_name), context))
107 return false;
108 }
109 else if (field.type.is_ptr && helpers::need_pointer_conversion(regular) && !helpers::need_struct_conversion(regular))
110 {
111 if (!as_generator(
112 indent << scope_tab << scope_tab << "_internal_struct." << string << " = Eina.PrimitiveConversion.ManagedToPointerAlloc(_external_struct." << string << ");\n")
113 .generate(sink, std::make_tuple(field_name, field_name), context))
114 return false;
115 }
116 else if (helpers::need_struct_conversion(regular))
117 {
118 if (!as_generator(
119 indent << scope_tab << scope_tab << "_internal_struct." << string << " = _external_struct." << string << ";\n")
120 .generate(sink, std::make_tuple(field_name, field_name), context))
121 return false;
122 }
123 else if (regular && (regular->base_type == "string" || regular->base_type == "mstring"))
124 {
125 if (!as_generator(
126 indent << scope_tab << scope_tab << "_internal_struct." << string << " = Eina.MemoryNative.StrDup(_external_struct." << string << ");\n")
127 .generate(sink, std::make_tuple(field_name, field_name), context))
128 return false;
129 }
130 else if (regular && regular->base_type == "stringshare")
131 {
132 if (!as_generator(
133 indent << scope_tab << scope_tab << "_internal_struct." << string << " = Eina.MemoryNative.AddStringshare(_external_struct." << string << ");\n")
134 .generate(sink, std::make_tuple(field_name, field_name), context))
135 return false;
136 }
137 else if (field.type.c_type == "Eina_Slice" || field.type.c_type == "const Eina_Slice"
138 || field.type.c_type == "Eina_Rw_Slice" || field.type.c_type == "const Eina_Rw_Slice")
139 {
140 if (!as_generator(
141 "\n" <<
142 indent << scope_tab << scope_tab << "_internal_struct." << field_name << ".Len = _external_struct." << field_name << ".Len;\n" <<
143 indent << scope_tab << scope_tab << "_internal_struct." << field_name << ".Mem = _external_struct." << field_name << ".Mem;\n")
144 .generate(sink, attributes::unused, context))
145 return false;
146 }
147 else if (field.type.c_type == "Eina_Value" || field.type.c_type == "const Eina_Value")
148 {
149 if (!as_generator(
150 indent << scope_tab << scope_tab << "_internal_struct." << string << " = _external_struct." << string << ".GetNative();\n"
151 ).generate(sink, std::make_tuple(field_name, field_name), context))
152 return false;
153 }
154 else if (field.type.c_type == "Eina_Value *" || field.type.c_type == "const Eina_Value *")
155 {
156 if (!as_generator(
157 indent << scope_tab << scope_tab << "_internal_struct." << string << " = _external_struct." << string << "?.NativeHandle ?? System.IntPtr.Zero;\n"
158 ).generate(sink, std::make_tuple(field_name, field_name), context))
159 return false;
160 }
161 else if (!field.type.is_ptr && regular && regular->base_type == "bool")
162 {
163 if (!as_generator(
164 indent << scope_tab << scope_tab << "_internal_struct." << string << " = _external_struct." << string << " ? (byte)1 : (byte)0;\n")
165 .generate(sink, std::make_tuple(field_name, field_name), context))
166 return false;
167 }
168 else if (!field.type.is_ptr && regular && regular->base_type == "char")
169 {
170 if (!as_generator(
171 indent << scope_tab << scope_tab << "_internal_struct." << string << " = (byte)_external_struct." << string << ";\n")
172 .generate(sink, std::make_tuple(field_name, field_name), context))
173 return false;
174 }
175 else // primitives and enums
176 {
177 if (!as_generator(
178 indent << scope_tab << scope_tab << "_internal_struct." << string << " = _external_struct." << string << ";\n")
179 .generate(sink, std::make_tuple(field_name, field_name), context))
180 return false;
181 }
182
183 return true;
184 }
185 } const to_internal_field_convert {};
186
187 struct to_external_field_convert_generator
188 {
189 template <typename OutputIterator, typename Context>
generateeolian_mono::to_external_field_convert_generator190 bool generate(OutputIterator sink, attributes::struct_field_def const& field, Context const& context) const
191 {
192 auto field_name = name_helpers::to_field_name(field.name);
193 auto regular = efl::eina::get<attributes::regular_type_def>(&field.type.original_type);
194 auto klass = efl::eina::get<attributes::klass_name>(&field.type.original_type);
195 auto complex = efl::eina::get<attributes::complex_type_def>(&field.type.original_type);
196
197 if (klass)
198 {
199 auto interface_name = name_helpers::klass_full_interface_name(*klass);
200 if (!as_generator(
201 "(" << interface_name << ") Efl.Eo.Globals.CreateWrapperFor(" << string << ");"
202 ).generate(sink, std::make_tuple(field_name, field_name), context))
203 return false;
204 }
205 else if (field.type.c_type == "Eina_Binbuf *" || field.type.c_type == "const Eina_Binbuf *")
206 {
207 if (!as_generator(
208 "new " << type << "(" << string << ", false);")
209 .generate(sink, std::make_tuple(field.type, field_name), context))
210 return false;
211 }
212 else if (complex && (complex->outer.base_type == "array"))
213 {
214 // Always assumes pointer
215 if (!as_generator(
216 "Efl.Eo.Globals.NativeArrayTo" << type << "(" << string << ");")
217 .generate(sink, std::make_tuple(field.type, field_name), context))
218 return false;
219 }
220 else if (complex && (complex->outer.base_type == "list"))
221 {
222 // Always assumes pointer
223 if (!as_generator(
224 "Efl.Eo.Globals.NativeListTo" << type << "(" << string << ");")
225 .generate(sink, std::make_tuple(field.type, field_name), context))
226 return false;
227 }
228 else if (complex && complex->outer.base_type == "hash")
229 {
230 if (!as_generator(
231 "new " << type << "(" << string << ", false, false, false);")
232 .generate(sink, std::make_tuple(field.type, field_name), context))
233 return false;
234 }
235 else if (complex && complex->outer.base_type == "iterator")
236 {
237 if (!as_generator(
238 "Efl.Eo.Globals.IteratorTo" << type << "(" << string << ");")
239 .generate(sink, std::make_tuple(field.type, field_name), context))
240 return false;
241 }
242 else if (complex && complex->outer.base_type == "accessor")
243 {
244 if (!as_generator(
245 "Efl.Eo.Globals.AccessorTo" << type << "(" << string << ");")
246 .generate(sink, std::make_tuple(field.type, field_name), context))
247 return false;
248 }
249 else if (field.type.is_ptr && helpers::need_pointer_conversion(regular) && !helpers::need_struct_conversion(regular))
250 {
251 if (!as_generator(
252 "Eina.PrimitiveConversion.PointerToManaged<" << type << ">(" << string << ");")
253 .generate(sink, std::make_tuple(field.type, field_name), context))
254 return false;
255 }
256 else if (helpers::need_struct_conversion(regular))
257 {
258 if (!as_generator(
259 string << ";")
260 .generate(sink, field_name, context))
261 return false;
262 }
263 else if (regular && (regular->base_type == "string" || regular->base_type == "mstring" || regular->base_type == "stringshare"))
264 {
265 if (!as_generator(
266 "Eina.StringConversion.NativeUtf8ToManagedString(" << string << ");")
267 .generate(sink, std::make_tuple(field_name, field_name), context))
268 return false;
269 }
270 else if (field.type.c_type == "Eina_Slice" || field.type.c_type == "const Eina_Slice"
271 || field.type.c_type == "Eina_Rw_Slice" || field.type.c_type == "const Eina_Rw_Slice")
272 {
273 if (!as_generator(field_name << ";")
274 .generate(sink, attributes::unused, context))
275 return false;
276 }
277 else if (field.type.c_type == "Eina_Value" || field.type.c_type == "const Eina_Value")
278 {
279 if (!as_generator(
280 "new Eina.Value(" << string << ");"
281 ).generate(sink, std::make_tuple(field_name), context))
282 return false;
283 }
284 else if (field.type.c_type == "Eina_Value *" || field.type.c_type == "const Eina_Value *")
285 {
286 if (!as_generator(
287 "new Eina.Value(" << string << ", Eina.Ownership.Unmanaged);"
288 ).generate(sink, std::make_tuple(field_name), context))
289 return false;
290 }
291 else if (!field.type.is_ptr && regular && regular->base_type == "bool")
292 {
293 if (!as_generator(
294 string << " != 0;"
295 ).generate(sink, std::make_tuple(field_name), context))
296 return false;
297 }
298 else if (!field.type.is_ptr && regular && regular->base_type == "char")
299 {
300 if (!as_generator(
301 "(char)" << string << ";"
302 ).generate(sink, std::make_tuple(field_name), context))
303 return false;
304 }
305 else // primitives and enums
306 {
307 if (!as_generator(
308 field_name << ";"
309 ).generate(sink, attributes::unused, context))
310 return false;
311 }
312 return true;
313 }
314 } const to_external_field_convert {};
315
316 // Internal Struct //
317
318 struct struct_private_property_generator
319 {
320 template <typename OutputIterator, typename Context>
generateeolian_mono::struct_private_property_generator321 bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const
322 {
323 auto const& indent = current_indentation(context);
324
325 // iterate struct fields
326 for (auto const& field : struct_.fields)
327 {
328 auto field_name = name_helpers::to_field_name(field.name);
329 auto klass = efl::eina::get<attributes::klass_name>(&field.type.original_type);
330 auto regular = efl::eina::get<attributes::regular_type_def>(&field.type.original_type);
331
332 if (klass
333 || (regular && (regular->base_type == "string"
334 || regular->base_type == "mstring"
335 || regular->base_type == "stringshare"
336 || regular->base_type == "any_value_ref")))
337 {
338 if (!as_generator(indent << scope_tab << "/// <summary>Internal wrapper for field " << field_name << "</summary>\n"
339 << indent << scope_tab << "private System.IntPtr " << field_name << ";\n")
340 .generate(sink, nullptr, context))
341 return false;
342 }
343 else if (regular && !(regular->base_qualifier & efl::eolian::grammar::attributes::qualifier_info::is_ref)
344 && regular->base_type == "bool")
345 {
346 if (!as_generator(indent << scope_tab << "/// <summary>Internal wrapper for field " << field_name << "</summary>\n"
347 << indent << scope_tab << "private System.Byte " << field_name << ";\n")
348 .generate(sink, nullptr, context))
349 return false;
350 }
351 else if (regular && !(regular->base_qualifier & efl::eolian::grammar::attributes::qualifier_info::is_ref)
352 && regular->base_type == "char")
353 {
354 if (!as_generator(indent << scope_tab << "/// <summary>Internal wrapper for field " << field_name << "</summary>\n"
355 << indent << scope_tab << "private System.Byte " << field_name << ";\n")
356 .generate(sink, nullptr, context))
357 return false;
358 }
359 else if (!as_generator(indent << scope_tab << eolian_mono::marshall_annotation(false) << "\n"
360 << indent << scope_tab << "private " << eolian_mono::marshall_type(false) << " " << string << ";\n")
361 .generate(sink, std::make_tuple(field.type, field.type, field_name), context))
362 return false;
363 }
364
365 // Check whether this is an extern struct without declared fields in .eo file and generate a
366 // placeholder field if positive.
367 // Mono's JIT is picky when generating function pointer for delegates with empty structs, leading to
368 // those 'mini-amd64.c condition fields not met' crashes.
369 if (struct_.fields.size() == 0)
370 {
371 if (!as_generator(indent << scope_tab << "/// <summary>Placeholder field</summary>\n"
372 << indent << scope_tab << "private IntPtr field;\n").generate(sink, nullptr, context))
373 return false;
374 }
375
376 if(!as_generator("\n")
377 .generate(sink, attributes::unused, context))
378 return false;
379
380 return true;
381 }
382 } const struct_private_property {};
383
384 // Managed Struct //
385
386 struct struct_definition_generator
387 {
388 /**
389 * Generates an implicit operator for packing only if the struct has more
390 * than one attribute. Then operator will receive a tuple with the same of
391 * each attribute's type in the same order they were declared.
392 *
393 * Remarks: due to the MCS compiler's limitations, no operator is generated
394 * for structs with more than 4 fields.
395 */
396 template <typename OutputIterator, typename Context>
generate_implicit_operatoreolian_mono::struct_definition_generator397 bool generate_implicit_operator(attributes::struct_def const& struct_
398 , OutputIterator sink
399 , Context const& context) const
400 {
401 if (struct_.fields.size() <= 1 || struct_.fields.size() > 4)
402 return true;
403
404 auto struct_name = binding_struct_name(struct_);
405 auto const& indent = current_indentation(context).inc();
406
407 if (!as_generator(
408 indent << scope_tab << "/// <summary>Packs tuple into " << struct_name << " object.\n"
409 << indent << scope_tab << "///<para>Since EFL 1.24.</para>\n"
410 << indent << scope_tab << "///</summary>\n"
411 ).generate(sink, attributes::unused, context))
412 return false;
413
414 if (!as_generator(
415 indent << scope_tab << "public static implicit operator " << struct_name << "(("
416 << (field_argument_decl % ", ")
417 << ") tuple)\n"
418 ).generate(sink, struct_.fields, context))
419 return false;
420
421 // object constructor
422 if (!as_generator(
423 indent << scope_tab << scope_tab << "=> new " << struct_name << "("
424 ).generate(sink, attributes::unused, context))
425 return false;
426
427 if (!as_generator(
428 (("tuple." << struct_field_name) % ", ")
429 << ");\n\n"
430 ).generate(sink, struct_.fields, context))
431 return false;
432
433 return true;
434 }
435
436 template <typename OutputIterator, typename Context>
generate_deconstruct_methodeolian_mono::struct_definition_generator437 bool generate_deconstruct_method(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const
438 {
439 auto const& indent = current_indentation(context).inc();
440 auto struct_name = binding_struct_name(struct_);
441
442 if (!as_generator(
443 indent << scope_tab << "/// <summary>Unpacks " << struct_name << " into tuple.\n"
444 << indent << scope_tab << "/// <para>Since EFL 1.24.</para>\n"
445 << indent << scope_tab << "/// </summary>\n"
446 << indent << scope_tab << "public void Deconstruct(\n"
447 ).generate(sink, attributes::unused, context))
448 return false;
449
450 // parameters
451 {
452 auto i = 0u;
453 for (auto const& field : struct_.fields)
454 {
455 auto field_name = name_helpers::to_field_name(field.name);
456
457 auto suffix = i == struct_.fields.size() - 1 ? "\n" : ",\n";
458
459 if (!as_generator(
460 indent << scope_tab << scope_tab << "out " << type << " " << field_name << suffix
461 ).generate(sink, std::make_tuple(field.type), context))
462 return false;
463
464 ++i;
465 }
466 }
467
468 if (!as_generator(
469 indent << scope_tab << ")\n"
470 << indent << scope_tab << "{\n"
471 ).generate(sink, attributes::unused, context))
472 return false;
473
474 // assigments
475 for (auto const& field : struct_.fields)
476 {
477 auto field_name = name_helpers::managed_name(field.name);
478 auto param_name = name_helpers::to_field_name(field.name);
479
480 if (!as_generator(
481 indent << scope_tab << scope_tab << param_name << " = this." << field_name << ";\n"
482 ).generate(sink, attributes::unused, context))
483 return false;
484 }
485
486 // the end
487 return as_generator(
488 indent << scope_tab << "}\n"
489 ).generate(sink, attributes::unused, context);
490 }
491
492 template <typename OutputIterator, typename Context>
generateeolian_mono::struct_definition_generator493 bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const
494 {
495 EINA_CXX_DOM_LOG_DBG(eolian_mono::domain) << "struct_definition_generator: " << struct_.cxx_name << std::endl;
496 auto const& indent = current_indentation(context).inc();
497 if(!as_generator(documentation(1)).generate(sink, struct_, context))
498 return false;
499 auto struct_managed_name = binding_struct_name(struct_);
500 if(!as_generator
501 (
502 indent << "[StructLayout(LayoutKind.Sequential)]\n"
503 << indent << "[Efl.Eo.BindingEntity]\n"
504 << indent << "[SuppressMessage(\"Microsoft.Naming\", \"CA1724:TypeNamesShouldNotMatchNamespaces\")]\n"
505 << indent << "public struct " << struct_managed_name << " : IEquatable<" << struct_managed_name << ">\n"
506 << indent << "{\n"
507 )
508 .generate(sink, attributes::unused, context))
509 return false;
510
511 if (!struct_private_property.generate(sink, struct_, change_indentation(indent, context)))
512 return false;
513
514 // iterate struct fields
515 for (auto const& field : struct_.fields)
516 {
517 auto docs = documentation(indent.n + 1);
518 if (!as_generator(docs).generate(sink, field, context))
519 return false;
520
521 if (!field.type.doc_summary.empty())
522 {
523 if (!docs.generate_tag_value(sink, field.type.doc_summary, context))
524 return false;
525 }
526
527 if (!as_generator(indent << scope_tab << "public " << type << " " << name_helpers::managed_name(field.name) << " { get => " << to_external_field_convert << " }\n").generate(sink, std::make_tuple(field.type, field), context))
528 return false;
529 }
530
531 auto struct_name = binding_struct_name(struct_);
532
533 if (struct_.fields.size() != 0)
534 {
535 // Constructor with default parameters for easy struct initialization
536 if(!as_generator(
537 indent << scope_tab << "/// <summary>Constructor for " << string << ".\n"
538 ).generate(sink, struct_name, context))
539 return false;
540
541 if (!struct_.documentation.since.empty())
542 if (!as_generator(indent << scope_tab << "/// <para>Since EFL " + struct_.documentation.since + ".</para>\n"
543 ).generate(sink, attributes::unused, context))
544 return false;
545
546 if (!as_generator(
547 indent << scope_tab << "/// </summary>\n"
548 << *(indent << scope_tab << field_argument_docs << "\n")
549 << indent << scope_tab << "public " << string << "(\n"
550 << ((indent << scope_tab << scope_tab << field_argument_default) % ",\n")
551 << ")\n"
552 << indent << scope_tab << "{\n"
553 << *(indent << scope_tab << scope_tab << field_argument_assignment)
554 << indent << scope_tab << "}\n\n")
555 .generate(sink, std::make_tuple(struct_.fields, struct_name, struct_.fields, struct_.fields), context))
556 return false;
557
558 if (!generate_implicit_operator(struct_, sink, context))
559 return false;
560
561 if (!generate_deconstruct_method(sink, struct_, context))
562 return false;
563 }
564
565 std::string since_line;
566 if (!struct_.documentation.since.empty())
567 if (!as_generator(indent << scope_tab << "/// <para>Since EFL " + struct_.documentation.since + ".</para>\n"
568 ).generate(std::back_inserter(since_line), attributes::unused, context))
569 return false;
570
571 // GetHashCode (needed by the equality comparisons)
572 if (!as_generator(
573 indent << scope_tab << "/// <summary>Get a hash code for this item.\n"
574 << since_line
575 << indent << scope_tab << "/// </summary>\n"
576 << indent << scope_tab << "public override int GetHashCode()\n"
577 << indent << scope_tab << "{\n"
578 ).generate(sink, attributes::unused, context))
579 return false;
580
581 if (struct_.fields.size() == 1 )
582 {
583 if (!as_generator(
584 indent << scope_tab << scope_tab << "return " << name_helpers::managed_name(struct_.fields[0].name) << ".GetHashCode();\n"
585 ).generate(sink, attributes::unused, context))
586 return false;
587 }
588 else if (struct_.fields.size() != 0 )
589 {
590 // int hash = 17;
591 // hash = 23 * fieldA.GetHashCode();
592 // hash = 23 * fieldB.GetHashCode();
593 // hash = 23 * fieldC.GetHashCode();
594 // return hash
595 if (!as_generator(
596 indent << scope_tab << scope_tab << "int hash = 17;\n"
597 << *(grammar::attribute_reorder<-1, -1>(indent << scope_tab << scope_tab << "hash = hash * 23 + " << name_helpers::struct_property_name << ".GetHashCode(" << culture_info << ");\n"))
598 << indent << scope_tab << scope_tab << "return hash;\n"
599 ).generate(sink, struct_.fields, context))
600 return false;
601 }
602 else
603 {
604 // Just compare the place holder pointers
605 if (!as_generator(
606 indent << scope_tab << scope_tab << "return field.GetHashCode();\n"
607 ).generate(sink, attributes::unused, context))
608 return false;
609 }
610
611 if (!as_generator(
612 indent << scope_tab << "}\n"
613 ).generate(sink, attributes::unused, context))
614 return false;
615
616 // IEquatable<T> Equals
617 if (!as_generator(
618 indent << scope_tab << "/// <summary>Equality comparison.\n"
619 << since_line
620 << indent << scope_tab << "/// </summary>\n"
621 << indent << scope_tab << "public bool Equals(" << struct_managed_name << " other)\n"
622 << indent << scope_tab << "{\n"
623 << indent << scope_tab << scope_tab << "return "
624 ).generate(sink, attributes::unused, context))
625 return false;
626
627 if (struct_.fields.size() != 0 )
628 {
629 if (!as_generator(
630 grammar::attribute_reorder<-1, -1>((name_helpers::struct_property_name << " == other." << name_helpers::struct_property_name)) % " && "
631 ).generate(sink, struct_.fields, context))
632 return false;
633 }
634 else
635 {
636 // Just compare the place holder pointers
637 if (!as_generator(
638 "field.Equals(other.field)"
639 ).generate(sink, attributes::unused, context))
640 return false;
641 }
642
643
644 if (!as_generator(
645 ";\n"
646 << indent << scope_tab << "}\n"
647 ).generate(sink, attributes::unused, context))
648 return false;
649
650 // ValueType.Equals
651 if (!as_generator(
652 indent << scope_tab << "/// <summary>Equality comparison.\n"
653 << since_line
654 << indent << scope_tab << "/// </summary>\n"
655 << indent << scope_tab << "public override bool Equals(object other)\n"
656 << indent << scope_tab << scope_tab << "=> ((other is " << struct_managed_name << ") ? Equals((" << struct_managed_name << ")other) : false);\n"
657 ).generate(sink, attributes::unused, context))
658 return false;
659
660 // Equality operators
661 if (!as_generator(
662 indent << scope_tab << "/// <summary>Equality comparison.\n"
663 << since_line
664 << indent << scope_tab << "/// </summary>\n"
665 << indent << scope_tab << "public static bool operator ==(" << struct_managed_name << " lhs, " << struct_managed_name << " rhs)\n"
666 << indent << scope_tab << scope_tab << "=> lhs.Equals(rhs);"
667 ).generate(sink, attributes::unused, context))
668 return false;
669
670 if (!as_generator(
671 indent << scope_tab << "/// <summary>Equality comparison.\n"
672 << since_line
673 << indent << scope_tab << "/// </summary>\n"
674 << indent << scope_tab << "public static bool operator !=(" << struct_managed_name << " lhs, " << struct_managed_name << " rhs)\n"
675 << indent << scope_tab << scope_tab << "=> !lhs.Equals(rhs);"
676 ).generate(sink, attributes::unused, context))
677 return false;
678
679 // Conversions from/to internal struct and IntPtrs
680 if(!as_generator(
681 indent << scope_tab << "/// <summary>Implicit conversion to the managed representation from a native pointer.\n"
682 ).generate(sink, attributes::unused, context))
683 return false;
684
685 if (!struct_.documentation.since.empty())
686 if (!as_generator(indent << scope_tab << "/// <para>Since EFL " + struct_.documentation.since + ".</para>\n"
687 ).generate(sink, attributes::unused, context))
688 return false;
689
690 if (!as_generator(
691 indent << scope_tab << "/// </summary>\n"
692 << indent << scope_tab << "/// <param name=\"ptr\">Native pointer to be converted.</param>\n"
693 << indent << scope_tab << "public static implicit operator " << struct_name << "(IntPtr ptr)\n"
694 << indent << scope_tab << "{\n"
695 << indent << scope_tab << scope_tab << "return (" << struct_name << ")Marshal.PtrToStructure(ptr, typeof(" << struct_name << "));\n"
696 << indent << scope_tab << "}\n\n"
697 ).generate(sink, attributes::unused, context))
698 return false;
699
700 if(!as_generator(
701 indent << scope_tab << "/// <summary>Conversion to the managed representation from a native pointer.\n"
702 ).generate(sink, attributes::unused, context))
703 return false;
704
705 if (!struct_.documentation.since.empty())
706 if (!as_generator(indent << scope_tab << "/// <para>Since EFL " + struct_.documentation.since + ".</para>\n"
707 ).generate(sink, attributes::unused, context))
708 return false;
709
710 if (!as_generator(
711 indent << scope_tab << "/// </summary>\n"
712 << indent << scope_tab << "/// <param name=\"ptr\">Native pointer to be converted.</param>\n"
713 << indent << scope_tab << "public static " << struct_name << " FromIntPtr(IntPtr ptr)\n"
714 << indent << scope_tab << "{\n"
715 << indent << scope_tab << scope_tab << "return ptr;\n"
716 << indent << scope_tab << "}\n\n"
717 ).generate(sink, attributes::unused, context))
718 return false;
719
720 if(!as_generator(indent << "}\n\n").generate(sink, attributes::unused, context)) return false;
721
722 return true;
723 }
724 } const struct_definition {};
725
726 struct struct_entities_generator
727 {
728 template <typename OutputIterator, typename Context>
generateeolian_mono::struct_entities_generator729 bool generate(OutputIterator sink, attributes::struct_def const& struct_, Context const& context) const
730 {
731 if (blacklist::is_struct_blacklisted(struct_, context))
732 return true;
733
734 if (!name_helpers::open_namespaces(sink, struct_.namespaces, context))
735 return false;
736
737 if (!struct_definition.generate(sink, struct_, context))
738 return false;
739
740 return name_helpers::close_namespaces(sink, struct_.namespaces, context);
741
742 }
743 } const struct_entities {};
744
745 }
746
747 namespace efl { namespace eolian { namespace grammar {
748
749 template <>
750 struct is_eager_generator< ::eolian_mono::struct_definition_generator> : std::true_type {};
751 template <>
752 struct is_generator< ::eolian_mono::struct_definition_generator> : std::true_type {};
753
754 template <>
755 struct is_eager_generator< ::eolian_mono::struct_private_property_generator> : std::true_type {};
756 template <>
757 struct is_generator< ::eolian_mono::struct_private_property_generator> : std::true_type {};
758
759 template <>
760 struct is_eager_generator< ::eolian_mono::to_internal_field_convert_generator> : std::true_type {};
761 template <>
762 struct is_generator< ::eolian_mono::to_internal_field_convert_generator> : std::true_type {};
763
764 template <>
765 struct is_eager_generator< ::eolian_mono::to_external_field_convert_generator> : std::true_type {};
766 template <>
767 struct is_generator< ::eolian_mono::to_external_field_convert_generator> : std::true_type {};
768
769 template <>
770 struct is_eager_generator< ::eolian_mono::struct_entities_generator> : std::true_type {};
771 template <>
772 struct is_generator< ::eolian_mono::struct_entities_generator> : std::true_type {};
773
774 namespace type_traits {
775 template <>
776 struct attributes_needed< ::eolian_mono::struct_definition_generator> : std::integral_constant<int, 1> {};
777
778 template <>
779 struct attributes_needed< ::eolian_mono::struct_private_property_generator> : std::integral_constant<int, 1> {};
780
781 template <>
782 struct attributes_needed< ::eolian_mono::to_internal_field_convert_generator> : std::integral_constant<int, 1> {};
783
784 template <>
785 struct attributes_needed< ::eolian_mono::to_external_field_convert_generator> : std::integral_constant<int, 1> {};
786
787 template <>
788 struct attributes_needed< ::eolian_mono::struct_entities_generator> : std::integral_constant<int, 1> {};
789 }
790
791 } } }
792
793 #endif
794