summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-06-04 18:43:07 -0300
committerVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-06-04 18:52:47 -0300
commit55d557e444f30135dc304e4e8e5eba7c959ea84f (patch)
tree3e634f35467545380f96e5fcca20d410a5a1292f
parentc2865a90ef75320f5ceb00abb03076b8363aa867 (diff)
csharp: make inherited C# classes constructible from native Cdevs/vitorsousa/constructible_eflsharp
With this commit it is now possible for a class that inherits from a C# binding class to be instantiated from native C code. It only has to provide a constructor that receives an `Efl.Eo.EoWrapper.ConstructingHandle` struct, and which calls the base binding constructor passing it. For example: `private Type(ConstructingHandle ch) : base(ch) {}`. Add some test files to validate the proper behavior of this feature. Add some small fixes in generation contexts in order to properly generate base constructors.
-rw-r--r--src/Makefile_Efl_Mono.am9
-rw-r--r--src/bin/eolian_mono/eolian/mono/klass.hh24
-rw-r--r--src/bindings/mono/eo_mono/EoWrapper.cs105
-rw-r--r--src/bindings/mono/eo_mono/iwrapper.cs11
-rw-r--r--src/lib/efl_mono/efl_custom_exports_mono.c10
-rw-r--r--src/tests/efl_mono/EoConstruction.cs79
-rw-r--r--src/tests/efl_mono/dummy_constructible_object.c70
-rw-r--r--src/tests/efl_mono/dummy_constructible_object.eo47
-rw-r--r--src/tests/efl_mono/dummy_test_object.c6
-rw-r--r--src/tests/efl_mono/libefl_mono_native_test.h1
-rw-r--r--src/tests/efl_mono/meson.build3
11 files changed, 352 insertions, 13 deletions
diff --git a/src/Makefile_Efl_Mono.am b/src/Makefile_Efl_Mono.am
index 0cf41589ff..3d04368ccf 100644
--- a/src/Makefile_Efl_Mono.am
+++ b/src/Makefile_Efl_Mono.am
@@ -70,6 +70,7 @@ efl_mono_test_eolian_files = \
70 tests/efl_mono/dummy_inherit_iface.eo \ 70 tests/efl_mono/dummy_inherit_iface.eo \
71 tests/efl_mono/dummy_inherit_helper.eo \ 71 tests/efl_mono/dummy_inherit_helper.eo \
72 tests/efl_mono/dummy_child.eo \ 72 tests/efl_mono/dummy_child.eo \
73 tests/efl_mono/dummy_constructible_object.eo \
73 tests/efl_mono/dummy_part_holder.eo \ 74 tests/efl_mono/dummy_part_holder.eo \
74 tests/efl_mono/dummy_numberwrapper.eo \ 75 tests/efl_mono/dummy_numberwrapper.eo \
75 tests/efl_mono/dummy_event_manager.eo 76 tests/efl_mono/dummy_event_manager.eo
@@ -403,6 +404,7 @@ tests_efl_mono_libefl_mono_native_test_la_SOURCES = \
403 tests/efl_mono/dummy_interfaces.c \ 404 tests/efl_mono/dummy_interfaces.c \
404 tests/efl_mono/dummy_numberwrapper.c \ 405 tests/efl_mono/dummy_numberwrapper.c \
405 tests/efl_mono/dummy_part_holder.c \ 406 tests/efl_mono/dummy_part_holder.c \
407 tests/efl_mono/dummy_constructible_object.c \
406 tests/efl_mono/dummy_test_object.c 408 tests/efl_mono/dummy_test_object.c
407 409
408efl_mono_test_eolian_c = $(efl_mono_test_eolian_files:%.eo=%.eo.c) 410efl_mono_test_eolian_c = $(efl_mono_test_eolian_files:%.eo=%.eo.c)
@@ -447,6 +449,11 @@ tests/efl_mono/dummy_part_holder.c: \
447 $(efl_mono_test_eolian_h) \ 449 $(efl_mono_test_eolian_h) \
448 tests/efl_mono/libefl_mono_native_test.h 450 tests/efl_mono/libefl_mono_native_test.h
449 451
452tests/efl_mono/dummy_constructible_object.c: \
453 $(efl_mono_test_eolian_c) \
454 $(efl_mono_test_eolian_h) \
455 tests/efl_mono/libefl_mono_native_test.h
456
450tests/efl_mono/dummy_test_object.c: \ 457tests/efl_mono/dummy_test_object.c: \
451 $(efl_mono_test_eolian_c) \ 458 $(efl_mono_test_eolian_c) \
452 $(efl_mono_test_eolian_h) \ 459 $(efl_mono_test_eolian_h) \
@@ -455,6 +462,7 @@ tests/efl_mono/dummy_test_object.c: \
455# Intermediate C Sharp test DLL 462# Intermediate C Sharp test DLL
456efl_mono_test_eolian_mono_files = tests/efl_mono/dummy_test_object.eo.cs \ 463efl_mono_test_eolian_mono_files = tests/efl_mono/dummy_test_object.eo.cs \
457tests/efl_mono/dummy_test_iface.eo.cs \ 464tests/efl_mono/dummy_test_iface.eo.cs \
465tests/efl_mono/dummy_constructible_object.eo.cs \
458tests/efl_mono/dummy_child.eo.cs \ 466tests/efl_mono/dummy_child.eo.cs \
459tests/efl_mono/dummy_event_manager.eo.cs \ 467tests/efl_mono/dummy_event_manager.eo.cs \
460tests/efl_mono/dummy_part_holder.eo.cs \ 468tests/efl_mono/dummy_part_holder.eo.cs \
@@ -509,6 +517,7 @@ tests_efl_mono_efl_mono_SOURCES = \
509 tests/efl_mono/Eldbus.cs \ 517 tests/efl_mono/Eldbus.cs \
510 tests/efl_mono/Eo.cs \ 518 tests/efl_mono/Eo.cs \
511 tests/efl_mono/EoPromises.cs \ 519 tests/efl_mono/EoPromises.cs \
520 tests/efl_mono/EoConstruction.cs \
512 tests/efl_mono/Errors.cs \ 521 tests/efl_mono/Errors.cs \
513 tests/efl_mono/Events.cs \ 522 tests/efl_mono/Events.cs \
514 tests/efl_mono/FunctionPointers.cs \ 523 tests/efl_mono/FunctionPointers.cs \
diff --git a/src/bin/eolian_mono/eolian/mono/klass.hh b/src/bin/eolian_mono/eolian/mono/klass.hh
index 6ac4aa1c3c..8b018f6413 100644
--- a/src/bin/eolian_mono/eolian/mono/klass.hh
+++ b/src/bin/eolian_mono/eolian/mono/klass.hh
@@ -198,6 +198,17 @@ struct klass
198 198
199 if (!as_generator 199 if (!as_generator
200 ( 200 (
201 scope_tab << "/// <summary>Constructor to be used when objects are expected to be constructed from native code.</summary>\n"
202 << scope_tab << "/// <param name=\"ch\">Tag struct storing the native handle of the object being constructed.</param>\n"
203 << scope_tab << "private " << concrete_name << "(ConstructingHandle ch) : base(ch)\n"
204 << scope_tab << "{\n"
205 << scope_tab << "}\n\n"
206 )
207 .generate(sink, attributes::unused, concrete_cxt))
208 return false;
209
210 if (!as_generator
211 (
201 scope_tab << "[System.Runtime.InteropServices.DllImport(" << context_find_tag<library_context>(concrete_cxt).actual_library_name(cls.filename) 212 scope_tab << "[System.Runtime.InteropServices.DllImport(" << context_find_tag<library_context>(concrete_cxt).actual_library_name(cls.filename)
202 << ")] internal static extern System.IntPtr\n" 213 << ")] internal static extern System.IntPtr\n"
203 << scope_tab << scope_tab << name_helpers::klass_get_name(cls) << "();\n" 214 << scope_tab << scope_tab << name_helpers::klass_get_name(cls) << "();\n"
@@ -246,7 +257,7 @@ struct klass
246 ).generate(sink, attributes::unused, concrete_cxt)) 257 ).generate(sink, attributes::unused, concrete_cxt))
247 return false; 258 return false;
248 259
249 if(!generate_native_inherit_class(sink, cls, change_indentation(indent.inc(), context))) 260 if(!generate_native_inherit_class(sink, cls, change_indentation(indent.inc(), concrete_cxt)))
250 return true; 261 return true;
251 262
252 if(!as_generator("}\n").generate(sink, attributes::unused, concrete_cxt)) return false; 263 if(!as_generator("}\n").generate(sink, attributes::unused, concrete_cxt)) return false;
@@ -318,7 +329,7 @@ struct klass
318 ).generate(sink, attributes::unused, inherit_cxt)) 329 ).generate(sink, attributes::unused, inherit_cxt))
319 return false; 330 return false;
320 331
321 if(!generate_native_inherit_class(sink, cls, change_indentation(indent.inc(), context))) 332 if(!generate_native_inherit_class(sink, cls, change_indentation(indent.inc(), inherit_cxt)))
322 return true; 333 return true;
323 334
324 if(!as_generator("}\n").generate(sink, attributes::unused, inherit_cxt)) return false; 335 if(!as_generator("}\n").generate(sink, attributes::unused, inherit_cxt)) return false;
@@ -357,7 +368,7 @@ struct klass
357 ( 368 (
358 indent << lit("/// <summary>Wrapper for native methods and virtual method delegates.\n") 369 indent << lit("/// <summary>Wrapper for native methods and virtual method delegates.\n")
359 << indent << "/// For internal use by generated code only.</summary>\n" 370 << indent << "/// For internal use by generated code only.</summary>\n"
360 << indent << "public " << (root ? "" : "new " ) << "class " << native_inherit_name << " " << (root ? " : Efl.Eo.NativeClass" : (": " + base_name)) <<"\n" 371 << indent << "public new class " << native_inherit_name << " : " << (root ? "Efl.Eo.EoWrapper.NativeMethods" : base_name) << "\n"
361 << indent << "{\n" 372 << indent << "{\n"
362 ).generate(sink, attributes::unused, inative_cxt)) 373 ).generate(sink, attributes::unused, inative_cxt))
363 return false; 374 return false;
@@ -396,7 +407,7 @@ struct klass
396 ).generate(sink, attributes::unused, inative_cxt)) 407 ).generate(sink, attributes::unused, inative_cxt))
397 return false; 408 return false;
398 409
399 if(!root) 410 if (!root || context_find_tag<class_context>(context).current_wrapper_kind != class_context::concrete)
400 if(!as_generator(indent << scope_tab << scope_tab << "descs.AddRange(base.GetEoOps(type));\n").generate(sink, attributes::unused, inative_cxt)) 411 if(!as_generator(indent << scope_tab << scope_tab << "descs.AddRange(base.GetEoOps(type));\n").generate(sink, attributes::unused, inative_cxt))
401 return false; 412 return false;
402 413
@@ -492,6 +503,11 @@ struct klass
492 << (*(scope_tab << scope_tab << constructor_invocation << "\n")) 503 << (*(scope_tab << scope_tab << constructor_invocation << "\n"))
493 << scope_tab << scope_tab << "FinishInstantiation();\n" 504 << scope_tab << scope_tab << "FinishInstantiation();\n"
494 << scope_tab << "}\n\n" 505 << scope_tab << "}\n\n"
506 << scope_tab << "/// <summary>Constructor to be used when objects are expected to be constructed from native code.</summary>\n"
507 << scope_tab << "/// <param name=\"ch\">Tag struct storing the native handle of the object being constructed.</param>\n"
508 << scope_tab << "protected " << inherit_name << "(ConstructingHandle ch) : base(ch)\n"
509 << scope_tab << "{\n"
510 << scope_tab << "}\n\n"
495 << scope_tab << "/// <summary>Initializes a new instance of the <see cref=\"" << inherit_name << "\"/> class.\n" 511 << scope_tab << "/// <summary>Initializes a new instance of the <see cref=\"" << inherit_name << "\"/> class.\n"
496 << scope_tab << "/// Internal usage: Constructs an instance from a native pointer. This is used when interacting with C code and should not be used directly.</summary>\n" 512 << scope_tab << "/// Internal usage: Constructs an instance from a native pointer. This is used when interacting with C code and should not be used directly.</summary>\n"
497 << scope_tab << "/// <param name=\"raw\">The native pointer to be wrapped.</param>\n" 513 << scope_tab << "/// <param name=\"raw\">The native pointer to be wrapped.</param>\n"
diff --git a/src/bindings/mono/eo_mono/EoWrapper.cs b/src/bindings/mono/eo_mono/EoWrapper.cs
index e1174a9fe8..0899b8682c 100644
--- a/src/bindings/mono/eo_mono/EoWrapper.cs
+++ b/src/bindings/mono/eo_mono/EoWrapper.cs
@@ -2,6 +2,7 @@ using System;
2using System.Runtime.InteropServices; 2using System.Runtime.InteropServices;
3using System.Runtime.CompilerServices; 3using System.Runtime.CompilerServices;
4using System.Threading; 4using System.Threading;
5using System.Reflection;
5 6
6namespace Efl 7namespace Efl
7{ 8{
@@ -62,6 +63,32 @@ public abstract class EoWrapper : IWrapper, IDisposable
62 private static Efl.EventCb ownershipUniqueDelegate = new Efl.EventCb(OwnershipUniqueCallback); 63 private static Efl.EventCb ownershipUniqueDelegate = new Efl.EventCb(OwnershipUniqueCallback);
63 private static Efl.EventCb ownershipSharedDelegate = new Efl.EventCb(OwnershipSharedCallback); 64 private static Efl.EventCb ownershipSharedDelegate = new Efl.EventCb(OwnershipSharedCallback);
64 65
66
67 /// <summary>Constructor to be used when objects are expected to be constructed from native code.
68 /// For a class that inherited from an EFL# class to be properly constructed from native code
69 /// one must create a constructor with this signature and calls this base constructor from it.
70 /// This constructor will take care of calling base constructors of the native classes and
71 /// perform additional setup so objects are ready to use.
72 /// It is advisable to check for the <see cref="NativeHandle"/> property in the top level
73 /// constructor and signal an error when it has a value of IntPtr.Zero after this
74 /// constructor completion.
75 /// Warning: Do not use this constructor directly from a `new` statement.</summary>
76 /// <param name="ch">Tag struct storing the native handle of the object being constructed.</param>
77 protected EoWrapper(ConstructingHandle ch)
78 {
79 handle = Efl.Eo.Globals.efl_constructor(Efl.Eo.Globals.efl_super(ch.NativeHandle, Efl.Eo.Globals.efl_class_get(ch.NativeHandle)));
80 if (handle == IntPtr.Zero)
81 {
82 Eina.Log.Warning("Natice constructor returned NULL");
83 return;
84 }
85
86 AddWrapperSupervisor();
87 // Make an additional reference to C#
88 // - Will also call EVENT_OWNERSHIP_SHARED
89 Efl.Eo.Globals.efl_ref(handle);
90 }
91
65 /// <summary>Initializes a new instance of the <see cref="Object"/> class. 92 /// <summary>Initializes a new instance of the <see cref="Object"/> class.
66 /// Internal usage: Constructs an instance from a native pointer. This is used when interacting with C code and should not be used directly.</summary> 93 /// Internal usage: Constructs an instance from a native pointer. This is used when interacting with C code and should not be used directly.</summary>
67 /// <param name="raw">The native pointer to be wrapped.</param> 94 /// <param name="raw">The native pointer to be wrapped.</param>
@@ -98,7 +125,17 @@ public abstract class EoWrapper : IWrapper, IDisposable
98 parent_ptr = parent.NativeHandle; 125 parent_ptr = parent.NativeHandle;
99 } 126 }
100 127
101 handle = Efl.Eo.Globals._efl_add_internal_start(file, line, actual_klass, parent_ptr, 1, 0); 128 if (!inherited)
129 {
130 handle = Efl.Eo.Globals._efl_add_internal_start(file, line, actual_klass, parent_ptr, 1, 0);
131 }
132 else
133 {
134 handle = Efl.Eo.Globals._efl_add_internal_start_bindings(file, line, actual_klass, parent_ptr, 1, 0,
135 Efl.Eo.Globals.efl_mono_avoid_top_level_constructor_callback_addr_get(),
136 IntPtr.Zero);
137 }
138
102 if (handle == System.IntPtr.Zero) 139 if (handle == System.IntPtr.Zero)
103 { 140 {
104 throw new Exception("Instantiation failed"); 141 throw new Exception("Instantiation failed");
@@ -297,8 +334,72 @@ public abstract class EoWrapper : IWrapper, IDisposable
297 AddNativeEventHandler("eo", "_EFL_EVENT_OWNERSHIP_SHARED", ownershipSharedDelegate, ownershipSharedDelegate); 334 AddNativeEventHandler("eo", "_EFL_EVENT_OWNERSHIP_SHARED", ownershipSharedDelegate, ownershipSharedDelegate);
298 Eina.Error.RaiseIfUnhandledException(); 335 Eina.Error.RaiseIfUnhandledException();
299 } 336 }
337
338 protected struct ConstructingHandle
339 {
340 public ConstructingHandle(IntPtr h)
341 {
342 NativeHandle = h;
343 }
344
345 public IntPtr NativeHandle { get; set; }
346 }
347
348 public abstract class NativeMethods : Efl.Eo.NativeClass
349 {
350 private static EflConstructorSelegate csharpEflConstructorStaticDelegate = new EflConstructorSelegate(Constructor);
351 private static Efl.Eo.NativeModule EoModule = new Efl.Eo.NativeModule("eo");
352
353 private delegate IntPtr EflConstructorSelegate(IntPtr obj, IntPtr pd);
354
355 public override System.Collections.Generic.List<Efl_Op_Description> GetEoOps(Type type)
356 {
357 var descs = new System.Collections.Generic.List<Efl_Op_Description>();
358
359 descs.Add(new Efl_Op_Description()
360 {
361 api_func = Efl.Eo.FunctionInterop.LoadFunctionPointer(EoModule.Module, "efl_constructor"),
362 func = Marshal.GetFunctionPointerForDelegate(csharpEflConstructorStaticDelegate)
363 });
364
365 return descs;
366 }
367
368 private static IntPtr Constructor(IntPtr obj, IntPtr pd)
369 {
370 try
371 {
372 var eoKlass = Efl.Eo.Globals.efl_class_get(obj);
373 var managedType = ClassRegister.GetManagedType(eoKlass);
374 if (managedType == null)
375 {
376 IntPtr nativeName = Efl.Eo.Globals.efl_class_name_get(eoKlass);
377 var name = Eina.StringConversion.NativeUtf8ToManagedString(nativeName);
378 Eina.Log.Warning($"Can't get Managed class for object handle 0x{(UInt64)obj:x} with native class [{name}]");
379 return IntPtr.Zero;
380 }
381
382 var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
383 ConstructorInfo constructor = managedType.GetConstructor(flags, null, new Type[1] { typeof(ConstructingHandle) }, null);
384 var eoWrapper = (Efl.Eo.IWrapper) constructor.Invoke(new object[1] { new ConstructingHandle(obj) });
385 if (eoWrapper == null)
386 {
387 Eina.Log.Warning("Constructor was unable to create a new object");
388 return IntPtr.Zero;
389 }
390
391 return eoWrapper.NativeHandle;
392 }
393 catch (Exception e)
394 {
395 Eina.Log.Warning($"Inherited constructor error: {e.ToString()}");
396 Eina.Error.Set(Eina.Error.UNHANDLED_EXCEPTION);
397 return IntPtr.Zero;
398 }
399 }
400 }
300} 401}
301 402
302} // namespace Global 403} // namespace Eo
303 404
304} // namespace Efl 405} // namespace Efl
diff --git a/src/bindings/mono/eo_mono/iwrapper.cs b/src/bindings/mono/eo_mono/iwrapper.cs
index 9e73ca4687..618d16ca0f 100644
--- a/src/bindings/mono/eo_mono/iwrapper.cs
+++ b/src/bindings/mono/eo_mono/iwrapper.cs
@@ -44,10 +44,6 @@ public class Globals
44 public static FunctionWrapper<efl_object_shutdown_delegate> efl_object_shutdown_ptr = new FunctionWrapper<efl_object_shutdown_delegate>(efl.Libs.EoModule, "efl_object_shutdown"); 44 public static FunctionWrapper<efl_object_shutdown_delegate> efl_object_shutdown_ptr = new FunctionWrapper<efl_object_shutdown_delegate>(efl.Libs.EoModule, "efl_object_shutdown");
45 public static void efl_object_shutdown() => efl_object_shutdown_ptr.Value.Delegate(); 45 public static void efl_object_shutdown() => efl_object_shutdown_ptr.Value.Delegate();
46 // [DllImport(efl.Libs.Eo)] public static extern void efl_object_shutdown(); 46 // [DllImport(efl.Libs.Eo)] public static extern void efl_object_shutdown();
47 public static FunctionWrapper<_efl_add_internal_start_delegate> _efl_add_internal_start_ptr = new FunctionWrapper<_efl_add_internal_start_delegate>(efl.Libs.EoModule, "_efl_add_internal_start");
48 public delegate IntPtr
49 _efl_add_internal_start_delegate([MarshalAs(UnmanagedType.LPStr)] String file, int line,
50 IntPtr klass, IntPtr parent, byte is_ref, byte is_fallback);
51 47
52 [DllImport(efl.Libs.CustomExports)] public static extern IntPtr efl_mono_wrapper_supervisor_get(IntPtr eo); 48 [DllImport(efl.Libs.CustomExports)] public static extern IntPtr efl_mono_wrapper_supervisor_get(IntPtr eo);
53 [DllImport(efl.Libs.CustomExports)] public static extern void efl_mono_wrapper_supervisor_set(IntPtr eo, IntPtr ws); 49 [DllImport(efl.Libs.CustomExports)] public static extern void efl_mono_wrapper_supervisor_set(IntPtr eo, IntPtr ws);
@@ -55,6 +51,9 @@ public class Globals
55 [DllImport(efl.Libs.Eo)] public static extern IntPtr 51 [DllImport(efl.Libs.Eo)] public static extern IntPtr
56 _efl_add_internal_start([MarshalAs(UnmanagedType.LPStr)] String file, int line, 52 _efl_add_internal_start([MarshalAs(UnmanagedType.LPStr)] String file, int line,
57 IntPtr klass, IntPtr parent, byte is_ref, byte is_fallback); 53 IntPtr klass, IntPtr parent, byte is_ref, byte is_fallback);
54 [DllImport(efl.Libs.Eo)] public static extern IntPtr
55 _efl_add_internal_start_bindings([MarshalAs(UnmanagedType.LPStr)] String file, int line, IntPtr klass, IntPtr parent,
56 byte is_ref, byte is_fallback, IntPtr substitute_ctor, IntPtr data);
58 public delegate IntPtr 57 public delegate IntPtr
59 _efl_add_end_delegate(IntPtr eo, byte is_ref, byte is_fallback); 58 _efl_add_end_delegate(IntPtr eo, byte is_ref, byte is_fallback);
60 [DllImport(efl.Libs.Eo)] public static extern IntPtr 59 [DllImport(efl.Libs.Eo)] public static extern IntPtr
@@ -196,6 +195,10 @@ public class Globals
196 public delegate IntPtr dlerror_delegate(); 195 public delegate IntPtr dlerror_delegate();
197 [DllImport(efl.Libs.Evil)] public static extern IntPtr dlerror(); 196 [DllImport(efl.Libs.Evil)] public static extern IntPtr dlerror();
198 197
198 [DllImport(efl.Libs.Eo)] public static extern IntPtr efl_constructor(IntPtr obj);
199
200 [DllImport(efl.Libs.CustomExports)] public static extern IntPtr efl_mono_avoid_top_level_constructor_callback_addr_get();
201
199 [DllImport(efl.Libs.Eo)] [return: MarshalAs(UnmanagedType.U1)] public static extern bool 202 [DllImport(efl.Libs.Eo)] [return: MarshalAs(UnmanagedType.U1)] public static extern bool
200 efl_event_callback_priority_add(IntPtr obj, IntPtr desc, short priority, IntPtr cb, IntPtr data); 203 efl_event_callback_priority_add(IntPtr obj, IntPtr desc, short priority, IntPtr cb, IntPtr data);
201 204
diff --git a/src/lib/efl_mono/efl_custom_exports_mono.c b/src/lib/efl_mono/efl_custom_exports_mono.c
index 55f0054da0..a11a11e4b6 100644
--- a/src/lib/efl_mono/efl_custom_exports_mono.c
+++ b/src/lib/efl_mono/efl_custom_exports_mono.c
@@ -166,6 +166,16 @@ EAPI Eina_Free_Cb efl_mono_native_efl_unref_addr_get()
166 return (Eina_Free_Cb)efl_mono_thread_safe_efl_unref; 166 return (Eina_Free_Cb)efl_mono_thread_safe_efl_unref;
167} 167}
168 168
169static Eo *_efl_mono_avoid_top_level_constructor_cb(void *data EINA_UNUSED, Eo *obj)
170{
171 return efl_constructor(efl_super(obj, efl_class_get(obj)));
172}
173
174EAPI Efl_Substitute_Ctor_Cb efl_mono_avoid_top_level_constructor_callback_addr_get()
175{
176 return &_efl_mono_avoid_top_level_constructor_cb;
177}
178
169// Iterator Wrapper // 179// Iterator Wrapper //
170 180
171typedef struct _Eina_Iterator_Wrapper_Mono 181typedef struct _Eina_Iterator_Wrapper_Mono
diff --git a/src/tests/efl_mono/EoConstruction.cs b/src/tests/efl_mono/EoConstruction.cs
new file mode 100644
index 0000000000..cd4a774bd1
--- /dev/null
+++ b/src/tests/efl_mono/EoConstruction.cs
@@ -0,0 +1,79 @@
1using System;
2
3class InheritedConstructibleObject : Dummy.ConstructibleObject
4{
5 public InheritedConstructibleObject()
6 {
7 if (this.NativeConstructionCount != 1)
8 {
9 DefaultConstrutorCallCount = -100;
10 }
11
12 ++DefaultConstrutorCallCount;
13 this.IncrementDefaultConstructionCount();
14 }
15
16 private InheritedConstructibleObject(ConstructingHandle ch) : base(ch)
17 {
18 if (this.NativeConstructionCount != 1)
19 {
20 SpecialConstrutorCallCount = -100;
21 }
22
23 ++SpecialConstrutorCallCount;
24 this.IncrementSpecialConstructionCount();
25 }
26
27 public int DefaultConstrutorCallCount { get; set; } = 0;
28 public int SpecialConstrutorCallCount { get; set; } = 0;
29}
30
31namespace TestSuite
32{
33
34class TestEoConstruction
35{
36 public static void TestGeneratedEoDirectConstruction()
37 {
38 var obj = new Dummy.ConstructibleObject();
39 Test.AssertEquals(obj.NativeConstructionCount, 1);
40 Test.AssertEquals(obj.DefaultConstructionCount, 0);
41 Test.AssertEquals(obj.SpecialConstructionCount, 0);
42 obj.Dispose();
43 }
44
45 public static void TestInheritedEoDirectConstruction()
46 {
47 var obj = new InheritedConstructibleObject();
48 Test.AssertEquals(obj.NativeConstructionCount, 1);
49 Test.AssertEquals(obj.DefaultConstructionCount, 1);
50 Test.AssertEquals(obj.SpecialConstructionCount, 0);
51 Test.AssertEquals(obj.DefaultConstrutorCallCount, 1);
52 Test.AssertEquals(obj.SpecialConstrutorCallCount, 0);
53 obj.Dispose();
54 }
55
56 public static void TestInheritedEoIndirectConstruction()
57 {
58 var obj = new Dummy.ConstructibleObject();
59 Test.AssertEquals(obj.NativeConstructionCount, 1);
60 Test.AssertEquals(obj.DefaultConstructionCount, 0);
61 Test.AssertEquals(obj.SpecialConstructionCount, 0);
62
63 var obj2 = (InheritedConstructibleObject) obj.ConstructTypeAndStore(typeof(InheritedConstructibleObject));
64 Test.AssertEquals(obj2.NativeConstructionCount, 1);
65 Test.AssertEquals(obj2.DefaultConstructionCount, 0);
66 Test.AssertEquals(obj2.SpecialConstructionCount, 1);
67 Test.AssertEquals(obj2.DefaultConstrutorCallCount, 0);
68 Test.AssertEquals(obj2.SpecialConstrutorCallCount, 1);
69
70 var internalObj = obj.InternalObject;
71 Test.Assert(obj2 == internalObj); // Ensure it always use the same object instance
72 Test.AssertEquals(obj2.NativeConstructionCount, 1); // And that constructors are not called again
73
74 obj.Dispose();
75 obj2.Dispose();
76 }
77}
78
79}
diff --git a/src/tests/efl_mono/dummy_constructible_object.c b/src/tests/efl_mono/dummy_constructible_object.c
new file mode 100644
index 0000000000..96842709ba
--- /dev/null
+++ b/src/tests/efl_mono/dummy_constructible_object.c
@@ -0,0 +1,70 @@
1#include "libefl_mono_native_test.h"
2
3typedef struct _Dummy_Constructible_Object_Data
4{
5 Eo *internal_obj;
6 int native_construction_count;
7 int default_construction_count;
8 int special_construction_count;
9} Dummy_Constructible_Object_Data;
10
11
12EOLIAN static Eo *
13_dummy_constructible_object_efl_object_constructor(Eo *obj, Dummy_Constructible_Object_Data *pd)
14{
15 ++(pd->native_construction_count);
16 return efl_constructor(efl_super(obj, DUMMY_CONSTRUCTIBLE_OBJECT_CLASS));
17}
18
19EOLIAN static void
20_dummy_constructible_object_efl_object_destructor(Eo *obj, Dummy_Constructible_Object_Data *pd)
21{
22 if (pd->internal_obj)
23 efl_unref(pd->internal_obj);
24 efl_destructor(efl_super(obj, DUMMY_CONSTRUCTIBLE_OBJECT_CLASS));
25}
26
27EOLIAN static Efl_Object *
28_dummy_constructible_object_construct_type_and_store(Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd, const Efl_Class *klass)
29{
30 pd->internal_obj = efl_add_ref(klass, NULL);
31 return pd->internal_obj;
32}
33
34EOLIAN static void
35_dummy_constructible_object_increment_default_construction_count(Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
36{
37 ++(pd->default_construction_count);
38}
39
40EOLIAN static void
41_dummy_constructible_object_increment_special_construction_count(Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
42{
43 ++(pd->special_construction_count);
44}
45
46EOLIAN static int
47_dummy_constructible_object_native_construction_count_get(const Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
48{
49 return pd->native_construction_count;
50}
51
52EOLIAN static int
53_dummy_constructible_object_default_construction_count_get(const Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
54{
55 return pd->default_construction_count;
56}
57
58EOLIAN static int
59_dummy_constructible_object_special_construction_count_get(const Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
60{
61 return pd->special_construction_count;
62}
63
64EOLIAN static Efl_Object *
65_dummy_constructible_object_internal_object_get(const Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
66{
67 return pd->internal_obj;
68}
69
70#include "dummy_constructible_object.eo.c"
diff --git a/src/tests/efl_mono/dummy_constructible_object.eo b/src/tests/efl_mono/dummy_constructible_object.eo
new file mode 100644
index 0000000000..f8ae944e6c
--- /dev/null
+++ b/src/tests/efl_mono/dummy_constructible_object.eo
@@ -0,0 +1,47 @@
1class Dummy.Constructible_Object extends Efl.Object {
2 methods {
3 construct_type_and_store {
4 params {
5 @in type: const(Efl.Class);
6 }
7 return: Efl.Object;
8 }
9 increment_default_construction_count {
10 }
11 increment_special_construction_count {
12 }
13 @property native_construction_count {
14 get {
15 }
16 values {
17 value: int;
18 }
19 }
20 @property default_construction_count {
21 get {
22 }
23 values {
24 value: int;
25 }
26 }
27 @property special_construction_count {
28 get {
29 }
30 values {
31 value: int;
32 }
33 }
34 @property internal_object {
35 get {
36 }
37 values {
38 value: Efl.Object;
39 }
40 }
41 }
42 implements {
43 Efl.Object.constructor;
44 Efl.Object.destructor;
45 }
46}
47
diff --git a/src/tests/efl_mono/dummy_test_object.c b/src/tests/efl_mono/dummy_test_object.c
index fa5d01888a..f9b276c085 100644
--- a/src/tests/efl_mono/dummy_test_object.c
+++ b/src/tests/efl_mono/dummy_test_object.c
@@ -56,9 +56,9 @@ Dummy_Numberwrapper **_new_obj_ref(int n)
56 return &r; 56 return &r;
57} 57}
58 58
59// ############ // 59// ################# //
60// Test.Testing // 60// Dummy.Test_Object //
61// ############ // 61// ################# //
62 62
63static Efl_Object* 63static Efl_Object*
64_dummy_test_object_efl_object_constructor(Eo *obj, Dummy_Test_Object_Data *pd) 64_dummy_test_object_efl_object_constructor(Eo *obj, Dummy_Test_Object_Data *pd)
diff --git a/src/tests/efl_mono/libefl_mono_native_test.h b/src/tests/efl_mono/libefl_mono_native_test.h
index 9251118fc6..b726bd05c1 100644
--- a/src/tests/efl_mono/libefl_mono_native_test.h
+++ b/src/tests/efl_mono/libefl_mono_native_test.h
@@ -55,6 +55,7 @@
55#include "dummy_inherit_helper.eo.h" 55#include "dummy_inherit_helper.eo.h"
56#include "dummy_part_holder.eo.h" 56#include "dummy_part_holder.eo.h"
57#include "dummy_event_manager.eo.h" 57#include "dummy_event_manager.eo.h"
58#include "dummy_constructible_object.eo.h"
58 59
59#include <interfaces/efl_part.eo.h> 60#include <interfaces/efl_part.eo.h>
60 61
diff --git a/src/tests/efl_mono/meson.build b/src/tests/efl_mono/meson.build
index f75a5b8bb9..e464cdd2a8 100644
--- a/src/tests/efl_mono/meson.build
+++ b/src/tests/efl_mono/meson.build
@@ -7,6 +7,7 @@ eo_files = [
7 'dummy_inherit_iface.eo', 7 'dummy_inherit_iface.eo',
8 'dummy_part_holder.eo', 8 'dummy_part_holder.eo',
9 'dummy_event_manager.eo', 9 'dummy_event_manager.eo',
10 'dummy_constructible_object.eo',
10] 11]
11 12
12eo_file_targets = [] 13eo_file_targets = []
@@ -33,6 +34,7 @@ efl_mono_native_test = library('efl_mono_native_test',
33 'dummy_part_holder.c', 34 'dummy_part_holder.c',
34 'dummy_test_object.c', 35 'dummy_test_object.c',
35 'dummy_event_manager.c', 36 'dummy_event_manager.c',
37 'dummy_constructible_object.c',
36 ], 38 ],
37 dependencies : [ecore, eo, efl], 39 dependencies : [ecore, eo, efl],
38) 40)
@@ -65,6 +67,7 @@ efl_mono_src = [
65 'Eldbus.cs', 67 'Eldbus.cs',
66 'Eo.cs', 68 'Eo.cs',
67 'EoPromises.cs', 69 'EoPromises.cs',
70 'EoConstruction.cs',
68 'Errors.cs', 71 'Errors.cs',
69 'Events.cs', 72 'Events.cs',
70 'FunctionPointers.cs', 73 'FunctionPointers.cs',