// Helper function to attach a cb to a future without creating a new wrapper directly. // It'll be used in the construtor, to attach the cleaning cb to an intermediate future. private static IntPtr ThenRaw(IntPtr previous, ResolvedCb cb) { FutureDesc desc = new FutureDesc(); desc.cb = NativeResolvedCbDelegate; GCHandle handle = GCHandle.Alloc(cb); desc.data = GCHandle.ToIntPtr(handle); return(eina_future_then_from_desc(previous, desc)); }
/// <summary> /// Creates a Future attached to the given Promise. /// /// Optionally a resolved callback may be provided. If so, it will be chained /// before the returned future. /// </summary> public Future(Promise promise, ResolvedCb cb = null) { IntPtr intermediate = eina_future_new(promise.Handle); Handle = ThenRaw(intermediate, (Eina.Value value) => { if (cb != null) { value = cb(value); } Handle = IntPtr.Zero; return(value); }); }
private static Eina.ValueNative NativeResolvedCb(IntPtr data, Eina.ValueNative value, IntPtr dead_future) { GCHandle handle = GCHandle.FromIntPtr(data); ResolvedCb cb = handle.Target as ResolvedCb; if (cb != null) { value = cb(value); } else { Eina.Log.Warning("Failed to get future callback."); } handle.Free(); return(value); }
/// <summary> /// Helper method for chaining a group of callbacks in a single go. /// /// It is just syntatic sugar for sequential Then() calls, without creating intermediate /// futures explicitly. /// </summary> public Future Chain(IEnumerable <ResolvedCb> cbs) { SanityChecks(); System.Collections.Generic.IList <ResolvedCb> cbsList = cbs.ToList(); FutureDesc[] descs = new FutureDesc[cbsList.Count() + 1]; // +1 due to the null-cb terminating descriptor. int i = 0; try { for (; i < cbsList.Count(); i++) { ResolvedCb cb = cbsList[i]; descs[i].cb = NativeResolvedCbDelegate; GCHandle handle = GCHandle.Alloc(cb); descs[i].data = GCHandle.ToIntPtr(handle); } descs[i].cb = null; descs[i].data = IntPtr.Zero; } catch (Exception e) { for (int j = 0; j <= i; j++) { if (descs[i].data == IntPtr.Zero) { continue; } GCHandle handle = GCHandle.FromIntPtr(descs[i].data); handle.Free(); } Eina.Log.Error($"Failed to create native future description for callbacks. Error: {e.ToString()}"); return(null); } return(new Future(eina_future_chain_array(Handle, descs))); }
private static Eina.ValueNative NativeResolvedCb(IntPtr data, Eina.ValueNative value, IntPtr dead_future) { GCHandle handle = GCHandle.FromIntPtr(data); ResolvedCb cb = handle.Target as ResolvedCb; if (cb != null) { 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 { Eina.Log.Warning("Failed to get future callback."); } handle.Free(); return(value); }
/// <summary> /// Creates a new future to be called after this one. /// /// Once the promise this future is attached to resolves, the callbacks on the chain /// are called in the order they were chained. /// /// CAUTION: Calling Then() on a future that had it called before will replace the previous chain /// from this point on. /// </summary> public Future Then(ResolvedCb cb) { SanityChecks(); return(new Future(ThenRaw(Handle, cb))); }