import * as Arr from "../Array.js"
import type * as Cause from "../Cause.js"
import * as Chunk from "../Chunk.js"
import * as Clock from "../Clock.js"
import * as Context from "../Context.js"
import * as Duration from "../Duration.js"
import type * as Effect from "../Effect.js"
import type { Exit } from "../Exit.js"
import type * as Fiber from "../Fiber.js"
import type * as FiberId from "../FiberId.js"
import type * as FiberRef from "../FiberRef.js"
import * as FiberRefs from "../FiberRefs.js"
import type * as FiberRefsPatch from "../FiberRefsPatch.js"
import type { LazyArg } from "../Function.js"
import { constFalse, constTrue, constVoid, dual, identity, pipe } from "../Function.js"
import * as HashMap from "../HashMap.js"
import * as HashSet from "../HashSet.js"
import * as List from "../List.js"
import * as LogLevel from "../LogLevel.js"
import * as LogSpan from "../LogSpan.js"
import type * as Metric from "../Metric.js"
import type * as MetricLabel from "../MetricLabel.js"
import * as Option from "../Option.js"
import * as Predicate from "../Predicate.js"
import type * as Random from "../Random.js"
import * as Ref from "../Ref.js"
import type * as runtimeFlagsPatch from "../RuntimeFlagsPatch.js"
import * as Tracer from "../Tracer.js"
import type * as Types from "../Types.js"
import type { Unify } from "../Unify.js"
import { internalCall } from "../Utils.js"
import * as internalCause from "./cause.js"
import { clockTag } from "./clock.js"
import * as core from "./core.js"
import * as defaultServices from "./defaultServices.js"
import * as doNotation from "./doNotation.js"
import * as fiberRefsPatch from "./fiberRefs/patch.js"
import type { FiberRuntime } from "./fiberRuntime.js"
import * as metricLabel from "./metric/label.js"
import * as runtimeFlags from "./runtimeFlags.js"
import * as internalTracer from "./tracer.js"
/* @internal */
export const annotateLogs = dual<
{
(key: string, value: unknown): (effect: Effect.Effect) => Effect.Effect
(
values: Record
): (effect: Effect.Effect) => Effect.Effect
},
{
(effect: Effect.Effect, key: string, value: unknown): Effect.Effect
(effect: Effect.Effect, values: Record): Effect.Effect
}
>(
(args) => core.isEffect(args[0]),
function() {
const args = arguments
return core.fiberRefLocallyWith(
args[0] as Effect.Effect,
core.currentLogAnnotations,
typeof args[1] === "string"
? HashMap.set(args[1], args[2])
: (annotations) =>
Object.entries(args[1] as Record).reduce(
(acc, [key, value]) => HashMap.set(acc, key, value),
annotations
)
)
}
)
/* @internal */
export const asSome = (self: Effect.Effect): Effect.Effect, E, R> =>
core.map(self, Option.some)
/* @internal */
export const asSomeError = (self: Effect.Effect): Effect.Effect, R> =>
core.mapError(self, Option.some)
/* @internal */
export const try_: {
(options: {
readonly try: LazyArg
readonly catch: (error: unknown) => E
}): Effect.Effect
(thunk: LazyArg): Effect.Effect
} = (
arg: LazyArg | {
readonly try: LazyArg
readonly catch: (error: unknown) => E
}
) => {
let evaluate: LazyArg
let onFailure: ((error: unknown) => E) | undefined = undefined
if (typeof arg === "function") {
evaluate = arg
} else {
evaluate = arg.try
onFailure = arg.catch
}
return core.suspend(() => {
try {
return core.succeed(internalCall(evaluate))
} catch (error) {
return core.fail(
onFailure
? internalCall(() => onFailure(error))
: new core.UnknownException(error, "An unknown error occurred in Effect.try")
)
}
})
}
/* @internal */
export const _catch: {
(
discriminator: N,
options: {
readonly failure: K
readonly onFailure: (error: Extract) => Effect.Effect
}
): (self: Effect.Effect) => Effect.Effect<
A | A1,
Exclude | E1,
R | R1
>
(
self: Effect.Effect,
discriminator: N,
options: {
readonly failure: K
readonly onFailure: (error: Extract) => Effect.Effect
}
): Effect.Effect | E1, R | R1>
} = dual(
3,
(self, tag, options) =>
core.catchAll(self, (e) => {
if (Predicate.hasProperty(e, tag) && e[tag] === options.failure) {
return options.onFailure(e)
}
return core.fail(e)
})
)
/* @internal */
export const catchAllDefect = dual<
(
f: (defect: unknown) => Effect.Effect
) => (self: Effect.Effect) => Effect.Effect,
(
self: Effect.Effect,
f: (defect: unknown) => Effect.Effect
) => Effect.Effect
>(2, (
self: Effect.Effect,
f: (defect: unknown) => Effect.Effect
): Effect.Effect =>
core.catchAllCause(
self,
(cause): Effect.Effect => {
const option = internalCause.find(cause, (_) => internalCause.isDieType(_) ? Option.some(_) : Option.none())
switch (option._tag) {
case "None": {
return core.failCause(cause)
}
case "Some": {
return f(option.value.defect)
}
}
}
))
/* @internal */
export const catchSomeCause: {
(
f: (cause: Cause.Cause>) => Option.Option>
): (self: Effect.Effect) => Effect.Effect
(
self: Effect.Effect,
f: (cause: Cause.Cause>) => Option.Option>
): Effect.Effect
} = dual(
2,
(
self: Effect.Effect,
f: (cause: Cause.Cause>) => Option.Option>
): Effect.Effect =>
core.matchCauseEffect(self, {
onFailure: (cause): Effect.Effect => {
const option = f(cause)
switch (option._tag) {
case "None": {
return core.failCause(cause)
}
case "Some": {
return option.value
}
}
},
onSuccess: core.succeed
})
)
/* @internal */
export const catchSomeDefect = dual<
(
pf: (defect: unknown) => Option.Option>
) => (self: Effect.Effect) => Effect.Effect,
(
self: Effect.Effect,
pf: (defect: unknown) => Option.Option>
) => Effect.Effect
>(
2,
(
self: Effect.Effect,
pf: (defect: unknown) => Option.Option>
): Effect.Effect =>
core.catchAllCause(
self,
(cause): Effect.Effect => {
const option = internalCause.find(cause, (_) => internalCause.isDieType(_) ? Option.some(_) : Option.none())
switch (option._tag) {
case "None": {
return core.failCause(cause)
}
case "Some": {
const optionEffect = pf(option.value.defect)
return optionEffect._tag === "Some" ? optionEffect.value : core.failCause(cause)
}
}
}
)
)
/* @internal */
export const catchTag: {
<
E,
const K extends Arr.NonEmptyReadonlyArray,
A1,
E1,
R1
>(
...args: [
...tags: K,
f: (e: Extract, { _tag: K[number] }>) => Effect.Effect
]
): (self: Effect.Effect) => Effect.Effect | E1, R | R1>
<
A,
E,
R,
const K extends Arr.NonEmptyReadonlyArray,
A1,
E1,
R1
>(
self: Effect.Effect,
...args: [
...tags: K,
f: (e: Extract, { _tag: K[number] }>) => Effect.Effect
]
): Effect.Effect | E1, R | R1>
} = dual(
(args: any) => core.isEffect(args[0]),
, R1, E1, A1>(
self: Effect.Effect,
...args: [
...tags: K & { [I in keyof K]: E extends { _tag: string } ? E["_tag"] : never },
f: (e: Extract, { _tag: K[number] }>) => Effect.Effect
]
): Effect.Effect | E1, R | R1> => {
const f = args[args.length - 1] as any
let predicate: Predicate.Predicate
if (args.length === 2) {
predicate = Predicate.isTagged(args[0] as string)
} else {
predicate = (e) => {
const tag = Predicate.hasProperty(e, "_tag") ? e["_tag"] : undefined
if (!tag) return false
for (let i = 0; i < args.length - 1; i++) {
if (args[i] === tag) return true
}
return false
}
}
return core.catchIf(self, predicate as Predicate.Refinement>, f) as any
}
) as any
/** @internal */
export const catchTags: {
<
E,
Cases extends (E extends { _tag: string } ? {
[K in E["_tag"]]+?: (error: Extract) => Effect.Effect
} :
{})
>(
cases: Cases
): (self: Effect.Effect) => Effect.Effect<
| A
| {
[K in keyof Cases]: Cases[K] extends ((...args: Array) => Effect.Effect) ? A : never
}[keyof Cases],
| Exclude
| {
[K in keyof Cases]: Cases[K] extends ((...args: Array) => Effect.Effect) ? E : never
}[keyof Cases],
| R
| {
[K in keyof Cases]: Cases[K] extends ((...args: Array) => Effect.Effect) ? R : never
}[keyof Cases]
>
<
R,
E,
A,
Cases extends (E extends { _tag: string } ? {
[K in E["_tag"]]+?: (error: Extract) => Effect.Effect
} :
{})
>(
self: Effect.Effect,
cases: Cases
): Effect.Effect<
| A
| {
[K in keyof Cases]: Cases[K] extends ((...args: Array) => Effect.Effect) ? A : never
}[keyof Cases],
| Exclude
| {
[K in keyof Cases]: Cases[K] extends ((...args: Array) => Effect.Effect) ? E : never
}[keyof Cases],
| R
| {
[K in keyof Cases]: Cases[K] extends ((...args: Array) => Effect.Effect) ? R : never
}[keyof Cases]
>
} = dual(2, (self, cases) => {
let keys: Array
return core.catchIf(
self,
(e): e is { readonly _tag: string } => {
keys ??= Object.keys(cases)
return Predicate.hasProperty(e, "_tag") && Predicate.isString(e["_tag"]) && keys.includes(e["_tag"])
},
(e) => cases[e["_tag"]](e)
)
})
/* @internal */
export const cause = (self: Effect.Effect): Effect.Effect, never, R> =>
core.matchCause(self, { onFailure: identity, onSuccess: () => internalCause.empty })
/* @internal */
export const clockWith: (f: (clock: Clock.Clock) => Effect.Effect) => Effect.Effect =
Clock.clockWith
/* @internal */
export const clock: Effect.Effect = clockWith(core.succeed)
/* @internal */
export const delay = dual<
(duration: Duration.DurationInput) => (self: Effect.Effect) => Effect.Effect,
(self: Effect.Effect, duration: Duration.DurationInput) => Effect.Effect
>(2, (self, duration) => core.zipRight(Clock.sleep(duration), self))
/* @internal */
export const descriptorWith = (
f: (descriptor: Fiber.Fiber.Descriptor) => Effect.Effect
): Effect.Effect =>
core.withFiberRuntime((state, status) =>
f({
id: state.id(),
status,
interruptors: internalCause.interruptors(state.getFiberRef(core.currentInterruptedCause))
})
) as Effect.Effect
/* @internal */
export const allowInterrupt: Effect.Effect = descriptorWith(
(descriptor) =>
HashSet.size(descriptor.interruptors) > 0
? core.interrupt
: core.void
)
/* @internal */
export const descriptor: Effect.Effect = descriptorWith(core.succeed)
/* @internal */
export const diffFiberRefs = (
self: Effect.Effect
): Effect.Effect<[FiberRefsPatch.FiberRefsPatch, A], E, R> => summarized(self, fiberRefs, fiberRefsPatch.diff)
/* @internal */
export const diffFiberRefsAndRuntimeFlags = (
self: Effect.Effect
): Effect.Effect<[[FiberRefsPatch.FiberRefsPatch, runtimeFlagsPatch.RuntimeFlagsPatch], A], E, R> =>
summarized(
self,
core.zip(fiberRefs, core.runtimeFlags),
([refs, flags], [refsNew, flagsNew]) => [fiberRefsPatch.diff(refs, refsNew), runtimeFlags.diff(flags, flagsNew)]
)
/* @internal */
export const Do: Effect.Effect<{}> = core.succeed({})
/* @internal */
export const bind: {
(
name: Exclude,
f: (a: Types.NoInfer) => Effect.Effect
): (
self: Effect.Effect
) => Effect.Effect<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, E2 | E1, R2 | R1>
(
self: Effect.Effect,
name: Exclude,
f: (a: Types.NoInfer) => Effect.Effect
): Effect.Effect<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, E1 | E2, R1 | R2>
} = doNotation.bind(core.map, core.flatMap)
/* @internal */
export const bindTo: {
(name: N): (self: Effect.Effect) => Effect.Effect<{ [K in N]: A }, E, R>
(self: Effect.Effect, name: N): Effect.Effect<{ [K in N]: A }, E, R>
} = doNotation.bindTo(core.map)
/* @internal */
export const let_: {
(
name: Exclude,
f: (a: Types.NoInfer) => B
): (
self: Effect.Effect
) => Effect.Effect<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, E, R>
(
self: Effect.Effect,
name: Exclude,
f: (a: Types.NoInfer) => B
): Effect.Effect<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, E, R>
} = doNotation.let_(core.map)
/* @internal */
export const dropUntil: {
(
predicate: (a: Types.NoInfer, i: number) => Effect.Effect
): (elements: Iterable) => Effect.Effect, E, R>
(
elements: Iterable,
predicate: (a: A, i: number) => Effect.Effect
): Effect.Effect, E, R>
} = dual(
2,
(
elements: Iterable,
predicate: (a: A, i: number) => Effect.Effect
): Effect.Effect, E, R> =>
core.suspend(() => {
const iterator = elements[Symbol.iterator]()
const builder: Array = []
let next: IteratorResult
let dropping: Effect.Effect = core.succeed(false)
let i = 0
while ((next = iterator.next()) && !next.done) {
const a = next.value
const index = i++
dropping = core.flatMap(dropping, (bool) => {
if (bool) {
builder.push(a)
return core.succeed(true)
}
return predicate(a, index)
})
}
return core.map(dropping, () => builder)
})
)
/* @internal */
export const dropWhile: {
(
predicate: (a: Types.NoInfer, i: number) => Effect.Effect
): (elements: Iterable) => Effect.Effect, E, R>
(
elements: Iterable,
predicate: (a: A, i: number) => Effect.Effect
): Effect.Effect, E, R>
} = dual(
2,
(
elements: Iterable,
predicate: (a: A, i: number) => Effect.Effect
): Effect.Effect, E, R> =>
core.suspend(() => {
const iterator = elements[Symbol.iterator]()
const builder: Array = []
let next
let dropping: Effect.Effect = core.succeed(true)
let i = 0
while ((next = iterator.next()) && !next.done) {
const a = next.value
const index = i++
dropping = core.flatMap(dropping, (d) =>
core.map(d ? predicate(a, index) : core.succeed(false), (b) => {
if (!b) {
builder.push(a)
}
return b
}))
}
return core.map(dropping, () => builder)
})
)
/* @internal */
export const contextWith = (f: (context: Context.Context) => A): Effect.Effect =>
core.map(core.context(), f)
/* @internal */
export const eventually = (self: Effect.Effect): Effect.Effect =>
core.orElse(self, () => core.flatMap(core.yieldNow(), () => eventually(self)))
/* @internal */
export const filterMap = dual<
, B>(
pf: (a: Effect.Effect.Success) => Option.Option
) => (elements: Iterable) => Effect.Effect, Effect.Effect.Error, Effect.Effect.Context>,
, B>(
elements: Iterable,
pf: (a: Effect.Effect.Success) => Option.Option
) => Effect.Effect, Effect.Effect.Error, Effect.Effect.Context>
>(2, (elements, pf) =>
core.map(
core.forEachSequential(elements, identity),
Arr.filterMap(pf)
))
/* @internal */
export const filterOrDie: {
(
refinement: Predicate.Refinement, B>,
orDieWith: (a: Types.EqualsWith>) => unknown
): (self: Effect.Effect) => Effect.Effect
(
predicate: Predicate.Predicate>,
orDieWith: (a: Types.NoInfer) => unknown
): (self: Effect.Effect) => Effect.Effect
(
self: Effect.Effect,
refinement: Predicate.Refinement,
orDieWith: (a: Types.EqualsWith>) => unknown
): Effect.Effect
(
self: Effect.Effect,
predicate: Predicate.Predicate,
orDieWith: (a: A) => unknown
): Effect.Effect
} = dual(
3,
(
self: Effect.Effect,
predicate: Predicate.Predicate,
orDieWith: (a: A) => unknown
): Effect.Effect => filterOrElse(self, predicate, (a) => core.dieSync(() => orDieWith(a)))
)
/* @internal */
export const filterOrDieMessage: {
(
refinement: Predicate.Refinement, B>,
message: string
): (self: Effect.Effect) => Effect.Effect
(
predicate: Predicate.Predicate>,
message: string
): (self: Effect.Effect) => Effect.Effect
(
self: Effect.Effect,
refinement: Predicate.Refinement,
message: string
): Effect.Effect
(
self: Effect.Effect,
predicate: Predicate.Predicate,
message: string
): Effect.Effect
} = dual(
3,
(self: Effect.Effect, predicate: Predicate.Predicate, message: string): Effect.Effect =>
filterOrElse(self, predicate, () => core.dieMessage(message))
)
/* @internal */
export const filterOrElse: {
(
refinement: Predicate.Refinement, B>,
orElse: (a: Types.EqualsWith, Exclude, B>>) => Effect.Effect
): (self: Effect.Effect) => Effect.Effect
(
predicate: Predicate.Predicate>,
orElse: (a: Types.NoInfer) => Effect.Effect
): (self: Effect.Effect) => Effect.Effect
(
self: Effect.Effect,
refinement: Predicate.Refinement,
orElse: (a: Types.EqualsWith>) => Effect.Effect
): Effect.Effect
(
self: Effect.Effect,
predicate: Predicate.Predicate,
orElse: (a: A) => Effect.Effect
): Effect.Effect
} = dual(3, (
self: Effect.Effect,
predicate: Predicate.Predicate,
orElse: (a: A) => Effect.Effect
): Effect.Effect =>
core.flatMap(
self,
(a) => predicate(a) ? core.succeed(a) : orElse(a)
))
/** @internal */
export const liftPredicate = dual<
(
predicate: Predicate.Refinement | Predicate.Predicate,
orFailWith: (a: Types.EqualsWith>) => E
) => (a: A) => Effect.Effect, E>,
(
self: A,
predicate: Predicate.Refinement | Predicate.Predicate,
orFailWith: (a: Types.EqualsWith>) => E
) => Effect.Effect
>(
3,
(
self: A,
predicate: Predicate.Refinement | Predicate.Predicate,
orFailWith: (a: Types.EqualsWith>) => E
): Effect.Effect =>
core.suspend(() => predicate(self) ? core.succeed(self as B) : core.fail(orFailWith(self as any)))
)
/* @internal */
export const filterOrFail: {
(
refinement: Predicate.Refinement, B>,
orFailWith: (a: Types.EqualsWith, Exclude, B>>) => E2
): (self: Effect.Effect) => Effect.Effect, E2 | E, R>
(
predicate: Predicate.Predicate>,
orFailWith: (a: Types.NoInfer) => E2
): (self: Effect.Effect) => Effect.Effect
(
self: Effect.Effect,
refinement: Predicate.Refinement,
orFailWith: (a: Types.EqualsWith>) => E2
): Effect.Effect, E2 | E, R>
(
self: Effect.Effect,
predicate: Predicate.Predicate,
orFailWith: (a: A) => E2
): Effect.Effect
(
refinement: Predicate.Refinement, B>
): (self: Effect.Effect) => Effect.Effect, Cause.NoSuchElementException | E, R>
(
predicate: Predicate.Predicate>
): (self: Effect.Effect) => Effect.Effect
(
self: Effect.Effect,
refinement: Predicate.Refinement
): Effect.Effect, E | Cause.NoSuchElementException, R>
(
self: Effect.Effect,
predicate: Predicate.Predicate
): Effect.Effect
} = dual((args) => core.isEffect(args[0]), (
self: Effect.Effect,
predicate: Predicate.Predicate,
orFailWith?: (a: A) => E2
): Effect.Effect =>
filterOrElse(
self,
predicate,
(a): Effect.Effect =>
orFailWith === undefined ? core.fail(new core.NoSuchElementException()) : core.failSync(() => orFailWith(a))
))
/* @internal */
export const findFirst: {
(
predicate: (a: Types.NoInfer, i: number) => Effect.Effect
): (elements: Iterable) => Effect.Effect, E, R>
(
elements: Iterable,
predicate: (a: Types.NoInfer, i: number) => Effect.Effect
): Effect.Effect, E, R>
} = dual(
2,
(
elements: Iterable,
predicate: (a: Types.NoInfer, i: number) => Effect.Effect
): Effect.Effect, E, R> =>
core.suspend(() => {
const iterator = elements[Symbol.iterator]()
const next = iterator.next()
if (!next.done) {
return findLoop(iterator, 0, predicate, next.value)
}
return core.succeed(Option.none())
})
)
const findLoop = (
iterator: Iterator,
index: number,
f: (a: A, i: number) => Effect.Effect,
value: A
): Effect.Effect, E, R> =>
core.flatMap(f(value, index), (result) => {
if (result) {
return core.succeed(Option.some(value))
}
const next = iterator.next()
if (!next.done) {
return findLoop(iterator, index + 1, f, next.value)
}
return core.succeed(Option.none())
})
/* @internal */
export const firstSuccessOf = >(
effects: Iterable
): Effect.Effect, Effect.Effect.Error, Effect.Effect.Context> =>
core.suspend(() => {
const list = Chunk.fromIterable(effects)
if (!Chunk.isNonEmpty(list)) {
return core.dieSync(() => new core.IllegalArgumentException(`Received an empty collection of effects`))
}
return pipe(
Chunk.tailNonEmpty(list),
Arr.reduce(Chunk.headNonEmpty(list), (left, right) => core.orElse(left, () => right) as Eff)
)
})
/* @internal */
export const flipWith: {
(
f: (effect: Effect.Effect) => Effect.Effect
): (self: Effect.Effect) => Effect.Effect
(
self: Effect.Effect,
f: (effect: Effect.Effect