[EflSharp] Update Circle and efl cs files (#995)
[platform/core/csapi/tizenfx.git] / internals / src / EflSharp / EflSharp / efl / eina_value.cs
old mode 100644 (file)
new mode 100755 (executable)
index 99cf097..57a6157
@@ -3,6 +3,8 @@
 #define CODE_ANALYSIS
 
 using System;
+using System.ComponentModel;
+using System.Linq;
 using System.Runtime.InteropServices;
 using System.Collections.Generic;
 using System.Security.Permissions;
@@ -47,6 +49,9 @@ static internal class UnsafeNativeMethods
     internal static extern void eina_value_free(IntPtr type);
 
     [DllImport(efl.Libs.Eina)]
+    internal static extern IntPtr eina_value_type_name_get(IntPtr type);
+
+    [DllImport(efl.Libs.Eina)]
     [return: MarshalAsAttribute(UnmanagedType.U1)]
     internal static extern bool eina_value_convert(IntPtr handle, IntPtr convert);
 
@@ -511,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)]
@@ -712,10 +719,45 @@ 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>();
     private static Dictionary<IntPtr, ValueType> NativeToManaged = new Dictionary<IntPtr, ValueType>();
+    private static Dictionary<System.Type, ValueType> StandardToManaged = new Dictionary<System.Type, ValueType>();
+    private static Dictionary<ValueType, System.Type> ManagedToStandard = new Dictionary<ValueType, System.Type>();
     private static bool TypesLoaded; // CLR defaults to false;
 
     public static ValueType GetManaged(IntPtr native)
@@ -725,7 +767,16 @@ static class ValueTypeBridge
             LoadTypes();
         }
 
-        return NativeToManaged[native];
+        try
+        {
+            return NativeToManaged[native];
+        }
+        catch (KeyNotFoundException)
+        {
+            var name_ptr = eina_value_type_name_get(native);
+            var name = Marshal.PtrToStringAnsi(name_ptr);
+            throw new Efl.EflException($"Unknown native eina value Type: 0x{native.ToInt64():x} with name {name}");
+        }
     }
 
     public static IntPtr GetNative(ValueType valueType)
@@ -738,48 +789,106 @@ static class ValueTypeBridge
         return ManagedToNative[valueType];
     }
 
+    /// <summary>Returns the Eina.Value type associated with the given C# type.</summary>
+    public static ValueType GetManaged(System.Type type)
+    {
+        ValueType v;
+        if (StandardToManaged.TryGetValue(type, out v))
+        {
+            return v;
+        }
+        else
+        {
+            if (typeof(Efl.Object).IsAssignableFrom(type))
+            {
+                return ValueType.Object;
+            }
+            throw new Efl.EflException($"Unknown value type mapping for C# type {type}");
+        }
+    }
+
+    /// <summary>Returns the System.Type associated with the given Eina.Value type.</summary>
+    /// <param name="valueType">The intermediate type as returned by <see cref="Eina.Value.GetValueType()" />.</param>
+    /// <returns>The associated C# type with this value type.</returns>
+    public static System.Type GetStandard(ValueType valueType)
+    {
+        System.Type ret = null;
+        if (ManagedToStandard.TryGetValue(valueType, out ret))
+        {
+            return ret;
+        }
+        else
+        {
+            throw new Efl.EflException($"Unknown C# type mapping for value type {valueType}");
+        }
+    }
+
     private static void LoadTypes()
     {
         Eina.Config.Init(); // Make sure eina is initialized.
 
         ManagedToNative.Add(ValueType.SByte, type_sbyte());
         NativeToManaged.Add(type_sbyte(), ValueType.SByte);
+        StandardToManaged.Add(typeof(sbyte), ValueType.SByte);
+        ManagedToStandard.Add(ValueType.SByte, typeof(sbyte));
 
         ManagedToNative.Add(ValueType.Byte, type_byte());
         NativeToManaged.Add(type_byte(), ValueType.Byte);
+        StandardToManaged.Add(typeof(byte), ValueType.Byte);
+        ManagedToStandard.Add(ValueType.Byte, typeof(byte));
 
         ManagedToNative.Add(ValueType.Short, type_short());
         NativeToManaged.Add(type_short(), ValueType.Short);
+        StandardToManaged.Add(typeof(short), ValueType.Short);
+        ManagedToStandard.Add(ValueType.Short, typeof(short));
 
         ManagedToNative.Add(ValueType.UShort, type_ushort());
         NativeToManaged.Add(type_ushort(), ValueType.UShort);
+        StandardToManaged.Add(typeof(ushort), ValueType.UShort);
+        ManagedToStandard.Add(ValueType.UShort, typeof(ushort));
 
         ManagedToNative.Add(ValueType.Int32, type_int32());
         NativeToManaged.Add(type_int32(), ValueType.Int32);
+        StandardToManaged.Add(typeof(int), ValueType.Int32);
+        ManagedToStandard.Add(ValueType.Int32, typeof(int));
 
         ManagedToNative.Add(ValueType.UInt32, type_uint32());
         NativeToManaged.Add(type_uint32(), ValueType.UInt32);
+        StandardToManaged.Add(typeof(uint), ValueType.UInt32);
+        ManagedToStandard.Add(ValueType.UInt32, typeof(uint));
 
         ManagedToNative.Add(ValueType.Long, type_long());
         NativeToManaged.Add(type_long(), ValueType.Long);
+        ManagedToStandard.Add(ValueType.Long, typeof(long));
 
         ManagedToNative.Add(ValueType.ULong, type_ulong());
         NativeToManaged.Add(type_ulong(), ValueType.ULong);
+        ManagedToStandard.Add(ValueType.ULong, typeof(ulong));
 
         ManagedToNative.Add(ValueType.Int64, type_int64());
         NativeToManaged.Add(type_int64(), ValueType.Int64);
+        StandardToManaged.Add(typeof(long), ValueType.Int64);
+        ManagedToStandard.Add(ValueType.Int64, typeof(long));
 
         ManagedToNative.Add(ValueType.UInt64, type_uint64());
         NativeToManaged.Add(type_uint64(), ValueType.UInt64);
+        StandardToManaged.Add(typeof(ulong), ValueType.UInt64);
+        ManagedToStandard.Add(ValueType.UInt64, typeof(ulong));
 
         ManagedToNative.Add(ValueType.Float, type_float());
         NativeToManaged.Add(type_float(), ValueType.Float);
+        StandardToManaged.Add(typeof(float), ValueType.Float);
+        ManagedToStandard.Add(ValueType.Float, typeof(float));
 
         ManagedToNative.Add(ValueType.Double, type_double());
         NativeToManaged.Add(type_double(), ValueType.Double);
+        StandardToManaged.Add(typeof(double), ValueType.Double);
+        ManagedToStandard.Add(ValueType.Double, typeof(double));
 
         ManagedToNative.Add(ValueType.String, type_string());
         NativeToManaged.Add(type_string(), ValueType.String);
+        StandardToManaged.Add(typeof(string), ValueType.String);
+        ManagedToStandard.Add(ValueType.String, typeof(string));
 
         ManagedToNative.Add(ValueType.Array, type_array());
         NativeToManaged.Add(type_array(), ValueType.Array);
@@ -787,14 +896,23 @@ 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);
 
         ManagedToNative.Add(ValueType.Error, type_error());
         NativeToManaged.Add(type_error(), ValueType.Error);
+        StandardToManaged.Add(typeof(Eina.Error), ValueType.Error);
+        ManagedToStandard.Add(ValueType.Error, typeof(Eina.Error));
 
         ManagedToNative.Add(ValueType.Object, type_object());
         NativeToManaged.Add(type_object(), ValueType.Object);
+        // We don't use `typeof(Efl.Object)` directly in the StandartToManaged dictionary as typeof(myobj) may
+        // return a different type. For ManagedToStandard, we make use of C# generics covariance to create
+        // an collection of Efl.Objects when unwrapping.
+        ManagedToStandard.Add(ValueType.Object, typeof(Efl.Object));
 
         ManagedToNative.Add(ValueType.Empty, IntPtr.Zero);
         NativeToManaged.Add(IntPtr.Zero, ValueType.Empty);
@@ -904,7 +1022,108 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
     private Value()
     {
         this.Handle = Alloc();
+
+        if (this.Handle == IntPtr.Zero)
+        {
+            throw new OutOfMemoryException("Failed to allocate memory for Eina.Value");
+        }
+
         this.Ownership = Ownership.Managed;
+        MemoryNative.Memset(this.Handle, 0, eina_value_sizeof());
+    }
+
+    /// <summary>Creates a new Value from the given C# value.</summary>
+    /// <param name="obj">The object to be wrapped.</param>
+    public Value(object obj) : this()
+    {
+        var objType = obj.GetType();
+
+        if (objType == typeof(sbyte))
+        {
+            Setup(ValueType.SByte);
+            Set((sbyte)obj);
+        }
+        else if (objType == typeof(byte))
+        {
+            Setup(ValueType.Byte);
+            Set((byte)obj);
+        }
+        else if (objType == typeof(short))
+        {
+            Setup(ValueType.Short);
+            Set((short)obj);
+        }
+        else if (objType == typeof(ushort))
+        {
+            Setup(ValueType.UShort);
+            Set((ushort)obj);
+        }
+        else if (objType == typeof(int))
+        {
+            Setup(ValueType.Int32);
+            Set((int)obj);
+        }
+        else if (objType == typeof(uint))
+        {
+            Setup(ValueType.UInt32);
+            Set((uint)obj);
+        }
+        else if (objType == typeof(long))
+        {
+            Setup(ValueType.Int64);
+            Set((long)obj);
+        }
+        else if (objType == typeof(ulong))
+        {
+            Setup(ValueType.UInt64);
+            Set((ulong)obj);
+        }
+        else if (objType == typeof(float))
+        {
+            Setup(ValueType.Float);
+            Set((float)obj);
+        }
+        else if (objType == typeof(double))
+        {
+            Setup(ValueType.Double);
+            Set((double)obj);
+        }
+        else if (objType == typeof(string))
+        {
+            Setup(ValueType.String);
+            Set(obj as string);
+        }
+        else if (typeof(Efl.Object).IsAssignableFrom(objType))
+        {
+            Setup(ValueType.Object);
+            Set(obj as Efl.Object);
+        }
+        else
+        {
+            // Container type conversion is supported only from IEnumerable<T>
+            if (!obj.GetType().GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
+            {
+                throw new ArgumentException($"Unsupported type for direct construction: {objType}");
+            }
+
+            Type[] genericArguments = objType.GetGenericArguments();
+            if (genericArguments.Count() != 1)
+            {
+                throw new ArgumentException($"Unsupported type for direct construction: {objType}");
+            }
+
+            var genericArg = genericArguments[0];
+
+            var argValueType = ValueTypeBridge.GetManaged(genericArg);
+
+            Setup(ValueType.Array, argValueType);
+
+            foreach (var item in obj as System.Collections.IEnumerable)
+            {
+                Append(item);
+            }
+
+        }
     }
 
     public Value(IntPtr handle, Ownership ownership = Ownership.Managed)
@@ -978,8 +1197,7 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
                 // free(), avoiding a call to eina_value_flush that would wipe the underlying value contents
                 // for pointer types like string.
                 tmp = MemoryNative.Alloc(Marshal.SizeOf(typeof(ValueNative)));
-                Marshal.StructureToPtr(value, tmp, false); // Can't get the address of a struct directly.
-                this.Handle = Alloc();
+                Marshal.StructureToPtr<ValueNative>(value, tmp, false); // Can't get the address of a struct directly.
 
                 // Copy is used to deep copy the pointed payload (e.g. strings) inside this struct, so we can own this value.
                 if (!eina_value_copy(tmp, this.Handle))
@@ -1379,6 +1597,121 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
         return b;
     }
 
+    /// <summary>Unwrap the value into its underlying C# value.
+    ///
+    /// <para>Useful for methods like <see crev="PropertyInfo.SetValue(object, object)" />
+    /// as it will unpack the value to it correct C# type.</para>
+    /// </summary>
+    /// <returns>The C# value wrapped by this value.</returns>
+    public object Unwrap()
+    {
+        switch (GetValueType())
+        {
+            case ValueType.SByte:
+                {
+                    sbyte o;
+                    Get(out o);
+                    return o;
+                }
+            case ValueType.Byte:
+                {
+                    byte o;
+                    Get(out o);
+                    return o;
+                }
+            case ValueType.Short:
+                {
+                    short o;
+                    Get(out o);
+                    return o;
+                }
+            case ValueType.UShort:
+                {
+                    ushort o;
+                    Get(out o);
+                    return o;
+                }
+            case ValueType.Int32:
+                {
+                    int o;
+                    Get(out o);
+                    return o;
+                }
+            case ValueType.UInt32:
+                {
+                    uint o;
+                    Get(out o);
+                    return o;
+                }
+            case ValueType.Int64:
+            case ValueType.Long:
+                {
+                    long o;
+                    Get(out o);
+                    return o;
+                }
+            case ValueType.UInt64:
+            case ValueType.ULong:
+                {
+                    ulong o;
+                    Get(out o);
+                    return o;
+                }
+            case ValueType.Float:
+                {
+                    float o;
+                    Get(out o);
+                    return o;
+                }
+            case ValueType.Double:
+                {
+                    double o;
+                    Get(out o);
+                    return o;
+                }
+            case ValueType.String:
+                {
+                    string o;
+                    Get(out o);
+                    return o;
+                }
+            case ValueType.Object:
+                {
+                    Efl.Object o;
+                    Get(out o);
+                    return o;
+                }
+            case ValueType.Array:
+            case ValueType.List:
+                {
+                    // Eina Array and Lists will be unwrapped into a System.Collections.Generic.List<T>
+                    // usually to be handled as IEnumerable<T> through LINQ.
+                    var genericType = ValueTypeBridge.GetStandard(GetValueSubType());
+                    Type[] typeArgs = { genericType };
+                    var containerType = typeof(System.Collections.Generic.List<>);
+                    var retType = containerType.MakeGenericType(typeArgs);
+                    object ret = Activator.CreateInstance(retType);
+
+                    var addMeth = retType.GetMethod("Add");
+
+                    if (addMeth == null)
+                    {
+                        throw new InvalidOperationException("Failed to get Add() method of container to wrap value");
+                    }
+
+                    for (int i = 0; i < Count(); i++)
+                    {
+                        object[] args = new object[]{ this[i] };
+                        addMeth.Invoke(ret, args);
+                    }
+
+                    return ret;
+                }
+            default:
+                throw new InvalidOperationException($"Unsupported value type to unwrap: {GetValueType()}");
+        }
+    }
+
     // Efl.Object conversions are made explicit to avoid ambiguity between
     // Set(Efl.Object) and Set(Value) when dealing with classes derived from
     // Efl.Object.
@@ -1482,7 +1815,7 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
         {
             if (Disposed)
             {
-                throw new ObjectDisposedException(base.GetType().Name);
+                throw new ObjectDisposedException($"Value at 0x{this.Handle.ToInt64():x}");
             }
 
             return this.Handle;
@@ -1494,7 +1827,7 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
     {
         if (Disposed)
         {
-            throw new ObjectDisposedException(base.GetType().Name);
+            throw new ObjectDisposedException($"Value at 0x{this.Handle.ToInt64():x}");
         }
 
         // Can't call setup with Empty value type (would give an eina error)
@@ -1540,7 +1873,7 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
     {
         if (Disposed)
         {
-            throw new ObjectDisposedException(GetType().Name);
+            throw new ObjectDisposedException($"Value at 0x{this.Handle.ToInt64():x}");
         }
     }
 
@@ -1591,6 +1924,7 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
     /// <summary>Get a ValueNative struct with the *value* pointed by this Eina.Value.</summary>
     public ValueNative GetNative()
     {
+        SanityChecks();
         ValueNative value = (ValueNative)Marshal.PtrToStructure(this.Handle, typeof(ValueNative));
         return value;
     }
@@ -1816,7 +2150,7 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
         if (!GetValueType().IsString())
         {
             throw (new ArgumentException(
-                        "Trying to set non-string value on a string Eina.Value"));
+                        "Trying to set string value on a non-string Eina.Value"));
         }
 
         // No need to worry about ownership as eina_value_set will copy the passed string.
@@ -2603,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>
@@ -2705,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;
+}
+
 }