예제 #1
0
        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> >());
            });
        }
예제 #2
0
        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> >());
            });
        }
예제 #3
0
        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> >());
                });
            });
        }