#define CODE_ANALYSIS
using System;
+using System.Linq;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Security.Permissions;
{
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)
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);
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);
}
else
{
- throw new ArgumentException($"Unsupported type for direct construction: {objType}");
+ // 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);
+ }
+
}
}
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()}");
}
#pragma warning disable 1591
using System;
+using System.Linq;
using System.Diagnostics.CodeAnalysis;
+using System.Collections.Generic;
namespace TestSuite {
Test.AssertEquals(prop.GetValue(source), newObj);
}
}
+
+ private class ComplexHolder
+ {
+ public IEnumerable<int> Bag { get; set; }
+ public IEnumerable<Efl.Object> BagOfObjects { get; set; }
+ }
+
+ public static void TestContainerFromToObject()
+ {
+ var initialBag = new Eina.Array<int>();
+ initialBag.Push(2);
+ initialBag.Push(4);
+ initialBag.Push(6);
+
+ var source = new ComplexHolder { Bag = initialBag };
+ var prop = source.GetType().GetProperty("Bag");
+ var v = new Eina.Value(prop.GetValue(source));
+ Test.AssertEquals(prop.GetValue(source), initialBag);
+
+ Test.AssertEquals(v.GetValueType(), Eina.ValueType.Array);
+ Test.AssertEquals(v.GetValueSubType(), Eina.ValueType.Int32);
+
+ Test.AssertEquals(v[0], initialBag[0]);
+ Test.AssertEquals(v[1], initialBag[1]);
+ Test.AssertEquals(v[2], initialBag[2]);
+
+ v[0] = 100;
+ v[1] = 200;
+ v[2] = 300;
+
+ prop.SetValue(source, v.Unwrap());
+
+ IEnumerable<int> newVal = prop.GetValue(source) as IEnumerable<int>;
+ var toCheck = newVal.ToList();
+
+ Test.AssertEquals(toCheck[0], 100);
+ Test.AssertEquals(toCheck[1], 200);
+ Test.AssertEquals(toCheck[2], 300);
+ }
+
+ public static void TestObjectContainerFromToObject()
+ {
+ var initialBag = new Eina.Array<Efl.Object>();
+ initialBag.Push(new Dummy.TestObject());
+ initialBag.Push(new Dummy.TestObject());
+ initialBag.Push(new Dummy.TestObject());
+
+ var source = new ComplexHolder { BagOfObjects = initialBag };
+ var prop = source.GetType().GetProperty("BagOfObjects");
+ var v = new Eina.Value(prop.GetValue(source));
+ Test.AssertEquals(prop.GetValue(source), initialBag);
+
+ Test.AssertEquals(v.GetValueType(), Eina.ValueType.Array);
+ Test.AssertEquals(v.GetValueSubType(), Eina.ValueType.Object);
+
+ Test.AssertEquals(v[0], initialBag[0]);
+ Test.AssertEquals(v[1], initialBag[1]);
+ Test.AssertEquals(v[2], initialBag[2]);
+
+ var first = new Dummy.TestObject();
+ var second = new Dummy.TestObject();
+ var third = new Dummy.TestObject();
+ v[0] = first;
+ v[1] = second;
+ v[2] = third;
+
+ prop.SetValue(source, v.Unwrap());
+
+ IEnumerable<Efl.Object> newVal = prop.GetValue(source) as IEnumerable<Efl.Object>;
+ var toCheck = newVal.ToList();
+
+ Test.AssertEquals(toCheck[0], first);
+ Test.AssertEquals(toCheck[1], second);
+ Test.AssertEquals(toCheck[2], third);
+ }
}
#pragma warning restore 1591
}