Beispiel #1
0
        /// <summary>
        /// Merge a sequence of producers into a single producer
        /// </summary>
        /// <remarks>The merged producer completes when all component producers have completed</remarks>
        /// <param name="ms">Sequence of producers to merge</param>
        /// <returns>Merged producers</returns>
        public static Producer <RT, OUT, A> merge <RT, OUT, A>(Seq <Producer <RT, OUT, A> > ms) where RT : struct, HasCancel <RT>
        {
            return(from e in Producer.lift <RT, OUT, RT>(runtime <RT>())
                   from x in Producer.enumerate2 <RT, OUT>(go(e))
                   from _ in Producer.yield <RT, OUT>(x)
                   select default(A));

            async IAsyncEnumerable <OUT> go(RT env)
            {
                var queue   = new ConcurrentQueue <OUT>();
                var wait    = new AutoResetEvent(true);
                var running = true;

                // Create a consumer that simply awaits a value and then puts it in our concurrent queue
                // to be re-yielded
                var enqueue = Consumer.awaiting <RT, OUT>()
                              .Map(x =>
                {
                    queue.Enqueue(x);
                    wait.Set();
                    return(default(A));
                })
                              .ToConsumer();

                // Compose the enqueue Consumer with the Producer to create an Effect that can be run
                var mme = ms.Map(m => m | enqueue).Strict();

                // Run the producing effects
                // We should NOT be awaiting these
                var mmt = mme.Map(m => m.RunEffect().Run(env).AsTask());

                // When all tasks are done, we're done
                // We should NOT be awaiting this
                #pragma warning disable CS4014
                Task.WhenAll(mmt.ToArray())
                .Iter(_ =>
                {
                    running = false;
                    wait.Set();
                });
                #pragma warning restore CS4014

                // Keep processing until we're cancelled or all of the Producers have stopped producing
                while (running && !env.CancellationToken.IsCancellationRequested)
                {
                    await wait.WaitOneAsync(env.CancellationToken).ConfigureAwait(false);

                    while (queue.TryDequeue(out var item))
                    {
                        yield return(item);
                    }
                }
            }
        }
Beispiel #2
0
 public static Producer <RT, OUT, B> SelectMany <RT, OUT, A, B>(this Producer <RT, OUT, A> ma, Func <A, Aff <RT, B> > f) where RT : struct, HasCancel <RT> =>
 from a in ma
 from b in Producer.lift <RT, OUT, B>(f(a))
 select b;
Beispiel #3
0
 public static Producer <RT, OUT, C> SelectMany <RT, OUT, A, B, C>(this Producer <OUT, A> ma, Func <A, Eff <RT, B> > f, Func <A, B, C> project) where RT : struct, HasCancel <RT> =>
 from a in ma.Interpret <RT>()
 from b in Producer.lift <RT, OUT, B>(f(a))
 select project(a, b);
Beispiel #4
0
 public static Producer <RT, OUT, C> SelectMany <RT, OUT, A, B, C>(this Eff <A> ma, Func <A, Producer <RT, OUT, B> > f, Func <A, B, C> project) where RT : struct, HasCancel <RT> =>
 from a in Producer.lift <RT, OUT, A>(ma)
 from b in f(a)
 select project(a, b);
Beispiel #5
0
 public static Producer <RT, OUT, B> SelectMany <RT, OUT, A, B>(this Eff <RT, A> ma, Func <A, Producer <OUT, B> > f) where RT : struct, HasCancel <RT> =>
 from a in Producer.lift <RT, OUT, A>(ma)
 from b in f(a).Interpret <RT>()
 select b;