public static Await <R> Condition <TEventArgs, TEventHandler, R>( Func <Optional <TEventArgs>, Optional <R> > choose, Action <TEventHandler> subscribe, Action <TEventHandler> unsubscribe, Func <Action <object, TEventArgs>, TEventHandler> convert) { return(complete => { // Create helper action to safely invoke choose action and supply result to completed. Func <Optional <TEventArgs>, Complete <R>, bool> tryChooseAndComplete = (e, doComplete) => { var choice = Try.Do(() => choose(e)); if (choice.IsSuccess && choice.Success.IsNone) { return false; } doComplete(choice.Map(x => x.Some)); return true; }; // When some result is chosen or exception thrown in process, // Then handle it and return immediately - Nothing to Cancel here. if (tryChooseAndComplete(None.Of <TEventArgs>(), complete)) { return NothingToCancel; } var eventHandler = default(TEventHandler); var completeFirst = new CompleteFirst(); Complete <R> completeAndUnsubscribe = x => completeFirst.Do(() => { var unsubscription = Try.Do(() => unsubscribe(eventHandler)); // Replacing original failure with unsubscription failure if got one. complete(unsubscription.IsError ? Error.Of <R>(unsubscription.Error) : x); }); // Convert action to event handler delegate (ignoring event source) and subscribe it. var subscription = Try.Do(() => subscribe( eventHandler = convert((_, e) => tryChooseAndComplete(e, completeAndUnsubscribe)))); if (subscription.IsError) { complete(Error.Of <R>(subscription.Error)); return NothingToCancel; } // In case that during subscribe, condition become true (e.g. event was already raised and will never be raised again) // We are checking condition one more time. if (tryChooseAndComplete(None.Of <TEventArgs>(), completeAndUnsubscribe)) { return NothingToCancel; } // Return Cancel with None result. return () => completeAndUnsubscribe(None.Of <Result <R> >()); }); }
public static Await <R> Many <T, R>( Func <Result <T>, int, Optional <R> > choose, R defaultResult, params Await <T>[] sources) { return(complete => { var cancels = Stack <Cancelable> .Empty; var completeFirst = new CompleteFirst(); var completeLast = new CompleteLast(sources.Length); Complete <R> cancelRestAndComplete = result => completeFirst.Do(() => { cancels.ForEach(x => Try.Do(() => x())); complete(result); }); for (var i = 0; i < sources.Length; i++) { var index = i; // save index to use in lambda var current = sources[i](result => { if (result.IsNone) // it means that we ignoring external canceling. { return; } var choice = Try.Do(() => choose(result.Some, index)); if (choice.IsError) { cancelRestAndComplete(Error.Of <R>(choice.Error)); } else if (choice.Success.IsSome) { cancelRestAndComplete(Success.Of(choice.Success.Some)); } else // at last try to complete whole workflow with default result. { completeLast.Do(() => completeFirst.Do(() => complete(Success.Of(defaultResult)))); } }); if (completeFirst.IsCompleted) // if all is done just return { return NothingToCancel; } cancels = cancels.Add(current); } return () => cancelRestAndComplete(None.Of <Result <R> >()); }); }
public static Await <R> Many <T1, T2, R>( Await <T1> source1, Await <T2> source2, R defaultResult, Func <Optional <Result <T1> >, Optional <Result <T2> >, Optional <R> > choose) { var result1 = None.Of <Result <T1> >(); var result2 = None.Of <Result <T2> >(); return(Many( (_, i) => choose(result1, result2), defaultResult, source1.Take(result => result1 = Success.Of(result)), source2.Take(result => result2 = Success.Of(result)))); }
public static Await <T> Operation <T>(Func <T> operation, Func <Action, Cancelable> invoker) { return(complete => { var completeFirst = new CompleteFirst(); var cancel = invoker(() => { var result = Try.Do(operation); completeFirst.Do(() => complete(result)); }); return () => completeFirst.Do(() => { Try.Do(() => cancel()); complete(None.Of <Result <T> >()); }); }); }
public static Await <R> Map <T, R>(this Await <T> source, Func <T, R> map) { return(complete => source(result => { if (result.IsNone) { complete(None.Of <Result <R> >()); } else if (result.Some.IsError) { complete(Error.Of <R>(result.Some.Error)); } else { var converted = Try.Do(() => map(result.Some.Success)); complete(converted.IsSuccess ? Success.Of(converted.Success) : Error.Of <R>(converted.Error)); } })); }
public static Optional <Result <T> > Wait <T>(this Await <T> source, int timeoutMilliseconds = Timeout.Infinite) { var completed = new AutoResetEvent(false); var result = None.Of <Result <T> >(); var cancel = source(x => { result = x; completed.Set(); }); if (completed.WaitOne(timeoutMilliseconds)) { return(result); } cancel(); return(None.Of <Result <T> >()); }
public static Optional <T> Of <T>(T value) { return((object)value == null?None.Of <T>() : Some.Of(value)); }
public static Await <Result <T>[]> All <T>(params Await <T>[] sources) { var results = new Result <T> [sources.Length]; return(Many((x, i) => None.Of <Result <T>[]>().Apply(_ => results[i] = x), results, sources)); }