efl-mono: Add object type support for Eina.Value
Summary: C# `Eina.Value` now has builtin support for `EINA_VALUE_TYPE_OBJECT`. To avoid ambiguity with the `Set` method overloads, explicit casting operators were used for wrapping/unwrapping `Efl.Object` instead of implicit ones like for other value types. Thus, to initialize an `Eina.Value` from an object, you can use the following: `var v = (Eina.Value)myObj;` Reviewers: felipealmeida, vitor.sousa, segfaultxavi, Jaehyun_Cho Reviewed By: Jaehyun_Cho Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9164
This commit is contained in:
parent
0a0f3d5bfe
commit
907bdad065
|
@ -182,6 +182,10 @@ static internal class UnsafeNativeMethods
|
|||
[return: MarshalAsAttribute(UnmanagedType.U1)]
|
||||
internal static extern bool eina_value_container_append_wrapper_string(IntPtr handle, string data);
|
||||
|
||||
[DllImport(efl.Libs.CustomExports)]
|
||||
[return: MarshalAsAttribute(UnmanagedType.U1)]
|
||||
internal static extern bool eina_value_container_append_wrapper_ptr(IntPtr handle, IntPtr data);
|
||||
|
||||
[DllImport(efl.Libs.CustomExports)]
|
||||
[return: MarshalAsAttribute(UnmanagedType.U1)]
|
||||
internal static extern bool eina_value_container_append_wrapper_char(IntPtr handle, sbyte data);
|
||||
|
@ -278,6 +282,10 @@ static internal class UnsafeNativeMethods
|
|||
[return: MarshalAsAttribute(UnmanagedType.U1)]
|
||||
internal static extern bool eina_value_container_set_wrapper_string(IntPtr handle, int index, string value);
|
||||
|
||||
[DllImport(efl.Libs.CustomExports)]
|
||||
[return: MarshalAsAttribute(UnmanagedType.U1)]
|
||||
internal static extern bool eina_value_container_set_wrapper_ptr(IntPtr handle, int index, IntPtr value);
|
||||
|
||||
[DllImport(efl.Libs.CustomExports)]
|
||||
[return: MarshalAsAttribute(UnmanagedType.U1)]
|
||||
internal static extern bool eina_value_container_set_wrapper_uchar(IntPtr handle, int index, byte value);
|
||||
|
@ -378,6 +386,10 @@ static internal class UnsafeNativeMethods
|
|||
[return: MarshalAsAttribute(UnmanagedType.U1)]
|
||||
internal static extern bool eina_value_optional_pset(IntPtr handle, IntPtr subtype, ref string value);
|
||||
|
||||
[DllImport(efl.Libs.Eina)]
|
||||
[return: MarshalAsAttribute(UnmanagedType.U1)]
|
||||
internal static extern bool eina_value_optional_pset(IntPtr handle, IntPtr subtype, ref IntPtr value);
|
||||
|
||||
[DllImport(efl.Libs.Eina)]
|
||||
[return: MarshalAsAttribute(UnmanagedType.U1)]
|
||||
internal static extern bool eina_value_optional_pset(IntPtr handle, IntPtr subtype, IntPtr value);
|
||||
|
@ -507,6 +519,10 @@ static internal class UnsafeNativeMethods
|
|||
// Error
|
||||
[DllImport(efl.Libs.CustomExports)]
|
||||
internal static extern IntPtr type_error();
|
||||
|
||||
// Error
|
||||
[DllImport(efl.Libs.CustomExports)]
|
||||
internal static extern IntPtr type_object();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -613,6 +629,7 @@ public enum ValueType
|
|||
Optional,
|
||||
/// <summary>Error values.</summary>
|
||||
Error,
|
||||
Object,
|
||||
/// <summary>Empty values.</summary>
|
||||
Empty,
|
||||
}
|
||||
|
@ -675,6 +692,11 @@ static class ValueTypeMethods
|
|||
return val == ValueType.Error;
|
||||
}
|
||||
|
||||
public static bool IsObject(this ValueType val)
|
||||
{
|
||||
return val == ValueType.Object;
|
||||
}
|
||||
|
||||
/// <summary>Returns the Marshal.SizeOf for the given ValueType native structure.</summary>
|
||||
public static int MarshalSizeOf(this ValueType val)
|
||||
{
|
||||
|
@ -771,6 +793,9 @@ static class ValueTypeBridge
|
|||
ManagedToNative.Add(ValueType.Error, type_error());
|
||||
NativeToManaged.Add(type_error(), ValueType.Error);
|
||||
|
||||
ManagedToNative.Add(ValueType.Object, type_object());
|
||||
NativeToManaged.Add(type_object(), ValueType.Object);
|
||||
|
||||
ManagedToNative.Add(ValueType.Empty, IntPtr.Zero);
|
||||
NativeToManaged.Add(IntPtr.Zero, ValueType.Empty);
|
||||
|
||||
|
@ -1354,6 +1379,32 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
|
|||
return b;
|
||||
}
|
||||
|
||||
// Efl.Object conversions are made explicit to avoid ambiguity between
|
||||
// Set(Efl.Object) and Set(Value) when dealing with classes derived from
|
||||
// Efl.Object.
|
||||
/// <summary>Explicit conversion from EFL objects.</summary>
|
||||
public static explicit operator Value(Efl.Object obj)
|
||||
{
|
||||
var v = new Eina.Value(ValueType.Object);
|
||||
if (!v.Set(obj))
|
||||
{
|
||||
throw new InvalidOperationException("Couldn't set value.");
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/// <summary>Explicit conversion from Value to Efl.Objects.</summary>
|
||||
public static explicit operator Efl.Object(Value v)
|
||||
{
|
||||
Efl.Object obj;
|
||||
if (!v.Get(out obj))
|
||||
{
|
||||
throw new InvalidOperationException("Couldn't get value.");
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>Creates an Value instance from a given array description.</summary>
|
||||
private static Value FromArrayDesc(Eina.EinaNative.Value_Array arrayDesc)
|
||||
{
|
||||
|
@ -1789,6 +1840,22 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
|
|||
return eina_value_set_wrapper_int(this.Handle, error_code);
|
||||
}
|
||||
|
||||
/// <summary>Stores the given object.</summary>
|
||||
public bool Set(Efl.Object value)
|
||||
{
|
||||
// FIXME Implement me
|
||||
SanityChecks();
|
||||
|
||||
if (this.Optional)
|
||||
{
|
||||
IntPtr ptr = value.NativeHandle;
|
||||
return eina_value_optional_pset(this.Handle,
|
||||
ValueTypeBridge.GetNative(ValueType.Object),
|
||||
ref ptr);
|
||||
}
|
||||
return eina_value_set_wrapper_ptr(this.Handle, value.NativeHandle);
|
||||
}
|
||||
|
||||
/// <summary>Stores the given value into this value. The target value must be an optional.</summary>
|
||||
public bool Set(Value value)
|
||||
{
|
||||
|
@ -2017,6 +2084,36 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
|
|||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>Gets the currently stored value as an <see cref="Efl.Object"/>.</summary>
|
||||
public bool Get(out Efl.Object obj)
|
||||
{
|
||||
// FIXME Implement me
|
||||
SanityChecks();
|
||||
IntPtr ptr;
|
||||
bool ret;
|
||||
|
||||
if (this.Optional)
|
||||
{
|
||||
ret = eina_value_optional_pget(this.Handle, out ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = eina_value_get_wrapper(this.Handle, out ptr);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
{
|
||||
obj = (Efl.Object) Efl.Eo.Globals.CreateWrapperFor(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = null;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Gets the currently stored value as an complex (e.g. container) Eina.Value.</summary>
|
||||
public bool Get(out Value value)
|
||||
{
|
||||
|
@ -2281,6 +2378,11 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
|
|||
string x = Convert.ToString(o);
|
||||
return eina_value_container_append_wrapper_string(this.Handle, x);
|
||||
}
|
||||
case ValueType.Object:
|
||||
{
|
||||
var x = (Efl.Object) o;
|
||||
return eina_value_container_append_wrapper_ptr(this.Handle, x.NativeHandle);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -2374,6 +2476,12 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
|
|||
eina_value_container_get_wrapper(this.Handle, i, out ptr);
|
||||
return Eina.StringConversion.NativeUtf8ToManagedString(ptr);
|
||||
}
|
||||
case ValueType.Object:
|
||||
{
|
||||
IntPtr ptr = IntPtr.Zero;
|
||||
eina_value_container_get_wrapper(this.Handle, i, out ptr);
|
||||
return Efl.Eo.Globals.CreateWrapperFor(ptr);
|
||||
}
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("Subtype not supported.");
|
||||
|
@ -2463,6 +2571,12 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
|
|||
eina_value_container_set_wrapper_string(this.Handle, i, x);
|
||||
break;
|
||||
}
|
||||
case ValueType.Object:
|
||||
{
|
||||
Efl.Object x = (Efl.Object)value;
|
||||
eina_value_container_set_wrapper_ptr(this.Handle, i, x.NativeHandle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -403,6 +403,9 @@ EAPI const Eina_Value_Type *type_list() {
|
|||
EAPI const Eina_Value_Type *type_error() {
|
||||
return EINA_VALUE_TYPE_ERROR;
|
||||
}
|
||||
EAPI const Eina_Value_Type *type_object() {
|
||||
return EINA_VALUE_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
EAPI const Eina_Value_Type *type_optional() {
|
||||
return EINA_VALUE_TYPE_OPTIONAL;
|
||||
|
|
|
@ -146,6 +146,31 @@ public static class TestEinaValue {
|
|||
}
|
||||
}
|
||||
|
||||
public static void TestObjectSimple()
|
||||
{
|
||||
using (Eina.Value v = new Eina.Value(Eina.ValueType.Object))
|
||||
{
|
||||
var obj = new Dummy.TestObject();
|
||||
Test.Assert(v.Set(obj));
|
||||
Efl.Object target;
|
||||
Test.Assert(v.Get(out target));
|
||||
Test.AssertEquals(target, obj);
|
||||
}
|
||||
}
|
||||
|
||||
// Efl.Object conversions are made explicit to avoid ambiguity between
|
||||
// Set(Efl.Object) and Set(Value) when dealing with classes derived from
|
||||
// Efl.Object.
|
||||
public static void TestObjectImplicit()
|
||||
{
|
||||
var obj = new Dummy.TestObject();
|
||||
var v = (Eina.Value)obj;
|
||||
Test.AssertEquals(v.GetValueType(), Eina.ValueType.Object);
|
||||
Efl.Object target = (Efl.Object)v;
|
||||
|
||||
Test.AssertEquals(target, obj);
|
||||
}
|
||||
|
||||
public static void TestSetWrongType()
|
||||
{
|
||||
using (Eina.Value v = new Eina.Value(Eina.ValueType.String)) {
|
||||
|
@ -259,6 +284,37 @@ public static class TestEinaValue {
|
|||
Test.AssertEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
public static void TestValueOptionalObject()
|
||||
{
|
||||
using (Eina.Value a = new Eina.Value(Eina.ValueType.Object)) {
|
||||
Test.Assert(!a.Optional);
|
||||
BoolRet dummy = () => a.OptionalEmpty;
|
||||
Test.AssertRaises<Eina.InvalidValueTypeException>(() => dummy());
|
||||
}
|
||||
|
||||
using (Eina.Value a = new Eina.Value(Eina.ValueType.Optional)) {
|
||||
Test.Assert(a.Optional);
|
||||
Test.Assert(a.OptionalEmpty); // By default, optional values are empty
|
||||
|
||||
// Sets expectation
|
||||
Efl.Object expected = new Dummy.TestObject();
|
||||
Test.Assert(a.Set(expected));
|
||||
Test.Assert(a.Optional);
|
||||
Test.Assert(!a.OptionalEmpty);
|
||||
|
||||
Test.Assert(a.Reset());
|
||||
Test.Assert(a.OptionalEmpty);
|
||||
|
||||
Test.Assert(a.Set(expected));
|
||||
Test.Assert(!a.OptionalEmpty);
|
||||
|
||||
Efl.Object received = null;
|
||||
Test.Assert(a.Get(out received));
|
||||
Test.AssertEquals(expected, received);
|
||||
}
|
||||
}
|
||||
|
||||
public static void TestValueOptionalArrays()
|
||||
{
|
||||
using (Eina.Value a = new Eina.Value(Eina.ValueType.Optional))
|
||||
|
@ -763,6 +819,30 @@ public static class TestEinaValue {
|
|||
}
|
||||
}
|
||||
|
||||
public static void TestValueArrayOfObjects()
|
||||
{
|
||||
|
||||
using(Eina.Value array = new Eina.Value(Eina.ValueType.Array, Eina.ValueType.Object)) {
|
||||
|
||||
var a = new Dummy.TestObject();
|
||||
var b = new Dummy.TestObject();
|
||||
|
||||
Test.Assert(array.Append(a));
|
||||
Test.Assert(array.Append(b));
|
||||
|
||||
Test.AssertEquals((Efl.Object)array[0], a);
|
||||
Test.AssertEquals((Efl.Object)array[1], b);
|
||||
|
||||
var c = new Dummy.TestObject();
|
||||
array[0] = c;
|
||||
array[1] = b;
|
||||
|
||||
Test.AssertEquals((Efl.Object)array[0], c);
|
||||
Test.AssertEquals((Efl.Object)array[1], b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void TestArrayOutOfBounds() {
|
||||
using(Eina.Value array = new Eina.Value(Eina.ValueType.Array, Eina.ValueType.Int32)) {
|
||||
object placeholder = null;
|
||||
|
|
Loading…
Reference in New Issue