UNPKG

@effect-ts/system

Version:

Effect-TS is a zero dependency set of libraries to write highly productive, purely functional TypeScript at scale.

128 lines (116 loc) 3.17 kB
// ets_tracing: off import "../../Operator/index.js" import * as Tp from "../../Collections/Immutable/Tuple/index.js" import { constVoid, pipe } from "../../Function/index.js" import type { Option } from "../../Option/index.js" import { none, some } from "../../Option/index.js" import * as P from "../../Promise/index.js" import { matchTag } from "../../Utils/index.js" import * as T from "../_internal/effect.js" import * as R from "../_internal/ref.js" type State<A> = Empty | Full<A> class Empty { readonly _tag = "Empty" constructor(readonly notifyConsumer: P.Promise<never, void>) {} } class Full<A> { readonly _tag = "Full" constructor(readonly a: A, readonly notifyProducer: P.Promise<never, void>) {} } /** * A synchronous queue-like abstraction that allows a producer to offer * an element and wait for it to be taken, and allows a consumer to wait * for an element to be available. */ class Handoff<A> { readonly _tag = "Handoff" constructor(readonly ref: R.Ref<State<A>>) {} } export function make<A>(): T.UIO<Handoff<A>> { return pipe( P.make<never, void>(), T.chain((p) => R.makeRef<State<A>>(new Empty(p))), T.map((ref) => new Handoff(ref)) ) } export function offer_<A>(h: Handoff<A>, a: A): T.UIO<void> { return pipe( P.make<never, void>(), T.chain((p) => pipe( h.ref, R.modify<T.UIO<void>, State<A>>( matchTag({ Empty: ({ notifyConsumer }) => Tp.tuple( pipe(notifyConsumer, P.succeed(constVoid()), T.zipRight(P.await(p))), new Full(a, p) ), Full: (s) => Tp.tuple( pipe( P.await(s.notifyProducer), T.chain(() => offer_(h, a)) ), s ) }) ), T.flatten ) ) ) } export function offer<A>(a: A) { return (h: Handoff<A>) => offer_(h, a) } export function take<A>(h: Handoff<A>): T.UIO<A> { return pipe( P.make<never, void>(), T.chain((p) => pipe( h.ref, R.modify<T.UIO<A>, State<A>>( matchTag({ Empty: (s) => Tp.tuple( pipe( s.notifyConsumer, P.await, T.chain(() => take(h)) ), s ), Full: ({ a, notifyProducer }) => Tp.tuple( pipe(notifyProducer, P.succeed(constVoid()), T.as(a)), new Empty(p) ) }) ), T.flatten ) ) ) } export function poll<A>(h: Handoff<A>): T.UIO<Option<A>> { return pipe( P.make<never, void>(), T.chain((p) => pipe( h.ref, R.modify<T.UIO<Option<A>>, State<A>>( matchTag({ Empty: (s) => Tp.tuple(T.succeed(none), s), Full: ({ a, notifyProducer }) => Tp.tuple( pipe(notifyProducer, P.succeed(constVoid()), T.as(some(a))), new Empty(p) ) }) ), T.flatten ) ) ) }