veffect
Version:
powerful TypeScript validation library built on the robust foundation of Effect combining exceptional type safety, high performance, and developer experience. Taking inspiration from Effect's functional principles, VEffect delivers a balanced approach tha
1,325 lines (1,277 loc) • 95 kB
text/typescript
import * as Cause from "../Cause.js"
import type * as Channel from "../Channel.js"
import * as Chunk from "../Chunk.js"
import * as Context from "../Context.js"
import * as Deferred from "../Deferred.js"
import * as Effect from "../Effect.js"
import * as Either from "../Either.js"
import * as Equal from "../Equal.js"
import * as Exit from "../Exit.js"
import * as Fiber from "../Fiber.js"
import { constVoid, dual, identity, pipe } from "../Function.js"
import type { LazyArg } from "../Function.js"
import * as Layer from "../Layer.js"
import type * as MergeDecision from "../MergeDecision.js"
import type * as MergeState from "../MergeState.js"
import type * as MergeStrategy from "../MergeStrategy.js"
import * as Option from "../Option.js"
import { hasProperty, type Predicate } from "../Predicate.js"
import * as PubSub from "../PubSub.js"
import * as Queue from "../Queue.js"
import * as Ref from "../Ref.js"
import * as Scope from "../Scope.js"
import type * as SingleProducerAsyncInput from "../SingleProducerAsyncInput.js"
import type * as Tracer from "../Tracer.js"
import * as executor from "./channel/channelExecutor.js"
import type * as ChannelState from "./channel/channelState.js"
import * as mergeDecision from "./channel/mergeDecision.js"
import * as mergeState from "./channel/mergeState.js"
import * as _mergeStrategy from "./channel/mergeStrategy.js"
import * as singleProducerAsyncInput from "./channel/singleProducerAsyncInput.js"
import * as core from "./core-stream.js"
import * as MergeDecisionOpCodes from "./opCodes/channelMergeDecision.js"
import * as MergeStateOpCodes from "./opCodes/channelMergeState.js"
import * as ChannelStateOpCodes from "./opCodes/channelState.js"
import * as tracer from "./tracer.js"
/** @internal */
export const acquireUseRelease = <Acquired, OutErr, Env, OutElem1, InElem, InErr, OutDone, InDone>(
acquire: Effect.Effect<Acquired, OutErr, Env>,
use: (a: Acquired) => Channel.Channel<OutElem1, InElem, OutErr, InErr, OutDone, InDone, Env>,
release: (a: Acquired, exit: Exit.Exit<OutDone, OutErr>) => Effect.Effect<any, never, Env>
): Channel.Channel<OutElem1, InElem, OutErr, InErr, OutDone, InDone, Env> =>
core.flatMap(
core.fromEffect(
Ref.make<
(exit: Exit.Exit<OutDone, OutErr>) => Effect.Effect<any, never, Env>
>(() => Effect.unit)
),
(ref) =>
pipe(
core.fromEffect(
Effect.uninterruptible(
Effect.tap(
acquire,
(a) => Ref.set(ref, (exit) => release(a, exit))
)
)
),
core.flatMap(use),
core.ensuringWith((exit) => Effect.flatMap(Ref.get(ref), (f) => f(exit)))
)
)
/** @internal */
export const as = dual<
<OutDone2>(
value: OutDone2
) => <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone2, InDone, Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutDone2>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
value: OutDone2
) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone2, InDone, Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutDone2>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
value: OutDone2
): Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone2, InDone, Env> => map(self, () => value))
/** @internal */
export const asUnit = <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
): Channel.Channel<OutElem, InElem, OutErr, InErr, void, InDone, Env> => map(self, constVoid)
/** @internal */
export const buffer = <InElem, InErr, InDone>(
options: {
readonly empty: InElem
readonly isEmpty: Predicate<InElem>
readonly ref: Ref.Ref<InElem>
}
): Channel.Channel<InElem, InElem, InErr, InErr, InDone, InDone> =>
core.suspend(() => {
const doBuffer = <InErr, InElem, InDone>(
empty: InElem,
isEmpty: Predicate<InElem>,
ref: Ref.Ref<InElem>
): Channel.Channel<InElem, InElem, InErr, InErr, InDone, InDone> =>
unwrap(
Ref.modify(ref, (inElem) =>
isEmpty(inElem) ?
[
core.readWith({
onInput: (input: InElem) =>
core.flatMap(
core.write(input),
() => doBuffer<InErr, InElem, InDone>(empty, isEmpty, ref)
),
onFailure: (error: InErr) => core.fail(error),
onDone: (done: InDone) => core.succeedNow(done)
}),
inElem
] as const :
[
core.flatMap(
core.write(inElem),
() => doBuffer<InErr, InElem, InDone>(empty, isEmpty, ref)
),
empty
] as const)
)
return doBuffer(options.empty, options.isEmpty, options.ref)
})
/** @internal */
export const bufferChunk = <InElem, InErr, InDone>(
ref: Ref.Ref<Chunk.Chunk<InElem>>
): Channel.Channel<Chunk.Chunk<InElem>, Chunk.Chunk<InElem>, InErr, InErr, InDone, InDone> =>
buffer({
empty: Chunk.empty(),
isEmpty: Chunk.isEmpty,
ref
})
/** @internal */
export const catchAll = dual<
<OutErr, OutElem1, InElem1, OutErr1, InErr1, OutDone1, InDone1, Env1>(
f: (error: OutErr) => Channel.Channel<OutElem1, InElem1, OutErr1, InErr1, OutDone1, InDone1, Env1>
) => <OutElem, InElem, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<
OutElem1 | OutElem,
InElem & InElem1,
OutErr1,
InErr & InErr1,
OutDone1 | OutDone,
InDone & InDone1,
Env1 | Env
>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutElem1, InElem1, OutErr1, InErr1, OutDone1, InDone1, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (error: OutErr) => Channel.Channel<OutElem1, InElem1, OutErr1, InErr1, OutDone1, InDone1, Env1>
) => Channel.Channel<
OutElem1 | OutElem,
InElem & InElem1,
OutErr1,
InErr & InErr1,
OutDone1 | OutDone,
InDone & InDone1,
Env1 | Env
>
>(
2,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutElem1, InElem1, OutErr1, InErr1, OutDone1, InDone1, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (error: OutErr) => Channel.Channel<OutElem1, InElem1, OutErr1, InErr1, OutDone1, InDone1, Env1>
): Channel.Channel<
OutElem | OutElem1,
InElem & InElem1,
OutErr1,
InErr & InErr1,
OutDone | OutDone1,
InDone & InDone1,
Env | Env1
> =>
core.catchAllCause(self, (cause) =>
Either.match(Cause.failureOrCause(cause), {
onLeft: f,
onRight: core.failCause
}))
)
/** @internal */
export const concatMap = dual<
<OutElem, OutElem2, InElem2, OutErr2, InErr2, X, InDone2, Env2>(
f: (o: OutElem) => Channel.Channel<OutElem2, InElem2, OutErr2, InErr2, X, InDone2, Env2>
) => <Env, InErr, InElem, InDone, OutErr, OutDone>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<
OutElem2,
InElem & InElem2,
OutErr2 | OutErr,
InErr & InErr2,
unknown,
InDone & InDone2,
Env2 | Env
>,
<Env, InErr, InElem, InDone, OutErr, OutDone, OutElem, OutElem2, Env2, InErr2, InElem2, InDone2, OutErr2, X>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (o: OutElem) => Channel.Channel<OutElem2, InElem2, OutErr2, InErr2, X, InDone2, Env2>
) => Channel.Channel<
OutElem2,
InElem & InElem2,
OutErr2 | OutErr,
InErr & InErr2,
unknown,
InDone & InDone2,
Env2 | Env
>
>(2, <Env, InErr, InElem, InDone, OutErr, OutDone, OutElem, OutElem2, Env2, InErr2, InElem2, InDone2, OutErr2, X>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (o: OutElem) => Channel.Channel<OutElem2, InElem2, OutErr2, InErr2, X, InDone2, Env2>
): Channel.Channel<
OutElem2,
InElem & InElem2,
OutErr | OutErr2,
InErr & InErr2,
unknown,
InDone & InDone2,
Env | Env2
> => core.concatMapWith(self, f, () => void 0, () => void 0))
/** @internal */
export const collect = dual<
<OutElem, OutElem2>(
pf: (o: OutElem) => Option.Option<OutElem2>
) => <InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem>
) => Channel.Channel<OutElem2, InElem, OutErr, InErr, OutDone, InDone, Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutElem2>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
pf: (o: OutElem) => Option.Option<OutElem2>
) => Channel.Channel<OutElem2, InElem, OutErr, InErr, OutDone, InDone, Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutElem2>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
pf: (o: OutElem) => Option.Option<OutElem2>
): Channel.Channel<OutElem2, InElem, OutErr, InErr, OutDone, InDone, Env> => {
const collector: Channel.Channel<OutElem2, OutElem, OutErr, OutErr, OutDone, OutDone, Env> = core
.readWith({
onInput: (out) =>
Option.match(pf(out), {
onNone: () => collector,
onSome: (out2) => core.flatMap(core.write(out2), () => collector)
}),
onFailure: core.fail,
onDone: core.succeedNow
})
return core.pipeTo(self, collector)
})
/** @internal */
export const concatOut = <OutElem, InElem, OutErr, InErr, InDone, Env, OutDone>(
self: Channel.Channel<
Channel.Channel<OutElem, InElem, OutErr, InErr, unknown, InDone, Env>,
InElem,
OutErr,
InErr,
OutDone,
InDone,
Env
>
): Channel.Channel<OutElem, InElem, OutErr, InErr, unknown, InDone, Env> => core.concatAll(self)
/** @internal */
export const mapInput = dual<
<InDone0, InDone>(
f: (a: InDone0) => InDone
) => <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone0, Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, InDone0>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (a: InDone0) => InDone
) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone0, Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, InDone0>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (a: InDone0) => InDone
): Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone0, Env> => {
const reader: Channel.Channel<InElem, InElem, InErr, InErr, InDone, InDone0> = core.readWith({
onInput: (inElem: InElem) => core.flatMap(core.write(inElem), () => reader),
onFailure: core.fail,
onDone: (done: InDone0) => core.succeedNow(f(done))
})
return core.pipeTo(reader, self)
})
/** @internal */
export const mapInputEffect = dual<
<InDone0, InDone, InErr, Env1>(
f: (i: InDone0) => Effect.Effect<InDone, InErr, Env1>
) => <OutElem, InElem, OutErr, OutDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone0, Env1 | Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, InDone0, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (i: InDone0) => Effect.Effect<InDone, InErr, Env1>
) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone0, Env1 | Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, InDone0, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (i: InDone0) => Effect.Effect<InDone, InErr, Env1>
): Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone0, Env | Env1> => {
const reader: Channel.Channel<InElem, InElem, InErr, InErr, InDone, InDone0, Env1> = core.readWith({
onInput: (inElem) => core.flatMap(core.write(inElem), () => reader),
onFailure: core.fail,
onDone: (done) => core.fromEffect(f(done))
})
return core.pipeTo(reader, self)
})
/** @internal */
export const mapInputError = dual<
<InErr0, InErr>(
f: (a: InErr0) => InErr
) => <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem, OutErr, InErr0, OutDone, InDone, Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, InErr0>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (a: InErr0) => InErr
) => Channel.Channel<OutElem, InElem, OutErr, InErr0, OutDone, InDone, Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, InErr0>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (a: InErr0) => InErr
): Channel.Channel<OutElem, InElem, OutErr, InErr0, OutDone, InDone, Env> => {
const reader: Channel.Channel<InElem, InElem, InErr, InErr0, InDone, InDone> = core.readWith({
onInput: (inElem: InElem) => core.flatMap(core.write(inElem), () => reader),
onFailure: (error) => core.fail(f(error)),
onDone: core.succeedNow
})
return core.pipeTo(reader, self)
})
/** @internal */
export const mapInputErrorEffect = dual<
<InErr0, InDone, InErr, Env1>(
f: (error: InErr0) => Effect.Effect<InDone, InErr, Env1>
) => <OutElem, InElem, OutErr, OutDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem, OutErr, InErr0, OutDone, InDone, Env1 | Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, InErr0, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (error: InErr0) => Effect.Effect<InDone, InErr, Env1>
) => Channel.Channel<OutElem, InElem, OutErr, InErr0, OutDone, InDone, Env1 | Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, InErr0, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (error: InErr0) => Effect.Effect<InDone, InErr, Env1>
): Channel.Channel<OutElem, InElem, OutErr, InErr0, OutDone, InDone, Env | Env1> => {
const reader: Channel.Channel<InElem, InElem, InErr, InErr0, InDone, InDone, Env1> = core.readWith({
onInput: (inElem) => core.flatMap(core.write(inElem), () => reader),
onFailure: (error) => core.fromEffect(f(error)),
onDone: core.succeedNow
})
return core.pipeTo(reader, self)
})
/** @internal */
export const mapInputIn = dual<
<InElem0, InElem>(
f: (a: InElem0) => InElem
) => <OutElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem0, OutErr, InErr, OutDone, InDone, Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, InElem0>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (a: InElem0) => InElem
) => Channel.Channel<OutElem, InElem0, OutErr, InErr, OutDone, InDone, Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, InElem0>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (a: InElem0) => InElem
): Channel.Channel<OutElem, InElem0, OutErr, InErr, OutDone, InDone, Env> => {
const reader: Channel.Channel<InElem, InElem0, InErr, InErr, InDone, InDone> = core.readWith({
onInput: (inElem) => core.flatMap(core.write(f(inElem)), () => reader),
onFailure: core.fail,
onDone: core.succeedNow
})
return core.pipeTo(reader, self)
})
/** @internal */
export const mapInputInEffect = dual<
<InElem0, InElem, InErr, Env1>(
f: (a: InElem0) => Effect.Effect<InElem, InErr, Env1>
) => <OutElem, OutErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem0, OutErr, InErr, OutDone, InDone, Env1 | Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, InElem0, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (a: InElem0) => Effect.Effect<InElem, InErr, Env1>
) => Channel.Channel<OutElem, InElem0, OutErr, InErr, OutDone, InDone, Env1 | Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, InElem0, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (a: InElem0) => Effect.Effect<InElem, InErr, Env1>
): Channel.Channel<OutElem, InElem0, OutErr, InErr, OutDone, InDone, Env | Env1> => {
const reader: Channel.Channel<InElem, InElem0, InErr, InErr, InDone, InDone, Env1> = core.readWith({
onInput: (inElem) => core.flatMap(core.flatMap(core.fromEffect(f(inElem)), core.write), () => reader),
onFailure: core.fail,
onDone: core.succeedNow
})
return core.pipeTo(reader, self)
})
/** @internal */
export const doneCollect = <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
): Channel.Channel<never, InElem, OutErr, InErr, [Chunk.Chunk<OutElem>, OutDone], InDone, Env> =>
core.suspend(() => {
const builder: Array<OutElem> = []
return pipe(
core.pipeTo(self, doneCollectReader<Env, OutErr, OutElem, OutDone>(builder)),
core.flatMap((outDone) => core.succeed([Chunk.unsafeFromArray(builder), outDone]))
)
})
/** @internal */
const doneCollectReader = <Env, OutErr, OutElem, OutDone>(
builder: Array<OutElem>
): Channel.Channel<never, OutElem, OutErr, OutErr, OutDone, OutDone, Env> => {
return core.readWith({
onInput: (outElem) =>
core.flatMap(
core.sync(() => {
builder.push(outElem)
}),
() => doneCollectReader<Env, OutErr, OutElem, OutDone>(builder)
),
onFailure: core.fail,
onDone: core.succeed
})
}
/** @internal */
export const drain = <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
): Channel.Channel<never, InElem, OutErr, InErr, OutDone, InDone, Env> => {
const drainer: Channel.Channel<never, OutElem, OutErr, OutErr, OutDone, OutDone, Env> = core
.readWithCause({
onInput: () => drainer,
onFailure: core.failCause,
onDone: core.succeed
})
return core.pipeTo(self, drainer)
}
/** @internal */
export const emitCollect = <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
): Channel.Channel<[Chunk.Chunk<OutElem>, OutDone], InElem, OutErr, InErr, void, InDone, Env> =>
core.flatMap(doneCollect(self), core.write)
/** @internal */
export const ensuring = dual<
<Z, Env1>(
finalizer: Effect.Effect<Z, never, Env1>
) => <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env1 | Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, Z, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
finalizer: Effect.Effect<Z, never, Env1>
) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env1 | Env>
>(2, <Env, InErr, InElem, InDone, OutErr, OutElem, OutDone, Env1, Z>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
finalizer: Effect.Effect<Z, never, Env1>
): Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env | Env1> =>
core.ensuringWith(self, () => finalizer))
/** @internal */
export const context = <Env>(): Channel.Channel<never, unknown, never, unknown, Context.Context<Env>, unknown, Env> =>
core.fromEffect(Effect.context<Env>())
/** @internal */
export const contextWith = <Env, OutDone>(
f: (env: Context.Context<Env>) => OutDone
): Channel.Channel<never, unknown, never, unknown, OutDone, unknown, Env> => map(context<Env>(), f)
/** @internal */
export const contextWithChannel = <
Env,
OutElem,
InElem,
OutErr,
InErr,
OutDone,
InDone,
Env1
>(
f: (env: Context.Context<Env>) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env1>
): Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env | Env1> => core.flatMap(context<Env>(), f)
/** @internal */
export const contextWithEffect = <Env, OutDone, OutErr, Env1>(
f: (env: Context.Context<Env>) => Effect.Effect<OutDone, OutErr, Env1>
): Channel.Channel<never, unknown, OutErr, unknown, OutDone, unknown, Env | Env1> => mapEffect(context<Env>(), f)
/** @internal */
export const flatten = <
OutElem,
InElem,
OutErr,
InErr,
OutElem1,
InElem1,
OutErr1,
InErr1,
OutDone2,
InDone1,
Env1,
InDone,
Env
>(
self: Channel.Channel<
OutElem,
InElem,
OutErr,
InErr,
Channel.Channel<OutElem1, InElem1, OutErr1, InErr1, OutDone2, InDone1, Env1>,
InDone,
Env
>
): Channel.Channel<
OutElem | OutElem1,
InElem & InElem1,
OutErr | OutErr1,
InErr & InErr1,
OutDone2,
InDone & InDone1,
Env | Env1
> => core.flatMap(self, identity)
/** @internal */
export const foldChannel = dual<
<
OutErr,
OutElem1,
InElem1,
OutErr1,
InErr1,
OutDone1,
InDone1,
Env1,
OutDone,
OutElem2,
InElem2,
OutErr2,
InErr2,
OutDone2,
InDone2,
Env2
>(
options: {
readonly onFailure: (
error: OutErr
) => Channel.Channel<OutElem1, InElem1, OutErr1, InErr1, OutDone1, InDone1, Env1>
readonly onSuccess: (
done: OutDone
) => Channel.Channel<OutElem2, InElem2, OutErr2, InErr2, OutDone2, InDone2, Env2>
}
) => <Env, InErr, InElem, InDone, OutElem>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<
OutElem1 | OutElem2 | OutElem,
InElem & InElem1 & InElem2,
OutErr1 | OutErr2,
InErr & InErr1 & InErr2,
OutDone1 | OutDone2,
InDone & InDone1 & InDone2,
Env1 | Env2 | Env
>,
<
OutElem,
InElem,
OutErr,
InErr,
OutDone,
InDone,
Env,
OutElem1,
InElem1,
OutErr1,
InErr1,
OutDone1,
InDone1,
Env1,
OutElem2,
InElem2,
OutErr2,
InErr2,
OutDone2,
InDone2,
Env2
>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
options: {
readonly onFailure: (
error: OutErr
) => Channel.Channel<OutElem1, InElem1, OutErr1, InErr1, OutDone1, InDone1, Env1>
readonly onSuccess: (
done: OutDone
) => Channel.Channel<OutElem2, InElem2, OutErr2, InErr2, OutDone2, InDone2, Env2>
}
) => Channel.Channel<
OutElem1 | OutElem2 | OutElem,
InElem & InElem1 & InElem2,
OutErr1 | OutErr2,
InErr & InErr1 & InErr2,
OutDone1 | OutDone2,
InDone & InDone1 & InDone2,
Env1 | Env2 | Env
>
>(2, <
OutElem,
InElem,
OutErr,
InErr,
OutDone,
InDone,
Env,
OutElem1,
InElem1,
OutErr1,
InErr1,
OutDone1,
InDone1,
Env1,
OutElem2,
InElem2,
OutErr2,
InErr2,
OutDone2,
InDone2,
Env2
>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
options: {
readonly onFailure: (error: OutErr) => Channel.Channel<OutElem1, InElem1, OutErr1, InErr1, OutDone1, InDone1, Env1>
readonly onSuccess: (done: OutDone) => Channel.Channel<OutElem2, InElem2, OutErr2, InErr2, OutDone2, InDone2, Env2>
}
): Channel.Channel<
OutElem | OutElem2 | OutElem1,
InElem & InElem1 & InElem2,
OutErr2 | OutErr1,
InErr & InErr1 & InErr2,
OutDone2 | OutDone1,
InDone & InDone1 & InDone2,
Env | Env1 | Env2
> =>
core.foldCauseChannel(self, {
onFailure: (cause) => {
const either = Cause.failureOrCause(cause)
switch (either._tag) {
case "Left": {
return options.onFailure(either.left)
}
case "Right": {
return core.failCause(either.right)
}
}
},
onSuccess: options.onSuccess
}))
/** @internal */
export const fromEither = <R, L>(
either: Either.Either<R, L>
): Channel.Channel<never, unknown, L, unknown, R, unknown> =>
core.suspend(() => Either.match(either, { onLeft: core.fail, onRight: core.succeed }))
/** @internal */
export const fromInput = <Err, Elem, Done>(
input: SingleProducerAsyncInput.AsyncInputConsumer<Err, Elem, Done>
): Channel.Channel<Elem, unknown, Err, unknown, Done, unknown> =>
unwrap(
input.takeWith(
core.failCause,
(elem) => core.flatMap(core.write(elem), () => fromInput(input)),
core.succeed
)
)
/** @internal */
export const fromPubSub = <Done, Err, Elem>(
pubsub: PubSub.PubSub<Either.Either<Elem, Exit.Exit<Done, Err>>>
): Channel.Channel<Elem, unknown, Err, unknown, Done, unknown> =>
unwrapScoped(Effect.map(PubSub.subscribe(pubsub), fromQueue))
/** @internal */
export const fromPubSubScoped = <Done, Err, Elem>(
pubsub: PubSub.PubSub<Either.Either<Elem, Exit.Exit<Done, Err>>>
): Effect.Effect<Channel.Channel<Elem, unknown, Err, unknown, Done, unknown>, never, Scope.Scope> =>
Effect.map(PubSub.subscribe(pubsub), fromQueue)
/** @internal */
export const fromOption = <A>(
option: Option.Option<A>
): Channel.Channel<never, unknown, Option.Option<never>, unknown, A, unknown> =>
core.suspend(() =>
Option.match(option, {
onNone: () => core.fail(Option.none()),
onSome: core.succeed
})
)
/** @internal */
export const fromQueue = <Done, Err, Elem>(
queue: Queue.Dequeue<Either.Either<Elem, Exit.Exit<Done, Err>>>
): Channel.Channel<Elem, unknown, Err, unknown, Done, unknown> => core.suspend(() => fromQueueInternal(queue))
/** @internal */
const fromQueueInternal = <Done, Err, Elem>(
queue: Queue.Dequeue<Either.Either<Elem, Exit.Exit<Done, Err>>>
): Channel.Channel<Elem, unknown, Err, unknown, Done, unknown> =>
pipe(
core.fromEffect(Queue.take(queue)),
core.flatMap(Either.match({
onLeft: Exit.match({
onFailure: core.failCause,
onSuccess: core.succeedNow
}),
onRight: (elem) =>
core.flatMap(
core.write(elem),
() => fromQueueInternal(queue)
)
}))
)
/** @internal */
export const identityChannel = <Elem, Err, Done>(): Channel.Channel<Elem, Elem, Err, Err, Done, Done> =>
core.readWith({
onInput: (input: Elem) => core.flatMap(core.write(input), () => identityChannel()),
onFailure: core.fail,
onDone: core.succeedNow
})
/** @internal */
export const interruptWhen = dual<
<OutDone1, OutErr1, Env1>(
effect: Effect.Effect<OutDone1, OutErr1, Env1>
) => <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem, OutErr1 | OutErr, InErr, OutDone1 | OutDone, InDone, Env1 | Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutDone1, OutErr1, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
effect: Effect.Effect<OutDone1, OutErr1, Env1>
) => Channel.Channel<OutElem, InElem, OutErr1 | OutErr, InErr, OutDone1 | OutDone, InDone, Env1 | Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutDone1, OutErr1, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
effect: Effect.Effect<OutDone1, OutErr1, Env1>
): Channel.Channel<OutElem, InElem, OutErr | OutErr1, InErr, OutDone | OutDone1, InDone, Env1 | Env> =>
mergeWith(self, {
other: core.fromEffect(effect),
onSelfDone: (selfDone) => mergeDecision.Done(Effect.suspend(() => selfDone)),
onOtherDone: (effectDone) => mergeDecision.Done(Effect.suspend(() => effectDone))
}))
/** @internal */
export const interruptWhenDeferred = dual<
<OutDone1, OutErr1>(
deferred: Deferred.Deferred<OutDone1, OutErr1>
) => <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem, OutErr1 | OutErr, InErr, OutDone1 | OutDone, InDone, Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutDone1, OutErr1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
deferred: Deferred.Deferred<OutDone1, OutErr1>
) => Channel.Channel<OutElem, InElem, OutErr1 | OutErr, InErr, OutDone1 | OutDone, InDone, Env>
>(2, <Env, InErr, InElem, InDone, OutErr, OutElem, OutDone, OutErr1, OutDone1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
deferred: Deferred.Deferred<OutDone1, OutErr1>
): Channel.Channel<OutElem, InElem, OutErr | OutErr1, InErr, OutDone | OutDone1, InDone, Env> =>
interruptWhen(self, Deferred.await(deferred)))
/** @internal */
export const map = dual<
<OutDone, OutDone2>(
f: (out: OutDone) => OutDone2
) => <OutElem, InElem, OutErr, InErr, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone2, InDone, Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutDone2>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (out: OutDone) => OutDone2
) => Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone2, InDone, Env>
>(2, <Env, InErr, InElem, InDone, OutErr, OutElem, OutDone, OutDone2>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (out: OutDone) => OutDone2
): Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone2, InDone, Env> =>
core.flatMap(self, (a) => core.sync(() => f(a))))
/** @internal */
export const mapEffect = dual<
<OutDone, OutDone1, OutErr1, Env1>(
f: (o: OutDone) => Effect.Effect<OutDone1, OutErr1, Env1>
) => <OutElem, InElem, OutErr, InErr, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem, OutErr1 | OutErr, InErr, OutDone1, InDone, Env1 | Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutDone1, OutErr1, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (o: OutDone) => Effect.Effect<OutDone1, OutErr1, Env1>
) => Channel.Channel<OutElem, InElem, OutErr1 | OutErr, InErr, OutDone1, InDone, Env1 | Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutDone1, OutErr1, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (o: OutDone) => Effect.Effect<OutDone1, OutErr1, Env1>
): Channel.Channel<OutElem, InElem, OutErr | OutErr1, InErr, OutDone1, InDone, Env | Env1> =>
core.flatMap(self, (z) => core.fromEffect(f(z))))
/** @internal */
export const mapError = dual<
<OutErr, OutErr2>(
f: (err: OutErr) => OutErr2
) => <OutElem, InElem, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem, OutErr2, InErr, OutDone, InDone, Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutErr2>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (err: OutErr) => OutErr2
) => Channel.Channel<OutElem, InElem, OutErr2, InErr, OutDone, InDone, Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutErr2>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (err: OutErr) => OutErr2
): Channel.Channel<OutElem, InElem, OutErr2, InErr, OutDone, InDone, Env> => mapErrorCause(self, Cause.map(f)))
/** @internal */
export const mapErrorCause = dual<
<OutErr, OutErr2>(
f: (cause: Cause.Cause<OutErr>) => Cause.Cause<OutErr2>
) => <OutElem, InElem, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem, InElem, OutErr2, InErr, OutDone, InDone, Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutErr2>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (cause: Cause.Cause<OutErr>) => Cause.Cause<OutErr2>
) => Channel.Channel<OutElem, InElem, OutErr2, InErr, OutDone, InDone, Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutErr2>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (cause: Cause.Cause<OutErr>) => Cause.Cause<OutErr2>
): Channel.Channel<OutElem, InElem, OutErr2, InErr, OutDone, InDone, Env> =>
core.catchAllCause(self, (cause) => core.failCause(f(cause))))
/** @internal */
export const mapOut = dual<
<OutElem, OutElem2>(
f: (o: OutElem) => OutElem2
) => <InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem2, InElem, OutErr, InErr, OutDone, InDone, Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutElem2>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (o: OutElem) => OutElem2
) => Channel.Channel<OutElem2, InElem, OutErr, InErr, OutDone, InDone, Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutElem2>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (o: OutElem) => OutElem2
): Channel.Channel<OutElem2, InElem, OutErr, InErr, OutDone, InDone, Env> => {
const reader: Channel.Channel<OutElem2, OutElem, OutErr, OutErr, OutDone, OutDone, Env> = core
.readWith({
onInput: (outElem) => core.flatMap(core.write(f(outElem)), () => reader),
onFailure: core.fail,
onDone: core.succeedNow
})
return core.pipeTo(self, reader)
})
/** @internal */
export const mapOutEffect = dual<
<OutElem, OutElem1, OutErr1, Env1>(
f: (o: OutElem) => Effect.Effect<OutElem1, OutErr1, Env1>
) => <InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem1, InElem, OutErr1 | OutErr, InErr, OutDone, InDone, Env1 | Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutElem1, OutErr1, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (o: OutElem) => Effect.Effect<OutElem1, OutErr1, Env1>
) => Channel.Channel<OutElem1, InElem, OutErr1 | OutErr, InErr, OutDone, InDone, Env1 | Env>
>(2, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutElem1, OutErr1, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (o: OutElem) => Effect.Effect<OutElem1, OutErr1, Env1>
): Channel.Channel<OutElem1, InElem, OutErr | OutErr1, InErr, OutDone, InDone, Env | Env1> => {
const reader: Channel.Channel<OutElem1, OutElem, OutErr | OutErr1, OutErr, OutDone, OutDone, Env | Env1> = core
.readWithCause({
onInput: (outElem) =>
pipe(
core.fromEffect(f(outElem)),
core.flatMap(core.write),
core.flatMap(() => reader)
),
onFailure: core.failCause,
onDone: core.succeedNow
})
return core.pipeTo(self, reader)
})
/** @internal */
export const mapOutEffectPar = dual<
<OutElem, OutElem1, OutErr1, Env1>(
f: (o: OutElem) => Effect.Effect<OutElem1, OutErr1, Env1>,
n: number
) => <InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<OutElem1, InElem, OutErr1 | OutErr, InErr, OutDone, InDone, Env1 | Env>,
<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutElem1, OutErr1, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (o: OutElem) => Effect.Effect<OutElem1, OutErr1, Env1>,
n: number
) => Channel.Channel<OutElem1, InElem, OutErr1 | OutErr, InErr, OutDone, InDone, Env1 | Env>
>(3, <OutElem, InElem, OutErr, InErr, OutDone, InDone, Env, OutElem1, OutErr1, Env1>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>,
f: (o: OutElem) => Effect.Effect<OutElem1, OutErr1, Env1>,
n: number
): Channel.Channel<OutElem1, InElem, OutErr | OutErr1, InErr, OutDone, InDone, Env | Env1> =>
pipe(
Effect.gen(function*($) {
const queue = yield* $(
Effect.acquireRelease(
Queue.bounded<Effect.Effect<Either.Either<OutElem1, OutDone>, OutErr | OutErr1, Env1>>(n),
(queue) => Queue.shutdown(queue)
)
)
const errorSignal = yield* $(Deferred.make<never, OutErr1>())
const withPermits = n === Number.POSITIVE_INFINITY ?
((_: number) => identity) :
(yield* $(Effect.makeSemaphore(n))).withPermits
const pull = yield* $(toPull(self))
yield* $(
Effect.matchCauseEffect(pull, {
onFailure: (cause) => Queue.offer(queue, Effect.failCause(cause)),
onSuccess: (either) =>
Either.match(
either,
{
onLeft: (outDone) => {
const lock = withPermits(n)
return Effect.zipRight(
Effect.interruptible(lock(Effect.unit)),
Effect.asUnit(Queue.offer(
queue,
Effect.succeed(Either.left(outDone))
))
)
},
onRight: (outElem) =>
Effect.gen(function*($) {
const deferred = yield* $(Deferred.make<OutElem1, OutErr1>())
const latch = yield* $(Deferred.make<void>())
yield* $(Effect.asUnit(Queue.offer(
queue,
Effect.map(Deferred.await(deferred), Either.right)
)))
yield* $(
Deferred.succeed(latch, void 0),
Effect.zipRight(
pipe(
Effect.uninterruptibleMask((restore) =>
pipe(
Effect.exit(restore(Deferred.await(errorSignal))),
Effect.raceFirst(Effect.exit(restore(f(outElem)))),
// TODO: remove
Effect.flatMap((exit) => Effect.suspend(() => exit))
)
),
Effect.tapErrorCause((cause) => Deferred.failCause(errorSignal, cause)),
Effect.intoDeferred(deferred)
)
),
withPermits(1),
Effect.forkScoped
)
yield* $(Deferred.await(latch))
})
}
)
}),
Effect.forever,
Effect.interruptible,
Effect.forkScoped
)
return queue
}),
Effect.map((queue) => {
const consumer: Channel.Channel<OutElem1, unknown, OutErr | OutErr1, unknown, OutDone, unknown, Env1> = unwrap(
Effect.matchCause(Effect.flatten(Queue.take(queue)), {
onFailure: core.failCause,
onSuccess: Either.match({
onLeft: core.succeedNow,
onRight: (outElem) => core.flatMap(core.write(outElem), () => consumer)
})
})
)
return consumer
}),
unwrapScoped
))
/** @internal */
export const mergeAll = (
options: {
readonly concurrency: number | "unbounded"
readonly bufferSize?: number | undefined
readonly mergeStrategy?: MergeStrategy.MergeStrategy | undefined
}
) => {
return <
OutElem,
InElem1,
OutErr1,
InErr1,
InDone1,
Env1,
InElem,
OutErr,
InErr,
InDone,
Env
>(
channels: Channel.Channel<
Channel.Channel<OutElem, InElem1, OutErr1, InErr1, unknown, InDone1, Env1>,
InElem,
OutErr,
InErr,
unknown,
InDone,
Env
>
): Channel.Channel<
OutElem,
InElem & InElem1,
OutErr | OutErr1,
InErr & InErr1,
unknown,
InDone & InDone1,
Env | Env1
> => mergeAllWith(options)(channels, constVoid)
}
/** @internal */
export const mergeAllUnbounded = <
OutElem,
InElem1,
OutErr1,
InErr1,
InDone1,
Env1,
InElem,
OutErr,
InErr,
InDone,
Env
>(
channels: Channel.Channel<
Channel.Channel<OutElem, InElem1, OutErr1, InErr1, unknown, InDone1, Env1>,
InElem,
OutErr,
InErr,
unknown,
InDone,
Env
>
): Channel.Channel<
OutElem,
InElem & InElem1,
OutErr | OutErr1,
InErr & InErr1,
unknown,
InDone & InDone1,
Env | Env1
> => mergeAllWith({ concurrency: "unbounded" })(channels, constVoid)
/** @internal */
export const mergeAllUnboundedWith = <
OutElem,
InElem1,
OutErr1,
InErr1,
OutDone,
InDone1,
Env1,
InElem,
OutErr,
InErr,
InDone,
Env
>(
channels: Channel.Channel<
Channel.Channel<OutElem, InElem1, OutErr1, InErr1, OutDone, InDone1, Env1>,
InElem,
OutErr,
InErr,
OutDone,
InDone,
Env
>,
f: (o1: OutDone, o2: OutDone) => OutDone
): Channel.Channel<
OutElem,
InElem & InElem1,
OutErr | OutErr1,
InErr & InErr1,
OutDone,
InDone & InDone1,
Env | Env1
> => mergeAllWith({ concurrency: "unbounded" })(channels, f)
/** @internal */
export const mergeAllWith = (
{
bufferSize = 16,
concurrency,
mergeStrategy = _mergeStrategy.BackPressure()
}: {
readonly concurrency: number | "unbounded"
readonly bufferSize?: number | undefined
readonly mergeStrategy?: MergeStrategy.MergeStrategy | undefined
}
) =>
<OutElem, InElem1, OutErr1, InErr1, OutDone, InDone1, Env1, InElem, OutErr, InErr, InDone, Env>(
channels: Channel.Channel<
Channel.Channel<OutElem, InElem1, OutErr1, InErr1, OutDone, InDone1, Env1>,
InElem,
OutErr,
InErr,
OutDone,
InDone,
Env
>,
f: (o1: OutDone, o2: OutDone) => OutDone
): Channel.Channel<
OutElem,
InElem & InElem1,
OutErr | OutErr1,
InErr & InErr1,
OutDone,
InDone & InDone1,
Env | Env1
> =>
pipe(
Effect.gen(function*($) {
const concurrencyN = concurrency === "unbounded" ? Number.MAX_SAFE_INTEGER : concurrency
const input = yield* $(singleProducerAsyncInput.make<
InErr & InErr1,
InElem & InElem1,
InDone & InDone1
>())
const queueReader = fromInput(input)
const queue = yield* $(
Effect.acquireRelease(
Queue.bounded<Effect.Effect<Either.Either<OutElem, OutDone>, OutErr | OutErr1, Env>>(bufferSize),
(queue) => Queue.shutdown(queue)
)
)
const cancelers = yield* $(
Effect.acquireRelease(
Queue.unbounded<Deferred.Deferred<void>>(),
(queue) => Queue.shutdown(queue)
)
)
const lastDone = yield* $(Ref.make<Option.Option<OutDone>>(Option.none()))
const errorSignal = yield* $(Deferred.make<void>())
const withPermits = (yield* $(Effect.makeSemaphore(concurrencyN)))
.withPermits
const pull = yield* $(toPull(channels))
const evaluatePull = (
pull: Effect.Effect<Either.Either<OutElem, OutDone>, OutErr | OutErr1, Env | Env1>
) =>
pipe(
Effect.flatMap(
pull,
Either.match({
onLeft: (done) => Effect.succeed(Option.some(done)),
onRight: (outElem) =>
Effect.as(
Queue.offer(queue, Effect.succeed(Either.right(outElem))),
Option.none()
)
})
),
Effect.repeat({ until: (_): _ is Option.Some<OutDone> => Option.isSome(_) }),
Effect.flatMap((outDone) =>
Ref.update(
lastDone,
Option.match({
onNone: () => Option.some(outDone.value),
onSome: (lastDone) => Option.some(f(lastDone, outDone.value))
})
)
),
Effect.catchAllCause((cause) =>
Cause.isInterrupted(cause) ?
Effect.failCause(cause) :
pipe(
Queue.offer(queue, Effect.failCause(cause)),
Effect.zipRight(Deferred.succeed(errorSignal, void 0)),
Effect.asUnit
)
)
)
yield* $(
Effect.matchCauseEffect(pull, {
onFailure: (cause) =>
pipe(
Queue.offer(queue, Effect.failCause(cause)),
Effect.zipRight(Effect.succeed(false))
),
onSuccess: Either.match({
onLeft: (outDone) =>
Effect.raceWith(
Effect.interruptible(Deferred.await(errorSignal)),
Effect.interruptible(withPermits(concurrencyN)(Effect.unit)),
{
onSelfDone: (_, permitAcquisition) => Effect.as(Fiber.interrupt(permitAcquisition), false),
onOtherDone: (_, failureAwait) =>
Effect.zipRight(
Fiber.interrupt(failureAwait),
pipe(
Ref.get(lastDone),
Effect.flatMap(Option.match({
onNone: () => Queue.offer(queue, Effect.succeed(Either.left(outDone))),
onSome: (lastDone) => Queue.offer(queue, Effect.succeed(Either.left(f(lastDone, outDone))))
})),
Effect.as(false)
)
)
}
),
onRight: (channel) =>
_mergeStrategy.match(mergeStrategy, {
onBackPressure: () =>
Effect.gen(function*($) {
const latch = yield* $(Deferred.make<void>())
const raceEffects: Effect.Effect<void, OutErr | OutErr1, Env | Env1> = pipe(
queueReader,
core.pipeTo(channel),
toPull,
Effect.flatMap((pull) =>
Effect.race(
evaluatePull(pull),
Effect.interruptible(Deferred.await(errorSignal))
)
),
Effect.scoped
)
yield* $(
Deferred.succeed(latch, void 0),
Effect.zipRight(raceEffects),
withPermits(1),
Effect.forkScoped
)
yield* $(Deferred.await(latch))
const errored = yield* $(Deferred.isDone(errorSignal))
return !errored
}),
onBufferSliding: () =>
Effect.gen(function*($) {
const canceler = yield* $(Deferred.make<void>())
const latch = yield* $(Deferred.make<void>())
const size = yield* $(Queue.size(cancelers))
yield* $(
Queue.take(cancelers),
Effect.flatMap((_) => Deferred.succeed(_, void 0)),
Effect.when(() => size >= concurrencyN)
)
yield* $(Queue.offer(cancelers, canceler))
const raceEffects: Effect.Effect<void, OutErr | OutErr1, Env | Env1> = pipe(
queueReader,
core.pipeTo(channel),
toPull,
Effect.flatMap((pull) =>
pipe(
evaluatePull(pull),
Effect.race(Effect.interruptible(Deferred.await(errorSignal))),
Effect.race(Effect.interruptible(Deferred.await(canceler)))
)
),
Effect.scoped
)
yield* $(
Deferred.succeed(latch, void 0),
Effect.zipRight(raceEffects),
withPermits(1),
Effect.forkScoped
)
yield* $(Deferred.await(latch))
const errored = yield* $(Deferred.isDone(errorSignal))
return !errored
})
})
})
}),
Effect.repeat({ while: (_) => _ }),
Effect.forkScoped
)
return [queue, input] as const
}),
Effect.map(([queue, input]) => {
const consumer: Channel.Channel<OutElem, unknown, OutErr | OutErr1, unknown, OutDone, unknown, Env | Env1> = pipe(
Queue.take(queue),
Effect.flatten,
Effect.matchCause({
onFailure: core.failCause,
onSuccess: Either.match({
onLeft: core.succeedNow,
onRight: (outElem) => core.flatMap(core.write(outElem), () => consumer)
})
}),
unwrap
)
return core.embedInput(consumer, input)
}),
unwrapScoped
)
/** @internal */
export const mergeMap = dual<
<OutElem, OutElem1, InElem1, OutErr1, InErr1, Z, InDone1, Env1>(
f: (outElem: OutElem) => Channel.Channel<OutElem1, InElem1, OutErr1, InErr1, Z, InDone1, Env1>,
options: {
readonly concurrency: number | "unbounded"
readonly bufferSize?: number | undefined
readonly mergeStrategy?: MergeStrategy.MergeStrategy | undefined
}
) => <InElem, OutErr, InErr, OutDone, InDone, Env>(
self: Channel.Channel<OutElem, InElem, OutErr, InErr, OutDone, InDone, Env>
) => Channel.Channel<
OutElem1,
InElem & InElem1,
OutErr1 | OutErr