{
SanityChecks();
eina_promise_resolve(this.Handle, value);
+ // Promise will take care of releasing this value correctly.
+ value.ReleaseOwnership();
this.Handle = IntPtr.Zero;
// Resolving a cb does *not* call its cancellation callback, so we have to release the
// lambda created in the constructor for cleanup.
/// </summary>
public Future(IntPtr handle)
{
- Handle = ThenRaw(handle, (Eina.Value value) =>
+ handle = ThenRaw(handle, (Eina.Value value) =>
{
Handle = IntPtr.Zero;
return value;
});
+ Handle = handle;
}
/// <summary>
ResolvedCb cb = handle.Target as ResolvedCb;
if (cb != null)
{
- value = cb(value);
+ Eina.Value managedValue = cb(value);
+ // Both `value` and `managedValue` will point to the same internal value data.
+ // Avoid C# wrapper invalidating the underlying C Eina_Value as the eina_future.c
+ // code will release it.
+ value = managedValue.GetNative();
+ managedValue.ReleaseOwnership();
}
else
{
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);
LoadTypes();
}
- return NativeToManaged[native];
+ try
+ {
+ return NativeToManaged[native];
+ }
+ catch (KeyNotFoundException ex)
+ {
+ 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)
// 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))
{
if (Disposed)
{
- throw new ObjectDisposedException(base.GetType().Name);
+ throw new ObjectDisposedException($"Value at 0x{this.Handle.ToInt64():x}");
}
return this.Handle;
{
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)
{
if (Disposed)
{
- throw new ObjectDisposedException(GetType().Name);
+ throw new ObjectDisposedException($"Value at 0x{this.Handle.ToInt64():x}");
}
}
/// <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;
}
}
else
{
- // Will mark the returned task below as completed.
- tcs.SetResult(received);
+ // Async receiver methods may consume the value C# wrapper, like when awaiting in the start of an
+ // using block. In order to continue to forward the value correctly to the next futures
+ // in the chain, we give the Async wrapper a copy of the received wrapper.
+ tcs.SetResult(new Eina.Value(received));
}
fulfilled = true;
Test.AssertEquals(received_value, reference_value);
}
+ public static void test_simple_with_object()
+ {
+ bool callbackCalled = false;
+ Eina.Value receivedValue = null;
+
+ Efl.Loop loop = Efl.App.AppMain;
+ Eina.Promise promise = new Eina.Promise();
+ Eina.Future future = new Eina.Future(promise);
+
+ future = future.Then((Eina.Value value) => {
+ callbackCalled = true;
+ receivedValue = new Eina.Value(value);
+ return value;
+ });
+
+ Eina.Value referenceValue = new Eina.Value(Eina.ValueType.Array, Eina.ValueType.Int32);
+ referenceValue.Append(32);
+ promise.Resolve(new Eina.Value(referenceValue));
+
+ loop.Iterate();
+
+ Test.Assert(callbackCalled, "Future callback should have been called.");
+ Test.AssertEquals(receivedValue, referenceValue);
+ }
+
public static void test_simple_reject()
{
bool callbackCalled = false;