/// <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); } } } }
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;
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);
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);
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;