csharp: Add marshal support for Eina.ValueType
authorLauro Moura <lauromoura@expertisesolutions.com.br>
Tue, 30 Jul 2019 14:05:26 +0000 (11:05 -0300)
committerWooHyun Jung <wh0705.jung@samsung.com>
Mon, 5 Aug 2019 01:48:36 +0000 (10:48 +0900)
Summary:
It uses a custom marshaler and a helper boxing class to convert between
the managed enum values and the native Eina_Value_Type pointers.

To be used by future MVVM machinery.

Reviewers: vitor.sousa, felipealmeida

Reviewed By: vitor.sousa

Subscribers: cedric, #reviewers, #committers

Tags: #efl

Differential Revision: https://phab.enlightenment.org/D9443

src/bin/eolian_mono/eolian/mono/marshall_annotation.hh
src/bin/eolian_mono/eolian/mono/marshall_type_impl.hh
src/bindings/mono/eina_mono/eina_value.cs
src/lib/efl_mono/efl_custom_exports_mono.c
src/tests/efl_mono/ValueEolian.cs
src/tests/efl_mono/dummy_test_object.c
src/tests/efl_mono/dummy_test_object.eo

index 632696d..6d56b24 100644 (file)
@@ -82,6 +82,9 @@ struct marshall_annotation_visitor_generate
           {"strbuf", false, [&] {
                 return "[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StrbufKeepOwnershipMarshaler))]";
           }},
+          {"Value_Type", false, [&] {
+                return "[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Eina.ValueTypeMarshaler))]";
+          }},
         };
       match const return_match_table[] =
         {
@@ -117,6 +120,9 @@ struct marshall_annotation_visitor_generate
           {"strbuf", false, [&] {
                 return "[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Efl.Eo.StrbufKeepOwnershipMarshaler))]";
           }},
+          {"Value_Type", false, [&] {
+                return "[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(Eina.ValueTypeMarshaler))]";
+          }},
         };
 
         if(eina::optional<bool> b = call_annotation_match
index 8de109e..588e8c2 100644 (file)
@@ -161,6 +161,13 @@ struct marshall_type_visitor_generate
                     r.base_type = "void";
                 return r;
                }}
+           , {"Value_Type", nullptr, [&]
+               {
+                regular_type_def r = regular;
+                r.namespaces.clear();
+                r.base_type = "Eina.ValueTypeBox";
+                return r;
+               }}
         };
 
         if (regular.is_struct() && !blacklist::is_struct_blacklisted(regular) && !(bool)(regular.base_qualifier & qualifier_info::is_own))
index cedf500..57a6157 100644 (file)
@@ -3,6 +3,7 @@
 #define CODE_ANALYSIS
 
 using System;
+using System.ComponentModel;
 using System.Linq;
 using System.Runtime.InteropServices;
 using System.Collections.Generic;
@@ -515,6 +516,8 @@ static internal class UnsafeNativeMethods
     internal static extern IntPtr type_array();
     [DllImport(efl.Libs.CustomExports)]
     internal static extern IntPtr type_list();
+    [DllImport(efl.Libs.CustomExports)]
+    internal static extern IntPtr type_hash();
 
     // Optional
     [DllImport(efl.Libs.CustomExports)]
@@ -716,6 +719,39 @@ static class ValueTypeMethods
     }
 }
 
+/// <summary>Boxing class for custom marshalling of ValueType enums.
+///
+/// <para>As custom marshalling of enums (and other value types) is not supported, use
+/// use this boxing class as an intermediate at the Marshalling API level (like in
+/// marshall_type_impl.hh in the generator). User-facing API still uses Eina.ValueType
+/// normally.</para>
+/// </summary>
+[EditorBrowsable(EditorBrowsableState.Never)]
+public class ValueTypeBox
+{
+    public ValueType _payload;
+
+    public ValueTypeBox(ValueType v)
+    {
+        _payload = v;
+    }
+
+    public static implicit operator ValueTypeBox(ValueType v)
+    {
+        return new ValueTypeBox(v);
+    }
+
+    public static implicit operator ValueType(ValueTypeBox box)
+    {
+        if (box == null)
+        {
+            return Eina.ValueType.Empty;
+        }
+
+        return box._payload;
+    }
+}
+
 static class ValueTypeBridge
 {
     private static Dictionary<ValueType, IntPtr> ManagedToNative = new Dictionary<ValueType, IntPtr>();
@@ -860,6 +896,9 @@ static class ValueTypeBridge
         ManagedToNative.Add(ValueType.List, type_list());
         NativeToManaged.Add(type_list(), ValueType.List);
 
+        ManagedToNative.Add(ValueType.Hash, type_hash());
+        NativeToManaged.Add(type_hash(), ValueType.Hash);
+
         ManagedToNative.Add(ValueType.Optional, type_optional());
         NativeToManaged.Add(type_optional(), ValueType.Optional);
 
@@ -2898,6 +2937,7 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
 
 /// <summary> Custom marshaler to convert value pointers to managed values and back,
 /// without changing ownership.</summary>
+[EditorBrowsable(EditorBrowsableState.Never)]
 public class ValueMarshaler : ICustomMarshaler
 {
     /// <summary>Creates a managed value from a C pointer, whitout taking ownership of it.</summary>
@@ -3000,4 +3040,49 @@ public class ValueMarshalerOwn : ICustomMarshaler
     static private ValueMarshalerOwn marshaler;
 }
 
+/// <summary> Custom marshaler to convert value type pointers to managed boxed enum values
+/// and back.</summary>
+public class ValueTypeMarshaler : ICustomMarshaler
+{
+    /// <summary>Creates a boxed ValueType enum value from a C pointer.</summary>
+    public object MarshalNativeToManaged(IntPtr pNativeData)
+    {
+        var r = ValueTypeBridge.GetManaged(pNativeData);
+        return new ValueTypeBox(r);
+    }
+    public static Eina.ValueType vtype;
+
+    /// <summary>Retrieves the C pointer from a given boxed enum value type.</summary>
+    public IntPtr MarshalManagedToNative(object managedObj)
+    {
+        ValueTypeBox v = (ValueTypeBox)managedObj;
+        return ValueTypeBridge.GetNative(v);
+    }
+
+    public void CleanUpNativeData(IntPtr pNativeData)
+    {
+    }
+
+    public void CleanUpManagedData(object managedObj)
+    {
+    }
+
+    public int GetNativeDataSize()
+    {
+        return -1;
+    }
+
+    public static ICustomMarshaler GetInstance(string cookie)
+    {
+        if (marshaler == null)
+        {
+            marshaler = new ValueTypeMarshaler();
+        }
+
+        return marshaler;
+    }
+
+    static private ValueTypeMarshaler marshaler;
+}
+
 }
index aa2572f..590bb4e 100644 (file)
@@ -421,6 +421,9 @@ EAPI const Eina_Value_Type *type_array() {
 EAPI const Eina_Value_Type *type_list() {
    return EINA_VALUE_TYPE_LIST;
 }
+EAPI const Eina_Value_Type *type_hash() {
+   return EINA_VALUE_TYPE_HASH;
+}
 EAPI const Eina_Value_Type *type_error() {
    return EINA_VALUE_TYPE_ERROR;
 }
index ea178d4..945228a 100644 (file)
@@ -160,6 +160,17 @@ public static class TestEinaValueEolian {
         Test.AssertEquals(expected, received);
         Test.AssertEquals(Eina.ValueType.Int32, received.GetValueType());
     }
+
+    public static void TestEolianEinaValueTypeMarshalling()
+    {
+        var obj = new Dummy.TestObject();
+
+        var values = Enum.GetValues(typeof(Eina.ValueType));
+        foreach (Eina.ValueType type in values)
+        {
+            Test.AssertEquals(type, obj.MirrorValueType(type));
+        }
+    }
 }
 #pragma warning restore 1591
 }
index 6717b12..8ba7536 100644 (file)
@@ -4685,6 +4685,11 @@ Efl_Object *_dummy_test_object_call_find_provider_for_iface(Eo *obj, EINA_UNUSED
     return efl_provider_find(obj, DUMMY_TEST_IFACE_INTERFACE);
 }
 
+const Eina_Value_Type *_dummy_test_object_mirror_value_type(EINA_UNUSED const Eo *obj, EINA_UNUSED Dummy_Test_Object_Data *pd, const Eina_Value_Type *type)
+{
+    return type;
+}
+
 // Inherit
 int _dummy_inherit_helper_receive_dummy_and_call_int_out(Dummy_Test_Object *x)
 {
index 2273c23..4f26beb 100644 (file)
@@ -1642,6 +1642,13 @@ class Dummy.Test_Object extends Efl.Object implements Dummy.Test_Iface {
       call_find_provider_for_iface {
          return: Efl.Object;
       }
+
+      mirror_value_type @beta @const {
+         params {
+            @in type: const(ptr(Eina.Value_Type));
+         }
+         return: const(ptr(Eina.Value_Type));
+      }
    }
    implements {
       Efl.Object.constructor;