Compare commits

...

5 Commits

Author SHA1 Message Date
Vitor Sousa 6e83ee95c1 equality methods and some test stubs 2019-06-11 15:33:39 -03:00
Vitor Sousa 2a99be2b52 DON'T LAND csharp: fix stringshare usage in eina containers 2019-06-10 19:02:01 -03:00
Vitor Sousa f6eeb3fb7c csharp: make inherited C# classes constructible from native C
Summary:
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.

Depends on D9070

Test Plan: `meson test` and `make check`

Reviewers: lauromoura, felipealmeida, segfaultxavi, woohyun

Subscribers: cedric, #reviewers, #committers

Tags: #efl

Differential Revision: https://phab.enlightenment.org/D9071
2019-06-04 19:42:55 -03:00
Vitor Sousa c2865a90ef eo: add an API entry for custom instantiation of Eo objects for binding usage
Add a new function in the Eo API in order to provide more options on object
instantiation for binding creators.

For the Eo lib to be able to construct objects that inherit from bindings in
many languages we should provide a way for bindings to call different kinds of
constructors, in a way that simply overriding the `efl_constructor` method is
not enough.
We need a way to differentiate at construction time if the Eo is being
constructed from C or from the binding, because if it is the
former we need too call the inherited object constructor from C and instantiate
a new object, and if it is the later we need to avoid instantiating a
new object because we are already in the middle of the process of creating
a new one.
`efl_constructor` alone does not provide any way of distinguishing between
those situations, so, being able to pass additional information for
efl_add_start (like a custom constructor pointer) is necessary to make the
right distinction.
2019-06-04 18:52:47 -03:00
Lauro Moura 82a320c683 csharp: Add a SafePtr wrapper in debug mode
This wrapper will trigger `ObjectDisposedException` when trying to call
a method on object after it was disposed.

It is enabled only with `--buildtype=debug` when configuring meson.
2019-06-04 18:52:47 -03:00
23 changed files with 967 additions and 43 deletions

View File

@ -70,6 +70,7 @@ efl_mono_test_eolian_files = \
tests/efl_mono/dummy_inherit_iface.eo \
tests/efl_mono/dummy_inherit_helper.eo \
tests/efl_mono/dummy_child.eo \
tests/efl_mono/dummy_constructible_object.eo \
tests/efl_mono/dummy_part_holder.eo \
tests/efl_mono/dummy_numberwrapper.eo \
tests/efl_mono/dummy_event_manager.eo
@ -403,6 +404,7 @@ tests_efl_mono_libefl_mono_native_test_la_SOURCES = \
tests/efl_mono/dummy_interfaces.c \
tests/efl_mono/dummy_numberwrapper.c \
tests/efl_mono/dummy_part_holder.c \
tests/efl_mono/dummy_constructible_object.c \
tests/efl_mono/dummy_test_object.c
efl_mono_test_eolian_c = $(efl_mono_test_eolian_files:%.eo=%.eo.c)
@ -447,6 +449,11 @@ tests/efl_mono/dummy_part_holder.c: \
$(efl_mono_test_eolian_h) \
tests/efl_mono/libefl_mono_native_test.h
tests/efl_mono/dummy_constructible_object.c: \
$(efl_mono_test_eolian_c) \
$(efl_mono_test_eolian_h) \
tests/efl_mono/libefl_mono_native_test.h
tests/efl_mono/dummy_test_object.c: \
$(efl_mono_test_eolian_c) \
$(efl_mono_test_eolian_h) \
@ -455,6 +462,7 @@ tests/efl_mono/dummy_test_object.c: \
# Intermediate C Sharp test DLL
efl_mono_test_eolian_mono_files = tests/efl_mono/dummy_test_object.eo.cs \
tests/efl_mono/dummy_test_iface.eo.cs \
tests/efl_mono/dummy_constructible_object.eo.cs \
tests/efl_mono/dummy_child.eo.cs \
tests/efl_mono/dummy_event_manager.eo.cs \
tests/efl_mono/dummy_part_holder.eo.cs \
@ -509,6 +517,7 @@ tests_efl_mono_efl_mono_SOURCES = \
tests/efl_mono/Eldbus.cs \
tests/efl_mono/Eo.cs \
tests/efl_mono/EoPromises.cs \
tests/efl_mono/EoConstruction.cs \
tests/efl_mono/Errors.cs \
tests/efl_mono/Events.cs \
tests/efl_mono/FunctionPointers.cs \

View File

@ -196,6 +196,17 @@ struct klass
if (!generate_fields(sink, cls, concrete_cxt))
return false;
if (!as_generator
(
scope_tab << "/// <summary>Constructor to be used when objects are expected to be constructed from native code.</summary>\n"
<< scope_tab << "/// <param name=\"ch\">Tag struct storing the native handle of the object being constructed.</param>\n"
<< scope_tab << "private " << concrete_name << "(ConstructingHandle ch) : base(ch)\n"
<< scope_tab << "{\n"
<< scope_tab << "}\n\n"
)
.generate(sink, attributes::unused, concrete_cxt))
return false;
if (!as_generator
(
scope_tab << "[System.Runtime.InteropServices.DllImport(" << context_find_tag<library_context>(concrete_cxt).actual_library_name(cls.filename)
@ -246,7 +257,7 @@ struct klass
).generate(sink, attributes::unused, concrete_cxt))
return false;
if(!generate_native_inherit_class(sink, cls, change_indentation(indent.inc(), context)))
if(!generate_native_inherit_class(sink, cls, change_indentation(indent.inc(), concrete_cxt)))
return true;
if(!as_generator("}\n").generate(sink, attributes::unused, concrete_cxt)) return false;
@ -318,7 +329,7 @@ struct klass
).generate(sink, attributes::unused, inherit_cxt))
return false;
if(!generate_native_inherit_class(sink, cls, change_indentation(indent.inc(), context)))
if(!generate_native_inherit_class(sink, cls, change_indentation(indent.inc(), inherit_cxt)))
return true;
if(!as_generator("}\n").generate(sink, attributes::unused, inherit_cxt)) return false;
@ -357,7 +368,7 @@ struct klass
(
indent << lit("/// <summary>Wrapper for native methods and virtual method delegates.\n")
<< indent << "/// For internal use by generated code only.</summary>\n"
<< indent << "public " << (root ? "" : "new " ) << "class " << native_inherit_name << " " << (root ? " : Efl.Eo.NativeClass" : (": " + base_name)) <<"\n"
<< indent << "public new class " << native_inherit_name << " : " << (root ? "Efl.Eo.EoWrapper.NativeMethods" : base_name) << "\n"
<< indent << "{\n"
).generate(sink, attributes::unused, inative_cxt))
return false;
@ -396,7 +407,7 @@ struct klass
).generate(sink, attributes::unused, inative_cxt))
return false;
if(!root)
if (!root || context_find_tag<class_context>(context).current_wrapper_kind != class_context::concrete)
if(!as_generator(indent << scope_tab << scope_tab << "descs.AddRange(base.GetEoOps(type));\n").generate(sink, attributes::unused, inative_cxt))
return false;
@ -492,6 +503,11 @@ struct klass
<< (*(scope_tab << scope_tab << constructor_invocation << "\n"))
<< scope_tab << scope_tab << "FinishInstantiation();\n"
<< scope_tab << "}\n\n"
<< scope_tab << "/// <summary>Constructor to be used when objects are expected to be constructed from native code.</summary>\n"
<< scope_tab << "/// <param name=\"ch\">Tag struct storing the native handle of the object being constructed.</param>\n"
<< scope_tab << "protected " << inherit_name << "(ConstructingHandle ch) : base(ch)\n"
<< scope_tab << "{\n"
<< scope_tab << "}\n\n"
<< scope_tab << "/// <summary>Initializes a new instance of the <see cref=\"" << inherit_name << "\"/> class.\n"
<< 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"
<< scope_tab << "/// <param name=\"raw\">The native pointer to be wrapped.</param>\n"

View File

@ -26,23 +26,26 @@ struct marshall_annotation_visitor_generate;
*/
struct marshall_type_generator
{
marshall_type_generator(bool is_return = false)
: is_return(is_return) {}
marshall_type_generator(bool is_return = false, bool is_special_subtype = false)
: is_return(is_return)
, is_special_subtype(is_special_subtype)
{}
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::type_def const& type, Context const& context) const
{
return type.original_type.visit(detail::marshall_type_visitor_generate<OutputIterator, Context>{sink, &context, type.c_type, false, is_return, type.is_ptr });
return type.original_type.visit(detail::marshall_type_visitor_generate<OutputIterator, Context>{sink, &context, type.c_type, false, is_return, type.is_ptr, is_special_subtype});
}
/* Some types may require a different conversion when they are in @out parameters. */
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const
{
return param.type.original_type.visit(detail::marshall_type_visitor_generate<OutputIterator, Context>{sink, &context, param.type.c_type
, param.direction != attributes::parameter_direction::in, false, param.type.is_ptr});
, param.direction != attributes::parameter_direction::in, false, param.type.is_ptr, is_special_subtype});
}
bool is_return;
bool is_special_subtype;
};
/*
@ -73,9 +76,9 @@ struct marshall_annotation_generator
struct marshall_type_terminal
{
marshall_type_generator const operator()(bool is_return) const
marshall_type_generator const operator()(bool is_return, bool is_special_subtype = false) const
{
return marshall_type_generator(is_return);
return marshall_type_generator(is_return, is_special_subtype);
}
} const marshall_type = {};

View File

@ -25,6 +25,7 @@ struct marshall_type_visitor_generate
bool is_out;
bool is_return;
bool is_ptr;
bool is_special_subtype;
typedef marshall_type_visitor_generate<OutputIterator, Context> visitor_type;
typedef bool result_type;
@ -70,12 +71,16 @@ struct marshall_type_visitor_generate
{
regular_type_def r = regular;
r.base_qualifier.qualifier ^= qualifier_info::is_ref;
if (is_special_subtype)
return replace_base_type(r, "Eina.StringShare");
return replace_base_type(r, "System.String");
}}
, {"stringshare", false, [&]
{
regular_type_def r = regular;
r.base_qualifier.qualifier ^= qualifier_info::is_ref;
if (is_special_subtype)
return replace_base_type(r, "Eina.StringShare");
return replace_base_type(r, "System.String");
}}
, {"strbuf", nullptr, [&]
@ -171,16 +176,16 @@ struct marshall_type_visitor_generate
regular_type_def r = regular;
r.base_type = "System.IntPtr";
r.namespaces.clear();
return visitor_generate<OutputIterator, Context>{sink, context, c_type, is_out, is_return, is_ptr}(r);
return visitor_generate<OutputIterator, Context>{sink, context, c_type, is_out, is_return, is_ptr, is_special_subtype}(r);
}
else
{
return visitor_generate<OutputIterator, Context>{sink, context, c_type, is_out, is_return, is_ptr}(regular);
return visitor_generate<OutputIterator, Context>{sink, context, c_type, is_out, is_return, is_ptr, is_special_subtype}(regular);
}
}
bool operator()(attributes::klass_name klass_name) const
{
return visitor_generate<OutputIterator, Context>{sink, context, c_type, is_out, is_return, is_ptr}(klass_name);
return visitor_generate<OutputIterator, Context>{sink, context, c_type, is_out, is_return, is_ptr, is_special_subtype}(klass_name);
}
bool operator()(attributes::complex_type_def const& complex) const
{
@ -225,7 +230,7 @@ struct marshall_type_visitor_generate
{
regular_type_def no_pointer_regular = complex.outer;
return visitor_type{sink, context, c_type, false}(no_pointer_regular)
&& as_generator("<" << (type % ", ") << ">").generate(sink, complex.subtypes, *context);
&& as_generator("<" << (type(false, false, true) % ", ") << ">").generate(sink, complex.subtypes, *context);
};
if(eina::optional<bool> b = call_match
@ -250,7 +255,7 @@ struct marshall_type_visitor_generate
return *b;
}
return visitor_generate<OutputIterator, Context>{sink, context, c_type, is_out, is_return, is_ptr}(complex);
return visitor_generate<OutputIterator, Context>{sink, context, c_type, is_out, is_return, is_ptr, is_special_subtype}(complex);
}
};
} }

View File

@ -14,29 +14,32 @@ struct visitor_generate;
struct type_generator
{
type_generator(bool is_return = false, bool is_optional = false)
: is_return(is_return), is_optional(is_optional) {}
type_generator(bool is_return = false, bool is_optional = false, bool is_special_subtype = false)
: is_return(is_return)
, is_optional(is_optional)
, is_special_subtype(is_special_subtype)
{}
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::type_def const& type, Context const& context) const
{
return type.original_type.visit(visitor_generate<OutputIterator, Context>{sink, &context, type.c_type, false, is_return, type.is_ptr, is_optional});
return type.original_type.visit(visitor_generate<OutputIterator, Context>{sink, &context, type.c_type, false, is_return, type.is_ptr, is_optional, is_special_subtype});
}
template <typename OutputIterator, typename Context>
bool generate(OutputIterator sink, attributes::parameter_def const& param, Context const& context) const
{
return param.type.original_type.visit(visitor_generate<OutputIterator, Context>{sink, &context, param.type.c_type
, param.direction != attributes::parameter_direction::in, false, param.type.is_ptr, is_optional});
, param.direction != attributes::parameter_direction::in, false, param.type.is_ptr, is_optional, is_special_subtype});
}
bool is_return, is_optional;
bool is_return, is_optional, is_special_subtype;
};
struct type_terminal
{
type_generator const operator()(bool is_return, bool is_optional = false) const
type_generator const operator()(bool is_return, bool is_optional = false, bool is_special_subtype = false) const
{
return type_generator(is_return, is_optional);
return type_generator(is_return, is_optional, is_special_subtype);
}
} const type = {};

View File

@ -99,6 +99,7 @@ struct visitor_generate
bool is_return;
bool is_ptr;
mutable bool is_optional;
bool is_special_subtype;
typedef visitor_generate<OutputIterator, Context> visitor_type;
typedef bool result_type;
@ -205,6 +206,8 @@ struct visitor_generate
{
regular_type_def r = regular;
r.base_qualifier.qualifier ^= qualifier_info::is_ref;
if (is_special_subtype)
return replace_base_type(r, "Eina.StringShare");
return replace_base_type(r, "System.String");
}}
, {"strbuf", nullptr, [&]
@ -400,7 +403,7 @@ struct visitor_generate
// if(is_out)
// pointers.push_back({{attributes::qualifier_info::is_none, {}}, true});
return visitor_type{sink, context, c_type, false}(no_pointer_regular)
&& as_generator("<" << (type % ", ") << ">").generate(sink, complex.subtypes, *context)
&& as_generator("<" << (type(false, false, true) % ", ") << ">").generate(sink, complex.subtypes, *context)
;
// && detail::generate_pointers(sink, pointers, *context, false);
};

View File

@ -88,7 +88,7 @@ public abstract class Application
/// <summary>
/// Called when the application is started. Arguments from the command line are passed here.
/// </summary>
protected abstract void OnInitialize(Eina.Array<System.String> args);
protected abstract void OnInitialize(string[] args);
/// <summary>
/// Arguments are passed here, Additional calls to this function may occure,
@ -130,8 +130,8 @@ public abstract class Application
{
Init(components);
Efl.App app = Efl.App.AppMain;
Eina.Array<String> command_line = new Eina.Array<String>();
command_line.Append(Environment.GetCommandLineArgs());
var command_line = new Eina.Array<Eina.StringShare>();
command_line.Append(Array.ConvertAll(Environment.GetCommandLineArgs(), s => (Eina.StringShare)s));
#if EFL_BETA
app.SetCommandArray(command_line);
#endif
@ -139,7 +139,14 @@ public abstract class Application
{
if (evt.arg.Initialization)
{
OnInitialize(evt.arg.Argv);
int n = evt.arg.Argv.Length;
var argv = new string[n];
for (int i = 0; i < n; ++i)
{
argv[i] = evt.arg.Argv[i];
}
OnInitialize(argv);
}
OnArguments(evt.arg);

View File

@ -41,6 +41,19 @@ internal static class NativeCustomExportFunctions
efl_mono_native_efl_unref_addr_get();
}
// TODO: move all native functions to a "NativeFunctions" class
internal static partial class NativeFunctions
{
[DllImport(efl.Libs.Eina)] public static extern IntPtr
eina_stringshare_add(string str);
[DllImport(efl.Libs.Eina)] public static extern void
eina_stringshare_del(IntPtr str);
[DllImport(efl.Libs.CustomExports)] public static extern void
efl_mono_native_stringshare_del_ref(IntPtr str);
[DllImport(efl.Libs.CustomExports)] public static extern IntPtr
efl_mono_native_stringshare_del_addr_get();
}
/// <summary>Wrapper around native memory DllImport'd functions</summary>
public static class MemoryNative
{
@ -75,6 +88,21 @@ public static class MemoryNative
return NativeCustomExportFunctions.efl_mono_native_strdup(str);
}
public static IntPtr AddStringShare(string str)
{
return NativeFunctions.eina_stringshare_add(str);
}
public static void DelStringShare(IntPtr str)
{
NativeFunctions.eina_stringshare_del(str);
}
public static void DelStringShareRef(IntPtr ptr)
{
NativeFunctions.efl_mono_native_stringshare_del_ref(ptr);
}
// IntPtr's for some native functions
public static IntPtr PtrCompareFuncPtrGet()
{
@ -91,6 +119,11 @@ public static class MemoryNative
return NativeCustomExportFunctions.efl_mono_native_free_addr_get();
}
public static IntPtr StringShareDelFuncPtrGet()
{
return NativeFunctions.efl_mono_native_stringshare_del_addr_get();
}
public static IntPtr EflUnrefFuncPtrGet()
{
return NativeCustomExportFunctions.efl_mono_native_efl_unref_addr_get();
@ -163,4 +196,121 @@ public enum Ownership
Unmanaged
}
/// TODO: reword this \/ \/ \/ \/ \/ \/ \/
/// Convert to a String the quickest possible.
/// Implements Equality/Inequality methods just because they have standard System.Object implementations that would not signal a compilation fail. The intent is not to provide full string API.
public class StringShare : IEquatable<StringShare>, IEquatable<string>
{
public StringShare()
{
}
public StringShare(string s)
{
Str = s;
}
public string Str { get; set; }
public static implicit operator string(StringShare ss)
{
if (ss == null)
{
return null;
}
return ss.Str;
}
public static implicit operator StringShare(string s)
{
if (s == null)
{
return null;
}
return new StringShare(s);
}
public static bool operator==(StringShare ss1, StringShare ss2)
{
return ((string)ss1) == ((string)ss2);
}
public static bool operator==(StringShare ss, string s)
{
return ((string)ss) == s;
}
public static bool operator==(string s, StringShare ss)
{
return ss == s;
}
public static bool operator!=(StringShare ss1, StringShare ss2)
{
return !(ss1 == ss2);
}
public static bool operator!=(StringShare ss, string s)
{
return !(ss == s);
}
public static bool operator!=(string s, StringShare ss)
{
return !(ss == s);
}
public override string ToString()
{
return Str;
}
public override int GetHashCode()
{
return Str == null ? 0 : Str.GetHashCode();
}
public override bool Equals(object other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
if (other.GetType() == typeof(string))
{
return this.Str == (string)other;
}
return other.GetType() == typeof(StringShare) && this == ((StringShare)other);
}
public bool Equals(StringShare other)
{
return this == other;
}
public bool Equals(string other)
{
return this.Str == other;
}
public void Set(string s)
{
Str = s;
}
public string Get()
{
return Str;
}
}
}

View File

@ -19,6 +19,7 @@ public enum ElementType
{
NumericType,
StringType,
StringShareType,
ObjectType
};
@ -195,6 +196,144 @@ public class StringElementTraits : IBaseElementTraits<string>
}
}
public class StringShareElementTraits : IBaseElementTraits<Eina.StringShare>
{
public StringShareElementTraits()
{
}
public IntPtr ManagedToNativeAlloc(Eina.StringShare man)
{
IntPtr newstring = MemoryNative.AddStringShare(man);
return newstring;
}
public IntPtr ManagedToNativeAllocInlistNode(Eina.StringShare man)
{
var node = new InlistNode<IntPtr>();
node.Val = ManagedToNativeAlloc(man);
GCHandle pinnedData = GCHandle.Alloc(node, GCHandleType.Pinned);
IntPtr ptr = pinnedData.AddrOfPinnedObject();
IntPtr nat = MemoryNative.AllocCopy(ptr, Marshal.SizeOf<InlistMem>() + Marshal.SizeOf<IntPtr>());
pinnedData.Free();
return nat;
}
public void ManagedToNativeCopyTo(Eina.StringShare man, IntPtr mem)
{
IntPtr stringptr = ManagedToNativeAlloc(man);
Marshal.WriteIntPtr(mem, stringptr);
}
public void NativeFree(IntPtr nat)
{
if (nat != IntPtr.Zero)
{
MemoryNative.DelStringShare(nat);
}
}
public void NativeFreeInlistNodeElement(IntPtr nat)
{
if (nat == IntPtr.Zero)
{
return;
}
var val = Marshal.PtrToStructure<IntPtr>
(nat + Marshal.SizeOf<InlistMem>());
NativeFree(val);
}
public void NativeFreeInlistNode(IntPtr nat, bool freeElement)
{
if (nat == IntPtr.Zero)
{
return;
}
if (freeElement)
{
NativeFreeInlistNodeElement(nat);
}
MemoryNative.Free(nat);
}
public void NativeFreeInplace(IntPtr nat)
{
MemoryNative.DelStringShareRef(nat);
}
public void ResidueFreeInplace(IntPtr nat)
{
}
public Eina.StringShare NativeToManaged(IntPtr nat)
{
if (nat == IntPtr.Zero)
{
return default(Eina.StringShare);
}
return StringConversion.NativeUtf8ToManagedString(nat);
}
public Eina.StringShare NativeToManagedInlistNode(IntPtr nat)
{
if (nat == IntPtr.Zero)
{
Eina.Log.Error("Null pointer for Inlist node.");
return default(Eina.StringShare);
}
IntPtr ptr_location = nat + Marshal.SizeOf<InlistMem>();
return NativeToManaged(Marshal.ReadIntPtr(ptr_location));
}
// Strings inplaced are always a pointer, because they are variable-sized
public Eina.StringShare NativeToManagedInplace(IntPtr nat)
{
if (nat == IntPtr.Zero)
{
return default(Eina.StringShare);
}
nat = Marshal.ReadIntPtr(nat);
if (nat == IntPtr.Zero)
{
return default(Eina.StringShare);
}
return NativeToManaged(nat);
}
public IntPtr EinaCompareCb()
{
return MemoryNative.StrCompareFuncPtrGet();
}
public IntPtr EinaFreeCb()
{
return MemoryNative.StringShareDelFuncPtrGet();
}
public IntPtr EinaHashNew()
{
return eina_hash_stringshared_new(IntPtr.Zero);
}
public IntPtr EinaInarrayNew(uint step)
{
return eina_inarray_new((uint)Marshal.SizeOf<IntPtr>(), step);
}
public IntPtr EinaHashIteratorKeyNew(IntPtr hash)
{
return eina_hash_iterator_key_new(hash);
}
}
public class EflObjectElementTraits<T> : IBaseElementTraits<T>
{
public IntPtr ManagedToNativeAlloc(T man)
@ -709,6 +848,11 @@ public static class TraitFunctions
return type == typeof(string);
}
public static bool IsStringShare(System.Type type)
{
return type == typeof(Eina.StringShare);
}
public static Eina.ElementType GetElementTypeCode(System.Type type)
{
if (IsEflObject(type))
@ -719,6 +863,10 @@ public static class TraitFunctions
{
return ElementType.StringType;
}
else if (IsStringShare(type))
{
return ElementType.StringShareType;
}
else
{
return ElementType.NumericType;
@ -764,6 +912,10 @@ public static class TraitFunctions
{
traits = new StringElementTraits();
}
else if (IsStringShare(type))
{
traits = new StringShareElementTraits();
}
else if (type.IsValueType)
{
if (type == typeof(int))

View File

@ -2,6 +2,7 @@ using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Reflection;
namespace Efl
{
@ -9,15 +10,85 @@ namespace Efl
namespace Eo
{
#if EFL_DEBUG
public class SafeIntPtr
{
private IntPtr handle;
private bool disposed;
private SafeIntPtr(IntPtr ptr)
{
handle = ptr;
}
public static implicit operator IntPtr(SafeIntPtr ptr)
{
if (ptr.disposed)
{
throw new ObjectDisposedException("Object has been disposed");
}
return ptr.handle;
}
public static implicit operator SafeIntPtr(IntPtr ptr)
{
return new SafeIntPtr(ptr);
}
public void Dispose()
{
disposed = true;
handle = IntPtr.Zero;
}
public long ToInt64()
{
return handle.ToInt64();
}
}
#endif
public abstract class EoWrapper : IWrapper, IDisposable
{
protected readonly object eventLock = new object();
protected bool inherited = false;
protected System.IntPtr handle = IntPtr.Zero;
#if EFL_DEBUG
protected SafeIntPtr handle;
#else
protected IntPtr handle;
#endif
private static Efl.EventCb ownershipUniqueDelegate = new Efl.EventCb(OwnershipUniqueCallback);
private static Efl.EventCb ownershipSharedDelegate = new Efl.EventCb(OwnershipSharedCallback);
/// <summary>Constructor to be used when objects are expected to be constructed from native code.
/// For a class that inherited from an EFL# class to be properly constructed from native code
/// one must create a constructor with this signature and calls this base constructor from it.
/// This constructor will take care of calling base constructors of the native classes and
/// perform additional setup so objects are ready to use.
/// It is advisable to check for the <see cref="NativeHandle"/> property in the top level
/// constructor and signal an error when it has a value of IntPtr.Zero after this
/// constructor completion.
/// Warning: Do not use this constructor directly from a `new` statement.</summary>
/// <param name="ch">Tag struct storing the native handle of the object being constructed.</param>
protected EoWrapper(ConstructingHandle ch)
{
handle = Efl.Eo.Globals.efl_constructor(Efl.Eo.Globals.efl_super(ch.NativeHandle, Efl.Eo.Globals.efl_class_get(ch.NativeHandle)));
if (handle == IntPtr.Zero)
{
Eina.Log.Warning("Natice constructor returned NULL");
return;
}
AddWrapperSupervisor();
// Make an additional reference to C#
// - Will also call EVENT_OWNERSHIP_SHARED
Efl.Eo.Globals.efl_ref(handle);
}
/// <summary>Initializes a new instance of the <see cref="Object"/> class.
/// Internal usage: Constructs an instance from a native pointer. This is used when interacting with C code and should not be used directly.</summary>
/// <param name="raw">The native pointer to be wrapped.</param>
@ -54,7 +125,17 @@ public abstract class EoWrapper : IWrapper, IDisposable
parent_ptr = parent.NativeHandle;
}
handle = Efl.Eo.Globals._efl_add_internal_start(file, line, actual_klass, parent_ptr, 1, 0);
if (!inherited)
{
handle = Efl.Eo.Globals._efl_add_internal_start(file, line, actual_klass, parent_ptr, 1, 0);
}
else
{
handle = Efl.Eo.Globals._efl_add_internal_start_bindings(file, line, actual_klass, parent_ptr, 1, 0,
Efl.Eo.Globals.efl_mono_avoid_top_level_constructor_callback_addr_get(),
IntPtr.Zero);
}
if (handle == System.IntPtr.Zero)
{
throw new Exception("Instantiation failed");
@ -91,7 +172,11 @@ public abstract class EoWrapper : IWrapper, IDisposable
if (disposing && handle != System.IntPtr.Zero)
{
IntPtr h = handle;
#if EFL_DEBUG
handle.Dispose();
#else
handle = IntPtr.Zero;
#endif
Efl.Eo.Globals.efl_mono_native_dispose(h);
}
else
@ -103,6 +188,9 @@ public abstract class EoWrapper : IWrapper, IDisposable
}
Monitor.Exit(Efl.All.InitLock);
#if EFL_DEBUG
handle.Dispose();
#endif
}
}
@ -110,7 +198,7 @@ public abstract class EoWrapper : IWrapper, IDisposable
/// <returns>A string with the type and the native pointer for this object.</returns>
public override String ToString()
{
return $"{this.GetType().Name}@[0x{(UInt64)handle:x}]";
return $"{this.GetType().Name}@[0x{handle.ToInt64():x}]";
}
/// <summary>Releases the underlying native instance.</summary>
@ -246,8 +334,72 @@ public abstract class EoWrapper : IWrapper, IDisposable
AddNativeEventHandler("eo", "_EFL_EVENT_OWNERSHIP_SHARED", ownershipSharedDelegate, ownershipSharedDelegate);
Eina.Error.RaiseIfUnhandledException();
}
protected struct ConstructingHandle
{
public ConstructingHandle(IntPtr h)
{
NativeHandle = h;
}
public IntPtr NativeHandle { get; set; }
}
public abstract class NativeMethods : Efl.Eo.NativeClass
{
private static EflConstructorSelegate csharpEflConstructorStaticDelegate = new EflConstructorSelegate(Constructor);
private static Efl.Eo.NativeModule EoModule = new Efl.Eo.NativeModule("eo");
private delegate IntPtr EflConstructorSelegate(IntPtr obj, IntPtr pd);
public override System.Collections.Generic.List<Efl_Op_Description> GetEoOps(Type type)
{
var descs = new System.Collections.Generic.List<Efl_Op_Description>();
descs.Add(new Efl_Op_Description()
{
api_func = Efl.Eo.FunctionInterop.LoadFunctionPointer(EoModule.Module, "efl_constructor"),
func = Marshal.GetFunctionPointerForDelegate(csharpEflConstructorStaticDelegate)
});
return descs;
}
private static IntPtr Constructor(IntPtr obj, IntPtr pd)
{
try
{
var eoKlass = Efl.Eo.Globals.efl_class_get(obj);
var managedType = ClassRegister.GetManagedType(eoKlass);
if (managedType == null)
{
IntPtr nativeName = Efl.Eo.Globals.efl_class_name_get(eoKlass);
var name = Eina.StringConversion.NativeUtf8ToManagedString(nativeName);
Eina.Log.Warning($"Can't get Managed class for object handle 0x{(UInt64)obj:x} with native class [{name}]");
return IntPtr.Zero;
}
var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
ConstructorInfo constructor = managedType.GetConstructor(flags, null, new Type[1] { typeof(ConstructingHandle) }, null);
var eoWrapper = (Efl.Eo.IWrapper) constructor.Invoke(new object[1] { new ConstructingHandle(obj) });
if (eoWrapper == null)
{
Eina.Log.Warning("Constructor was unable to create a new object");
return IntPtr.Zero;
}
return eoWrapper.NativeHandle;
}
catch (Exception e)
{
Eina.Log.Warning($"Inherited constructor error: {e.ToString()}");
Eina.Error.Set(Eina.Error.UNHANDLED_EXCEPTION);
return IntPtr.Zero;
}
}
}
}
} // namespace Global
} // namespace Eo
} // namespace Efl

View File

@ -44,10 +44,6 @@ public class Globals
public static FunctionWrapper<efl_object_shutdown_delegate> efl_object_shutdown_ptr = new FunctionWrapper<efl_object_shutdown_delegate>(efl.Libs.EoModule, "efl_object_shutdown");
public static void efl_object_shutdown() => efl_object_shutdown_ptr.Value.Delegate();
// [DllImport(efl.Libs.Eo)] public static extern void efl_object_shutdown();
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");
public delegate IntPtr
_efl_add_internal_start_delegate([MarshalAs(UnmanagedType.LPStr)] String file, int line,
IntPtr klass, IntPtr parent, byte is_ref, byte is_fallback);
[DllImport(efl.Libs.CustomExports)] public static extern IntPtr efl_mono_wrapper_supervisor_get(IntPtr eo);
[DllImport(efl.Libs.CustomExports)] public static extern void efl_mono_wrapper_supervisor_set(IntPtr eo, IntPtr ws);
@ -55,6 +51,9 @@ public class Globals
[DllImport(efl.Libs.Eo)] public static extern IntPtr
_efl_add_internal_start([MarshalAs(UnmanagedType.LPStr)] String file, int line,
IntPtr klass, IntPtr parent, byte is_ref, byte is_fallback);
[DllImport(efl.Libs.Eo)] public static extern IntPtr
_efl_add_internal_start_bindings([MarshalAs(UnmanagedType.LPStr)] String file, int line, IntPtr klass, IntPtr parent,
byte is_ref, byte is_fallback, IntPtr substitute_ctor, IntPtr data);
public delegate IntPtr
_efl_add_end_delegate(IntPtr eo, byte is_ref, byte is_fallback);
[DllImport(efl.Libs.Eo)] public static extern IntPtr
@ -196,6 +195,10 @@ public class Globals
public delegate IntPtr dlerror_delegate();
[DllImport(efl.Libs.Evil)] public static extern IntPtr dlerror();
[DllImport(efl.Libs.Eo)] public static extern IntPtr efl_constructor(IntPtr obj);
[DllImport(efl.Libs.CustomExports)] public static extern IntPtr efl_mono_avoid_top_level_constructor_callback_addr_get();
[DllImport(efl.Libs.Eo)] [return: MarshalAs(UnmanagedType.U1)] public static extern bool
efl_event_callback_priority_add(IntPtr obj, IntPtr desc, short priority, IntPtr cb, IntPtr data);

View File

@ -148,6 +148,10 @@ if get_option('mono-beta')
extra_cs_args += '-d:EFL_BETA'
endif
if get_option('buildtype') == 'debug'
extra_cs_args += '-d:EFL_DEBUG'
endif
efl_mono_install_dir = join_paths(dir_lib, 'efl-mono-'+version_major)
efl_mono_xml_doc = join_paths(meson.current_build_dir(), 'efl_mono.xml')

View File

@ -125,6 +125,12 @@ EAPI void efl_mono_native_free_ref(void **ptr)
free(*ptr);
}
EAPI void efl_mono_native_stringshare_del_ref(void **str)
{
if (!str) return;
eina_stringshare_del(*str);
}
EAPI void *efl_mono_native_alloc_copy(const void *val, unsigned int size)
{
if (!val) return NULL;
@ -161,11 +167,26 @@ EAPI Eina_Free_Cb efl_mono_native_free_addr_get()
return (Eina_Free_Cb)free;
}
EAPI Eina_Free_Cb efl_mono_native_stringshare_del_addr_get()
{
return (Eina_Free_Cb)eina_stringshare_del;
}
EAPI Eina_Free_Cb efl_mono_native_efl_unref_addr_get()
{
return (Eina_Free_Cb)efl_mono_thread_safe_efl_unref;
}
static Eo *_efl_mono_avoid_top_level_constructor_cb(void *data EINA_UNUSED, Eo *obj)
{
return efl_constructor(efl_super(obj, efl_class_get(obj)));
}
EAPI Efl_Substitute_Ctor_Cb efl_mono_avoid_top_level_constructor_callback_addr_get()
{
return &_efl_mono_avoid_top_level_constructor_cb;
}
// Iterator Wrapper //
typedef struct _Eina_Iterator_Wrapper_Mono

View File

@ -1539,6 +1539,35 @@ EAPI Eo *_efl_added_get(void);
EAPI Eo * _efl_add_internal_start(const char *file, int line, const Efl_Class *klass_id, Eo *parent, Eina_Bool ref, Eina_Bool is_fallback);
/**
* @typedef Efl_Substitute_Ctor_Cb
* Callback to be called instead of the object constructor.
*
* Only intended for binding creators.
*
* @param data Additional data previously supplied by the user
* @param obj_id The object being constructed.
* @return The constructed object in case of success, NULL otherwise.
*/
typedef Eo *(*Efl_Substitute_Ctor_Cb)(void *data, Eo *obj_id);
/**
* @brief Just like _efl_add_internal_start() but with additional options
*
* Only intended for binding creators.
*
* @param file File name of the call site, used for debug logs.
* @param line Line number of the call site, used for debug logs.
* @param klass_id Pointer for the class being instantiated.
* @param ref Whether or not the object will have an additional reference if it has a parent.
* @param parent Object parent, can be NULL.
* @param is_fallback Whether or not the fallback @c efl_added behaviour is to be used.
* @param substitute_ctor Optional callback to replace the call for efl_constructor(), if NULL efl_constructor() will be called normally.
* @param sub_ctor_data Additional data to be passed to the @p substitute_ctor callback.
* @return An handle to the new object on success, NULL otherwise.
*/
EAPI Eo * _efl_add_internal_start_bindings(const char *file, int line, const Efl_Class *klass_id, Eo *parent, Eina_Bool ref, Eina_Bool is_fallback, Efl_Substitute_Ctor_Cb substitute_ctor, void *sub_ctor_data);
/**
* @brief Unrefs the object and reparents it to NULL.
*

View File

@ -857,8 +857,8 @@ err_klass:
return EINA_FALSE;
}
EAPI Eo *
_efl_add_internal_start(const char *file, int line, const Efl_Class *klass_id, Eo *parent_id, Eina_Bool ref, Eina_Bool is_fallback)
static Eo *
_efl_add_internal_start_do(const char *file, int line, const Efl_Class *klass_id, Eo *parent_id, Eina_Bool ref, Eina_Bool is_fallback, Efl_Substitute_Ctor_Cb substitute_ctor, void *sub_ctor_data)
{
const char *func_name = __FUNCTION__;
_Eo_Object *obj;
@ -918,7 +918,8 @@ _efl_add_internal_start(const char *file, int line, const Efl_Class *klass_id, E
if (parent_id) efl_parent_set(eo_id, parent_id);
/* eo_id can change here. Freeing is done on the resolved object. */
eo_id = efl_constructor(eo_id);
if (!substitute_ctor) eo_id = efl_constructor(eo_id);
else eo_id = substitute_ctor(sub_ctor_data, eo_id);
// not likely so use goto to alleviate l1 instruction cache of rare code
if (!eo_id) goto err_noid;
// not likely so use goto to alleviate l1 instruction cache of rare code
@ -962,6 +963,17 @@ err_parent:
return NULL;
}
EAPI Eo *
_efl_add_internal_start(const char *file, int line, const Efl_Class *klass_id, Eo *parent_id, Eina_Bool ref, Eina_Bool is_fallback)
{
return _efl_add_internal_start_do(file, line, klass_id, parent_id, ref, is_fallback, NULL, NULL);
}
EAPI Eo * _efl_add_internal_start_bindings(const char *file, int line, const Efl_Class *klass_id, Eo *parent_id, Eina_Bool ref, Eina_Bool is_fallback, Efl_Substitute_Ctor_Cb substitute_ctor, void *sub_ctor_data)
{
return _efl_add_internal_start_do(file, line, klass_id, parent_id, ref, is_fallback, substitute_ctor, sub_ctor_data);
}
static Eo *
_efl_add_internal_end(Eo *eo_id, Eo *finalized_id)
{

View File

@ -492,6 +492,14 @@ class TestEinaArray
Test.AssertEquals("test string §éΨبÿツ", a[0]);
}
public static void push_stringshare()
{
var a = new Eina.Array<Eina.StringShare>();
Test.Assert(a.Handle != IntPtr.Zero);
Test.Assert(a.Push("test string §éΨبÿツ"));
Test.AssertEquals("test string §éΨبÿツ", a[0].Str);
}
public static void push_obj()
{
var a = new Eina.Array<Dummy.Numberwrapper>();
@ -521,6 +529,15 @@ class TestEinaArray
Test.Assert(a.Count() == 0);
}
public static void pop_stringshare()
{
var a = new Eina.Array<Eina.StringShare>();
Test.Assert(a.Handle != IntPtr.Zero);
Test.Assert(a.Push("test string"));
Test.Assert(a.Pop() == "test string");
Test.Assert(a.Count() == 0);
}
public static void pop_obj()
{
var a = new Eina.Array<Dummy.Numberwrapper>();
@ -558,6 +575,18 @@ class TestEinaArray
Test.Assert(a[0] == "abc");
}
public static void data_set_stringshare()
{
var a = new Eina.Array<Eina.StringShare>();
Test.Assert(a.Handle != IntPtr.Zero);
Test.Assert(a.Push("test string"));
Test.Assert(a[0] == "test string");
a.DataSet(0, "other string");
Test.Assert(a[0] == "other string");
a[0] = "abc";
Test.Assert(a[0] == "abc");
}
public static void data_set_obj()
{
var a = new Eina.Array<Dummy.Numberwrapper>();
@ -617,6 +646,22 @@ class TestEinaArray
Test.Assert(a.Count() == 3);
}
public static void count_stringshare()
{
var a = new Eina.Array<Eina.StringShare>();
Test.Assert(a.Handle != IntPtr.Zero);
Test.Assert(a.Count() == 0);
Test.Assert(a.Push("a"));
Test.Assert(a[0] == "a");
Test.Assert(a.Count() == 1);
Test.Assert(a.Push("b"));
Test.Assert(a[1] == "b");
Test.Assert(a.Count() == 2);
Test.Assert(a.Push("c"));
Test.Assert(a[2] == "c");
Test.Assert(a.Count() == 3);
}
public static void count_obj()
{
var a = new Eina.Array<Dummy.Numberwrapper>();
@ -678,6 +723,22 @@ class TestEinaArray
Test.Assert(a.Length == 3);
}
public static void length_stringshare()
{
var a = new Eina.Array<Eina.Stringshare>();
Test.Assert(a.Handle != IntPtr.Zero);
Test.Assert(a.Length == 0);
Test.Assert(a.Push("a"));
Test.Assert(a[0] == "a");
Test.Assert(a.Length == 1);
Test.Assert(a.Push("b"));
Test.Assert(a[1] == "b");
Test.Assert(a.Length == 2);
Test.Assert(a.Push("c"));
Test.Assert(a[2] == "c");
Test.Assert(a.Length == 3);
}
public static void eina_array_as_ienumerable_int()
{
var a = new Eina.Array<int>();
@ -710,6 +771,22 @@ class TestEinaArray
}
}
public static void eina_array_as_ienumerable_stringshare()
{
var a = new Eina.Array<Eina.StringShare>();
Test.Assert(a.Handle != IntPtr.Zero);
Test.Assert(a.Push("X"));
Test.Assert(a.Push("XX"));
Test.Assert(a.Push("XXX"));
string cmp = "X";
foreach (string e in a)
{
Test.AssertEquals(cmp, e);
cmp = cmp + "X";
}
}
public static void eina_array_as_ienumerable_obj()
{
var a = new Dummy.Numberwrapper();
@ -888,6 +965,80 @@ class TestEinaArray
Test.Assert(arr.Handle == IntPtr.Zero);
}
// Eina.Stringshare //
public static void test_eina_array_strshare_in()
{
var t = new Dummy.TestObject();
var arr = new Eina.Array<Eina.StringShare>();
arr.Append(base_seq_str);
Test.Assert(t.EinaArrayStrShareIn(arr));
Test.Assert(arr.Own);
Test.Assert(arr.ToArray().SequenceEqual(modified_seq_str));
arr.Dispose();
Test.Assert(arr.Handle == IntPtr.Zero);
}
public static void test_eina_array_strshare_in_own()
{
var t = new Dummy.TestObject();
var arr = new Eina.Array<Eina.StringShare>();
arr.Append(base_seq_str);
Test.Assert(t.EinaArrayStrShareInOwn(arr));
Test.Assert(!arr.Own);
Test.Assert(arr.ToArray().SequenceEqual(modified_seq_str));
arr.Dispose();
Test.Assert(arr.Handle == IntPtr.Zero);
Test.Assert(t.CheckEinaArrayStrShareInOwn());
}
public static void test_eina_array_strshare_out()
{
var t = new Dummy.TestObject();
Eina.Array<Eina.StringShare> arr;
Test.Assert(t.EinaArrayStrShareOut(out arr));
Test.Assert(!arr.Own);
Test.Assert(arr.ToArray().SequenceEqual(base_seq_str));
Test.Assert(arr.Append(append_seq_str));
arr.Dispose();
Test.Assert(arr.Handle == IntPtr.Zero);
Test.Assert(t.CheckEinaArrayStrShareOut());
}
public static void test_eina_array_strshare_out_own()
{
var t = new Dummy.TestObject();
Eina.Array<Eina.StringShare> arr;
Test.Assert(t.EinaArrayStrShareOutOwn(out arr));
Test.Assert(arr.Own);
Test.Assert(arr.ToArray().SequenceEqual(base_seq_str));
Test.Assert(arr.Append(append_seq_str));
arr.Dispose();
Test.Assert(arr.Handle == IntPtr.Zero);
}
public static void test_eina_array_strshare_return()
{
var t = new Dummy.TestObject();
var arr = t.EinaArrayStrShareReturn();
Test.Assert(!arr.Own);
Test.Assert(arr.ToArray().SequenceEqual(base_seq_str));
Test.Assert(arr.Append(append_seq_str));
arr.Dispose();
Test.Assert(arr.Handle == IntPtr.Zero);
Test.Assert(t.CheckEinaArrayStrShareReturn());
}
public static void test_eina_array_strshare_return_own()
{
var t = new Dummy.TestObject();
var arr = t.EinaArrayStrShareReturnOwn();
Test.Assert(arr.Own);
Test.Assert(arr.ToArray().SequenceEqual(base_seq_str));
Test.Assert(arr.Append(append_seq_str));
arr.Dispose();
Test.Assert(arr.Handle == IntPtr.Zero);
}
// Object //
public static void test_eina_array_obj_in()

View File

@ -522,6 +522,10 @@ class TestObjectDeletion
part.Del();
Test.AssertNull(obj.OnePart);
#if EFL_DEBUG
Test.AssertRaises<ObjectDisposedException>(() => part.SetParent(null));
#endif
}
}

View File

@ -0,0 +1,79 @@
using System;
class InheritedConstructibleObject : Dummy.ConstructibleObject
{
public InheritedConstructibleObject()
{
if (this.NativeConstructionCount != 1)
{
DefaultConstrutorCallCount = -100;
}
++DefaultConstrutorCallCount;
this.IncrementDefaultConstructionCount();
}
private InheritedConstructibleObject(ConstructingHandle ch) : base(ch)
{
if (this.NativeConstructionCount != 1)
{
SpecialConstrutorCallCount = -100;
}
++SpecialConstrutorCallCount;
this.IncrementSpecialConstructionCount();
}
public int DefaultConstrutorCallCount { get; set; } = 0;
public int SpecialConstrutorCallCount { get; set; } = 0;
}
namespace TestSuite
{
class TestEoConstruction
{
public static void TestGeneratedEoDirectConstruction()
{
var obj = new Dummy.ConstructibleObject();
Test.AssertEquals(obj.NativeConstructionCount, 1);
Test.AssertEquals(obj.DefaultConstructionCount, 0);
Test.AssertEquals(obj.SpecialConstructionCount, 0);
obj.Dispose();
}
public static void TestInheritedEoDirectConstruction()
{
var obj = new InheritedConstructibleObject();
Test.AssertEquals(obj.NativeConstructionCount, 1);
Test.AssertEquals(obj.DefaultConstructionCount, 1);
Test.AssertEquals(obj.SpecialConstructionCount, 0);
Test.AssertEquals(obj.DefaultConstrutorCallCount, 1);
Test.AssertEquals(obj.SpecialConstrutorCallCount, 0);
obj.Dispose();
}
public static void TestInheritedEoIndirectConstruction()
{
var obj = new Dummy.ConstructibleObject();
Test.AssertEquals(obj.NativeConstructionCount, 1);
Test.AssertEquals(obj.DefaultConstructionCount, 0);
Test.AssertEquals(obj.SpecialConstructionCount, 0);
var obj2 = (InheritedConstructibleObject) obj.ConstructTypeAndStore(typeof(InheritedConstructibleObject));
Test.AssertEquals(obj2.NativeConstructionCount, 1);
Test.AssertEquals(obj2.DefaultConstructionCount, 0);
Test.AssertEquals(obj2.SpecialConstructionCount, 1);
Test.AssertEquals(obj2.DefaultConstrutorCallCount, 0);
Test.AssertEquals(obj2.SpecialConstrutorCallCount, 1);
var internalObj = obj.InternalObject;
Test.Assert(obj2 == internalObj); // Ensure it always use the same object instance
Test.AssertEquals(obj2.NativeConstructionCount, 1); // And that constructors are not called again
obj.Dispose();
obj2.Dispose();
}
}
}

View File

@ -0,0 +1,70 @@
#include "libefl_mono_native_test.h"
typedef struct _Dummy_Constructible_Object_Data
{
Eo *internal_obj;
int native_construction_count;
int default_construction_count;
int special_construction_count;
} Dummy_Constructible_Object_Data;
EOLIAN static Eo *
_dummy_constructible_object_efl_object_constructor(Eo *obj, Dummy_Constructible_Object_Data *pd)
{
++(pd->native_construction_count);
return efl_constructor(efl_super(obj, DUMMY_CONSTRUCTIBLE_OBJECT_CLASS));
}
EOLIAN static void
_dummy_constructible_object_efl_object_destructor(Eo *obj, Dummy_Constructible_Object_Data *pd)
{
if (pd->internal_obj)
efl_unref(pd->internal_obj);
efl_destructor(efl_super(obj, DUMMY_CONSTRUCTIBLE_OBJECT_CLASS));
}
EOLIAN static Efl_Object *
_dummy_constructible_object_construct_type_and_store(Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd, const Efl_Class *klass)
{
pd->internal_obj = efl_add_ref(klass, NULL);
return pd->internal_obj;
}
EOLIAN static void
_dummy_constructible_object_increment_default_construction_count(Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
{
++(pd->default_construction_count);
}
EOLIAN static void
_dummy_constructible_object_increment_special_construction_count(Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
{
++(pd->special_construction_count);
}
EOLIAN static int
_dummy_constructible_object_native_construction_count_get(const Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
{
return pd->native_construction_count;
}
EOLIAN static int
_dummy_constructible_object_default_construction_count_get(const Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
{
return pd->default_construction_count;
}
EOLIAN static int
_dummy_constructible_object_special_construction_count_get(const Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
{
return pd->special_construction_count;
}
EOLIAN static Efl_Object *
_dummy_constructible_object_internal_object_get(const Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
{
return pd->internal_obj;
}
#include "dummy_constructible_object.eo.c"

View File

@ -0,0 +1,47 @@
class Dummy.Constructible_Object extends Efl.Object {
methods {
construct_type_and_store {
params {
@in type: const(Efl.Class);
}
return: Efl.Object;
}
increment_default_construction_count {
}
increment_special_construction_count {
}
@property native_construction_count {
get {
}
values {
value: int;
}
}
@property default_construction_count {
get {
}
values {
value: int;
}
}
@property special_construction_count {
get {
}
values {
value: int;
}
}
@property internal_object {
get {
}
values {
value: Efl.Object;
}
}
}
implements {
Efl.Object.constructor;
Efl.Object.destructor;
}
}

View File

@ -56,9 +56,9 @@ Dummy_Numberwrapper **_new_obj_ref(int n)
return &r;
}
// ############ //
// Test.Testing //
// ############ //
// ################# //
// Dummy.Test_Object //
// ################# //
static Efl_Object*
_dummy_test_object_efl_object_constructor(Eo *obj, Dummy_Test_Object_Data *pd)

View File

@ -55,6 +55,7 @@
#include "dummy_inherit_helper.eo.h"
#include "dummy_part_holder.eo.h"
#include "dummy_event_manager.eo.h"
#include "dummy_constructible_object.eo.h"
#include <interfaces/efl_part.eo.h>

View File

@ -7,6 +7,7 @@ eo_files = [
'dummy_inherit_iface.eo',
'dummy_part_holder.eo',
'dummy_event_manager.eo',
'dummy_constructible_object.eo',
]
eo_file_targets = []
@ -33,6 +34,7 @@ efl_mono_native_test = library('efl_mono_native_test',
'dummy_part_holder.c',
'dummy_test_object.c',
'dummy_event_manager.c',
'dummy_constructible_object.c',
],
dependencies : [ecore, eo, efl],
)
@ -65,6 +67,7 @@ efl_mono_src = [
'Eldbus.cs',
'Eo.cs',
'EoPromises.cs',
'EoConstruction.cs',
'Errors.cs',
'Events.cs',
'FunctionPointers.cs',