summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLauro Moura <lauromoura@expertisesolutions.com.br>2019-07-11 13:36:25 -0300
committerVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-07-11 15:57:32 -0300
commit3b5d050353b7e766f2f763c1a6a13afd3b9e8ad0 (patch)
tree0e2fd21bdb585a6ff91e36cd679b3310e3fb6b0a
parent6be38caeaec8e7808af9d0ab4b34465c84bb6e76 (diff)
csharp: Enable conversion of container Eina.Values
Summary: When creating a new Value with any IEnumerable of a supported type, the IEnumerable will be copied into an Eina.Value of type EINA_VALUE_ARRAY_TYPE. Similarly, `Unwrap()` on a Eina.Value container will create a new System.Collections.List<T> and return it. Depends on D9272 Reviewers: felipealmeida, vitor.sousa, segfaultxavi Reviewed By: vitor.sousa Subscribers: cedric, #reviewers, #committers Tags: #efl, #expertise_solutions Differential Revision: https://phab.enlightenment.org/D9273
-rw-r--r--src/bindings/mono/eina_mono/eina_value.cs117
-rw-r--r--src/tests/efl_mono/Value.cs77
2 files changed, 193 insertions, 1 deletions
diff --git a/src/bindings/mono/eina_mono/eina_value.cs b/src/bindings/mono/eina_mono/eina_value.cs
index 37412b679b..cedf5001c2 100644
--- a/src/bindings/mono/eina_mono/eina_value.cs
+++ b/src/bindings/mono/eina_mono/eina_value.cs
@@ -3,6 +3,7 @@
3#define CODE_ANALYSIS 3#define CODE_ANALYSIS
4 4
5using System; 5using System;
6using System.Linq;
6using System.Runtime.InteropServices; 7using System.Runtime.InteropServices;
7using System.Collections.Generic; 8using System.Collections.Generic;
8using System.Security.Permissions; 9using System.Security.Permissions;
@@ -719,6 +720,8 @@ static class ValueTypeBridge
719{ 720{
720 private static Dictionary<ValueType, IntPtr> ManagedToNative = new Dictionary<ValueType, IntPtr>(); 721 private static Dictionary<ValueType, IntPtr> ManagedToNative = new Dictionary<ValueType, IntPtr>();
721 private static Dictionary<IntPtr, ValueType> NativeToManaged = new Dictionary<IntPtr, ValueType>(); 722 private static Dictionary<IntPtr, ValueType> NativeToManaged = new Dictionary<IntPtr, ValueType>();
723 private static Dictionary<System.Type, ValueType> StandardToManaged = new Dictionary<System.Type, ValueType>();
724 private static Dictionary<ValueType, System.Type> ManagedToStandard = new Dictionary<ValueType, System.Type>();
722 private static bool TypesLoaded; // CLR defaults to false; 725 private static bool TypesLoaded; // CLR defaults to false;
723 726
724 public static ValueType GetManaged(IntPtr native) 727 public static ValueType GetManaged(IntPtr native)
@@ -750,48 +753,106 @@ static class ValueTypeBridge
750 return ManagedToNative[valueType]; 753 return ManagedToNative[valueType];
751 } 754 }
752 755
756 /// <summary>Returns the Eina.Value type associated with the given C# type.</summary>
757 public static ValueType GetManaged(System.Type type)
758 {
759 ValueType v;
760 if (StandardToManaged.TryGetValue(type, out v))
761 {
762 return v;
763 }
764 else
765 {
766 if (typeof(Efl.Object).IsAssignableFrom(type))
767 {
768 return ValueType.Object;
769 }
770 throw new Efl.EflException($"Unknown value type mapping for C# type {type}");
771 }
772 }
773
774 /// <summary>Returns the System.Type associated with the given Eina.Value type.</summary>
775 /// <param name="valueType">The intermediate type as returned by <see cref="Eina.Value.GetValueType()" />.</param>
776 /// <returns>The associated C# type with this value type.</returns>
777 public static System.Type GetStandard(ValueType valueType)
778 {
779 System.Type ret = null;
780 if (ManagedToStandard.TryGetValue(valueType, out ret))
781 {
782 return ret;
783 }
784 else
785 {
786 throw new Efl.EflException($"Unknown C# type mapping for value type {valueType}");
787 }
788 }
789
753 private static void LoadTypes() 790 private static void LoadTypes()
754 { 791 {
755 Eina.Config.Init(); // Make sure eina is initialized. 792 Eina.Config.Init(); // Make sure eina is initialized.
756 793
757 ManagedToNative.Add(ValueType.SByte, type_sbyte()); 794 ManagedToNative.Add(ValueType.SByte, type_sbyte());
758 NativeToManaged.Add(type_sbyte(), ValueType.SByte); 795 NativeToManaged.Add(type_sbyte(), ValueType.SByte);
796 StandardToManaged.Add(typeof(sbyte), ValueType.SByte);
797 ManagedToStandard.Add(ValueType.SByte, typeof(sbyte));
759 798
760 ManagedToNative.Add(ValueType.Byte, type_byte()); 799 ManagedToNative.Add(ValueType.Byte, type_byte());
761 NativeToManaged.Add(type_byte(), ValueType.Byte); 800 NativeToManaged.Add(type_byte(), ValueType.Byte);
801 StandardToManaged.Add(typeof(byte), ValueType.Byte);
802 ManagedToStandard.Add(ValueType.Byte, typeof(byte));
762 803
763 ManagedToNative.Add(ValueType.Short, type_short()); 804 ManagedToNative.Add(ValueType.Short, type_short());
764 NativeToManaged.Add(type_short(), ValueType.Short); 805 NativeToManaged.Add(type_short(), ValueType.Short);
806 StandardToManaged.Add(typeof(short), ValueType.Short);
807 ManagedToStandard.Add(ValueType.Short, typeof(short));
765 808
766 ManagedToNative.Add(ValueType.UShort, type_ushort()); 809 ManagedToNative.Add(ValueType.UShort, type_ushort());
767 NativeToManaged.Add(type_ushort(), ValueType.UShort); 810 NativeToManaged.Add(type_ushort(), ValueType.UShort);
811 StandardToManaged.Add(typeof(ushort), ValueType.UShort);
812 ManagedToStandard.Add(ValueType.UShort, typeof(ushort));
768 813
769 ManagedToNative.Add(ValueType.Int32, type_int32()); 814 ManagedToNative.Add(ValueType.Int32, type_int32());
770 NativeToManaged.Add(type_int32(), ValueType.Int32); 815 NativeToManaged.Add(type_int32(), ValueType.Int32);
816 StandardToManaged.Add(typeof(int), ValueType.Int32);
817 ManagedToStandard.Add(ValueType.Int32, typeof(int));
771 818
772 ManagedToNative.Add(ValueType.UInt32, type_uint32()); 819 ManagedToNative.Add(ValueType.UInt32, type_uint32());
773 NativeToManaged.Add(type_uint32(), ValueType.UInt32); 820 NativeToManaged.Add(type_uint32(), ValueType.UInt32);
821 StandardToManaged.Add(typeof(uint), ValueType.UInt32);
822 ManagedToStandard.Add(ValueType.UInt32, typeof(uint));
774 823
775 ManagedToNative.Add(ValueType.Long, type_long()); 824 ManagedToNative.Add(ValueType.Long, type_long());
776 NativeToManaged.Add(type_long(), ValueType.Long); 825 NativeToManaged.Add(type_long(), ValueType.Long);
826 ManagedToStandard.Add(ValueType.Long, typeof(long));
777 827
778 ManagedToNative.Add(ValueType.ULong, type_ulong()); 828 ManagedToNative.Add(ValueType.ULong, type_ulong());
779 NativeToManaged.Add(type_ulong(), ValueType.ULong); 829 NativeToManaged.Add(type_ulong(), ValueType.ULong);
830 ManagedToStandard.Add(ValueType.ULong, typeof(ulong));
780 831
781 ManagedToNative.Add(ValueType.Int64, type_int64()); 832 ManagedToNative.Add(ValueType.Int64, type_int64());
782 NativeToManaged.Add(type_int64(), ValueType.Int64); 833 NativeToManaged.Add(type_int64(), ValueType.Int64);
834 StandardToManaged.Add(typeof(long), ValueType.Int64);
835 ManagedToStandard.Add(ValueType.Int64, typeof(long));
783 836
784 ManagedToNative.Add(ValueType.UInt64, type_uint64()); 837 ManagedToNative.Add(ValueType.UInt64, type_uint64());
785 NativeToManaged.Add(type_uint64(), ValueType.UInt64); 838 NativeToManaged.Add(type_uint64(), ValueType.UInt64);
839 StandardToManaged.Add(typeof(ulong), ValueType.UInt64);
840 ManagedToStandard.Add(ValueType.UInt64, typeof(ulong));
786 841
787 ManagedToNative.Add(ValueType.Float, type_float()); 842 ManagedToNative.Add(ValueType.Float, type_float());
788 NativeToManaged.Add(type_float(), ValueType.Float); 843 NativeToManaged.Add(type_float(), ValueType.Float);
844 StandardToManaged.Add(typeof(float), ValueType.Float);
845 ManagedToStandard.Add(ValueType.Float, typeof(float));
789 846
790 ManagedToNative.Add(ValueType.Double, type_double()); 847 ManagedToNative.Add(ValueType.Double, type_double());
791 NativeToManaged.Add(type_double(), ValueType.Double); 848 NativeToManaged.Add(type_double(), ValueType.Double);
849 StandardToManaged.Add(typeof(double), ValueType.Double);
850 ManagedToStandard.Add(ValueType.Double, typeof(double));
792 851
793 ManagedToNative.Add(ValueType.String, type_string()); 852 ManagedToNative.Add(ValueType.String, type_string());
794 NativeToManaged.Add(type_string(), ValueType.String); 853 NativeToManaged.Add(type_string(), ValueType.String);
854 StandardToManaged.Add(typeof(string), ValueType.String);
855 ManagedToStandard.Add(ValueType.String, typeof(string));
795 856
796 ManagedToNative.Add(ValueType.Array, type_array()); 857 ManagedToNative.Add(ValueType.Array, type_array());
797 NativeToManaged.Add(type_array(), ValueType.Array); 858 NativeToManaged.Add(type_array(), ValueType.Array);
@@ -804,9 +865,15 @@ static class ValueTypeBridge
804 865
805 ManagedToNative.Add(ValueType.Error, type_error()); 866 ManagedToNative.Add(ValueType.Error, type_error());
806 NativeToManaged.Add(type_error(), ValueType.Error); 867 NativeToManaged.Add(type_error(), ValueType.Error);
868 StandardToManaged.Add(typeof(Eina.Error), ValueType.Error);
869 ManagedToStandard.Add(ValueType.Error, typeof(Eina.Error));
807 870
808 ManagedToNative.Add(ValueType.Object, type_object()); 871 ManagedToNative.Add(ValueType.Object, type_object());
809 NativeToManaged.Add(type_object(), ValueType.Object); 872 NativeToManaged.Add(type_object(), ValueType.Object);
873 // We don't use `typeof(Efl.Object)` directly in the StandartToManaged dictionary as typeof(myobj) may
874 // return a different type. For ManagedToStandard, we make use of C# generics covariance to create
875 // an collection of Efl.Objects when unwrapping.
876 ManagedToStandard.Add(ValueType.Object, typeof(Efl.Object));
810 877
811 ManagedToNative.Add(ValueType.Empty, IntPtr.Zero); 878 ManagedToNative.Add(ValueType.Empty, IntPtr.Zero);
812 NativeToManaged.Add(IntPtr.Zero, ValueType.Empty); 879 NativeToManaged.Add(IntPtr.Zero, ValueType.Empty);
@@ -994,7 +1061,29 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
994 } 1061 }
995 else 1062 else
996 { 1063 {
997 throw new ArgumentException($"Unsupported type for direct construction: {objType}"); 1064 // Container type conversion is supported only from IEnumerable<T>
1065 if (!obj.GetType().GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
1066 {
1067 throw new ArgumentException($"Unsupported type for direct construction: {objType}");
1068 }
1069
1070 Type[] genericArguments = objType.GetGenericArguments();
1071 if (genericArguments.Count() != 1)
1072 {
1073 throw new ArgumentException($"Unsupported type for direct construction: {objType}");
1074 }
1075
1076 var genericArg = genericArguments[0];
1077
1078 var argValueType = ValueTypeBridge.GetManaged(genericArg);
1079
1080 Setup(ValueType.Array, argValueType);
1081
1082 foreach (var item in obj as System.Collections.IEnumerable)
1083 {
1084 Append(item);
1085 }
1086
998 } 1087 }
999 } 1088 }
1000 1089
@@ -1553,6 +1642,32 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
1553 Get(out o); 1642 Get(out o);
1554 return o; 1643 return o;
1555 } 1644 }
1645 case ValueType.Array:
1646 case ValueType.List:
1647 {
1648 // Eina Array and Lists will be unwrapped into a System.Collections.Generic.List<T>
1649 // usually to be handled as IEnumerable<T> through LINQ.
1650 var genericType = ValueTypeBridge.GetStandard(GetValueSubType());
1651 Type[] typeArgs = { genericType };
1652 var containerType = typeof(System.Collections.Generic.List<>);
1653 var retType = containerType.MakeGenericType(typeArgs);
1654 object ret = Activator.CreateInstance(retType);
1655
1656 var addMeth = retType.GetMethod("Add");
1657
1658 if (addMeth == null)
1659 {
1660 throw new InvalidOperationException("Failed to get Add() method of container to wrap value");
1661 }
1662
1663 for (int i = 0; i < Count(); i++)
1664 {
1665 object[] args = new object[]{ this[i] };
1666 addMeth.Invoke(ret, args);
1667 }
1668
1669 return ret;
1670 }
1556 default: 1671 default:
1557 throw new InvalidOperationException($"Unsupported value type to unwrap: {GetValueType()}"); 1672 throw new InvalidOperationException($"Unsupported value type to unwrap: {GetValueType()}");
1558 } 1673 }
diff --git a/src/tests/efl_mono/Value.cs b/src/tests/efl_mono/Value.cs
index 1c83344675..ba56c36409 100644
--- a/src/tests/efl_mono/Value.cs
+++ b/src/tests/efl_mono/Value.cs
@@ -3,7 +3,9 @@
3#pragma warning disable 1591 3#pragma warning disable 1591
4 4
5using System; 5using System;
6using System.Linq;
6using System.Diagnostics.CodeAnalysis; 7using System.Diagnostics.CodeAnalysis;
8using System.Collections.Generic;
7 9
8namespace TestSuite { 10namespace TestSuite {
9 11
@@ -1099,6 +1101,81 @@ public static class TestValueFromObject
1099 Test.AssertEquals(prop.GetValue(source), newObj); 1101 Test.AssertEquals(prop.GetValue(source), newObj);
1100 } 1102 }
1101 } 1103 }
1104
1105 private class ComplexHolder
1106 {
1107 public IEnumerable<int> Bag { get; set; }
1108 public IEnumerable<Efl.Object> BagOfObjects { get; set; }
1109 }
1110
1111 public static void TestContainerFromToObject()
1112 {
1113 var initialBag = new Eina.Array<int>();
1114 initialBag.Push(2);
1115 initialBag.Push(4);
1116 initialBag.Push(6);
1117
1118 var source = new ComplexHolder { Bag = initialBag };
1119 var prop = source.GetType().GetProperty("Bag");
1120 var v = new Eina.Value(prop.GetValue(source));
1121 Test.AssertEquals(prop.GetValue(source), initialBag);
1122
1123 Test.AssertEquals(v.GetValueType(), Eina.ValueType.Array);
1124 Test.AssertEquals(v.GetValueSubType(), Eina.ValueType.Int32);
1125
1126 Test.AssertEquals(v[0], initialBag[0]);
1127 Test.AssertEquals(v[1], initialBag[1]);
1128 Test.AssertEquals(v[2], initialBag[2]);
1129
1130 v[0] = 100;
1131 v[1] = 200;
1132 v[2] = 300;
1133
1134 prop.SetValue(source, v.Unwrap());
1135
1136 IEnumerable<int> newVal = prop.GetValue(source) as IEnumerable<int>;
1137 var toCheck = newVal.ToList();
1138
1139 Test.AssertEquals(toCheck[0], 100);
1140 Test.AssertEquals(toCheck[1], 200);
1141 Test.AssertEquals(toCheck[2], 300);
1142 }
1143
1144 public static void TestObjectContainerFromToObject()
1145 {
1146 var initialBag = new Eina.Array<Efl.Object>();
1147 initialBag.Push(new Dummy.TestObject());
1148 initialBag.Push(new Dummy.TestObject());
1149 initialBag.Push(new Dummy.TestObject());
1150
1151 var source = new ComplexHolder { BagOfObjects = initialBag };
1152 var prop = source.GetType().GetProperty("BagOfObjects");
1153 var v = new Eina.Value(prop.GetValue(source));
1154 Test.AssertEquals(prop.GetValue(source), initialBag);
1155
1156 Test.AssertEquals(v.GetValueType(), Eina.ValueType.Array);
1157 Test.AssertEquals(v.GetValueSubType(), Eina.ValueType.Object);
1158
1159 Test.AssertEquals(v[0], initialBag[0]);
1160 Test.AssertEquals(v[1], initialBag[1]);
1161 Test.AssertEquals(v[2], initialBag[2]);
1162
1163 var first = new Dummy.TestObject();
1164 var second = new Dummy.TestObject();
1165 var third = new Dummy.TestObject();
1166 v[0] = first;
1167 v[1] = second;
1168 v[2] = third;
1169
1170 prop.SetValue(source, v.Unwrap());
1171
1172 IEnumerable<Efl.Object> newVal = prop.GetValue(source) as IEnumerable<Efl.Object>;
1173 var toCheck = newVal.ToList();
1174
1175 Test.AssertEquals(toCheck[0], first);
1176 Test.AssertEquals(toCheck[1], second);
1177 Test.AssertEquals(toCheck[2], third);
1178 }
1102} 1179}
1103#pragma warning restore 1591 1180#pragma warning restore 1591
1104} 1181}