effect 3.3.5 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Micro/package.json +6 -0
- package/dist/cjs/Array.js +18 -3
- package/dist/cjs/Array.js.map +1 -1
- package/dist/cjs/Chunk.js +13 -2
- package/dist/cjs/Chunk.js.map +1 -1
- package/dist/cjs/Effect.js +110 -8
- package/dist/cjs/Effect.js.map +1 -1
- package/dist/cjs/Either.js +31 -1
- package/dist/cjs/Either.js.map +1 -1
- package/dist/cjs/ManagedRuntime.js.map +1 -1
- package/dist/cjs/Micro.js +2383 -0
- package/dist/cjs/Micro.js.map +1 -0
- package/dist/cjs/Option.js +1 -2
- package/dist/cjs/Option.js.map +1 -1
- package/dist/cjs/Schedule.js +2 -2
- package/dist/cjs/Stream.js.map +1 -1
- package/dist/cjs/Tuple.js +16 -9
- package/dist/cjs/Tuple.js.map +1 -1
- package/dist/cjs/index.js +4 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/internal/core-effect.js +4 -2
- package/dist/cjs/internal/core-effect.js.map +1 -1
- package/dist/cjs/internal/core.js +12 -2
- package/dist/cjs/internal/core.js.map +1 -1
- package/dist/cjs/internal/fiberRuntime.js +32 -0
- package/dist/cjs/internal/fiberRuntime.js.map +1 -1
- package/dist/cjs/internal/stream.js.map +1 -1
- package/dist/cjs/internal/version.js +1 -1
- package/dist/dts/Array.d.ts +14 -0
- package/dist/dts/Array.d.ts.map +1 -1
- package/dist/dts/Cause.d.ts +1 -1
- package/dist/dts/Chunk.d.ts +11 -0
- package/dist/dts/Chunk.d.ts.map +1 -1
- package/dist/dts/Effect.d.ts +109 -5
- package/dist/dts/Effect.d.ts.map +1 -1
- package/dist/dts/Either.d.ts +35 -0
- package/dist/dts/Either.d.ts.map +1 -1
- package/dist/dts/ManagedRuntime.d.ts +15 -0
- package/dist/dts/ManagedRuntime.d.ts.map +1 -1
- package/dist/dts/Micro.d.ts +2002 -0
- package/dist/dts/Micro.d.ts.map +1 -0
- package/dist/dts/Option.d.ts +2 -0
- package/dist/dts/Option.d.ts.map +1 -1
- package/dist/dts/Schedule.d.ts +2 -2
- package/dist/dts/Stream.d.ts +45 -6
- package/dist/dts/Stream.d.ts.map +1 -1
- package/dist/dts/Tuple.d.ts +18 -0
- package/dist/dts/Tuple.d.ts.map +1 -1
- package/dist/dts/index.d.ts +7 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/internal/core-effect.d.ts.map +1 -1
- package/dist/dts/internal/core.d.ts.map +1 -1
- package/dist/dts/internal/fiberRuntime.d.ts.map +1 -1
- package/dist/esm/Array.js +14 -0
- package/dist/esm/Array.js.map +1 -1
- package/dist/esm/Chunk.js +11 -0
- package/dist/esm/Chunk.js.map +1 -1
- package/dist/esm/Effect.js +107 -5
- package/dist/esm/Effect.js.map +1 -1
- package/dist/esm/Either.js +30 -0
- package/dist/esm/Either.js.map +1 -1
- package/dist/esm/ManagedRuntime.js.map +1 -1
- package/dist/esm/Micro.js +2307 -0
- package/dist/esm/Micro.js.map +1 -0
- package/dist/esm/Option.js +1 -1
- package/dist/esm/Option.js.map +1 -1
- package/dist/esm/Schedule.js +2 -2
- package/dist/esm/Stream.js.map +1 -1
- package/dist/esm/Tuple.js +15 -8
- package/dist/esm/Tuple.js.map +1 -1
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/core-effect.js +2 -0
- package/dist/esm/internal/core-effect.js.map +1 -1
- package/dist/esm/internal/core.js +10 -1
- package/dist/esm/internal/core.js.map +1 -1
- package/dist/esm/internal/fiberRuntime.js +32 -0
- package/dist/esm/internal/fiberRuntime.js.map +1 -1
- package/dist/esm/internal/stream.js.map +1 -1
- package/dist/esm/internal/version.js +1 -1
- package/package.json +9 -1
- package/src/Array.ts +15 -0
- package/src/Cause.ts +1 -1
- package/src/Chunk.ts +12 -0
- package/src/Effect.ts +117 -5
- package/src/Either.ts +51 -0
- package/src/ManagedRuntime.ts +16 -0
- package/src/Micro.ts +3826 -0
- package/src/Option.ts +12 -1
- package/src/Schedule.ts +2 -2
- package/src/Stream.ts +60 -8
- package/src/Tuple.ts +18 -8
- package/src/index.ts +8 -0
- package/src/internal/core-effect.ts +33 -0
- package/src/internal/core.ts +18 -1
- package/src/internal/fiberRuntime.ts +32 -0
- package/src/internal/stream.ts +8 -4
- package/src/internal/version.ts +1 -1
package/src/Micro.ts
ADDED
|
@@ -0,0 +1,3826 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A lightweight alternative to the `Effect` data type, with a subset of the functionality.
|
|
3
|
+
*
|
|
4
|
+
* @since 3.4.0
|
|
5
|
+
* @experimental
|
|
6
|
+
*/
|
|
7
|
+
import type { Channel, ChannelTypeId } from "./Channel.js"
|
|
8
|
+
import * as Context from "./Context.js"
|
|
9
|
+
import type { Effect, EffectTypeId } from "./Effect.js"
|
|
10
|
+
import * as Effectable from "./Effectable.js"
|
|
11
|
+
import * as Either from "./Either.js"
|
|
12
|
+
import { constTrue, constVoid, dual, identity, type LazyArg } from "./Function.js"
|
|
13
|
+
import { globalValue } from "./GlobalValue.js"
|
|
14
|
+
import type { Inspectable } from "./Inspectable.js"
|
|
15
|
+
import { NodeInspectSymbol, toStringUnknown } from "./Inspectable.js"
|
|
16
|
+
import { StructuralPrototype } from "./internal/effectable.js"
|
|
17
|
+
import { SingleShotGen } from "./internal/singleShotGen.js"
|
|
18
|
+
import * as Option from "./Option.js"
|
|
19
|
+
import { type Pipeable, pipeArguments } from "./Pipeable.js"
|
|
20
|
+
import { isIterable, isTagged, type Predicate, type Refinement } from "./Predicate.js"
|
|
21
|
+
import type { ReadonlyRecord } from "./Record.js"
|
|
22
|
+
import type { Sink, SinkTypeId } from "./Sink.js"
|
|
23
|
+
import type { Stream, StreamTypeId } from "./Stream.js"
|
|
24
|
+
import type { Concurrency, Covariant, Equals, NoInfer, NotFunction, Simplify } from "./Types.js"
|
|
25
|
+
import { YieldWrap, yieldWrapGet } from "./Utils.js"
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @since 3.4.0
|
|
29
|
+
* @experimental
|
|
30
|
+
* @category type ids
|
|
31
|
+
*/
|
|
32
|
+
export const TypeId: unique symbol = Symbol.for("effect/Micro")
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @since 3.4.0
|
|
36
|
+
* @experimental
|
|
37
|
+
* @category type ids
|
|
38
|
+
*/
|
|
39
|
+
export type TypeId = typeof TypeId
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @since 3.4.0
|
|
43
|
+
* @experimental
|
|
44
|
+
* @category symbols
|
|
45
|
+
*/
|
|
46
|
+
export const runSymbol: unique symbol = Symbol.for("effect/Micro/runSymbol")
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @since 3.4.0
|
|
50
|
+
* @experimental
|
|
51
|
+
* @category symbols
|
|
52
|
+
*/
|
|
53
|
+
export type runSymbol = typeof runSymbol
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* A lightweight alternative to the `Effect` data type, with a subset of the functionality.
|
|
57
|
+
*
|
|
58
|
+
* @since 3.4.0
|
|
59
|
+
* @experimental
|
|
60
|
+
* @category models
|
|
61
|
+
*/
|
|
62
|
+
export interface Micro<out A, out E = never, out R = never> extends Effect<A, E, R> {
|
|
63
|
+
readonly [TypeId]: Micro.Variance<A, E, R>
|
|
64
|
+
readonly [runSymbol]: (env: Env<any>, onResult: (result: Result<A, E>) => void) => void
|
|
65
|
+
[Symbol.iterator](): MicroIterator<Micro<A, E, R>>
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @since 3.4.0
|
|
70
|
+
* @experimental
|
|
71
|
+
*/
|
|
72
|
+
export declare namespace Micro {
|
|
73
|
+
/**
|
|
74
|
+
* @since 3.4.0
|
|
75
|
+
* @experimental
|
|
76
|
+
*/
|
|
77
|
+
export interface Variance<A, E, R> {
|
|
78
|
+
_A: Covariant<A>
|
|
79
|
+
_E: Covariant<E>
|
|
80
|
+
_R: Covariant<R>
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @since 3.4.0
|
|
85
|
+
* @experimental
|
|
86
|
+
*/
|
|
87
|
+
export type Success<T> = T extends Micro<infer _A, infer _E, infer _R> ? _A : never
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @since 3.4.0
|
|
91
|
+
* @experimental
|
|
92
|
+
*/
|
|
93
|
+
export type Error<T> = T extends Micro<infer _A, infer _E, infer _R> ? _E : never
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @since 3.4.0
|
|
97
|
+
* @experimental
|
|
98
|
+
*/
|
|
99
|
+
export type Context<T> = T extends Micro<infer _A, infer _E, infer _R> ? _R : never
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @since 3.4.0
|
|
104
|
+
* @experimental
|
|
105
|
+
* @category guards
|
|
106
|
+
*/
|
|
107
|
+
export const isMicro = (u: unknown): u is Micro<any, any, any> => typeof u === "object" && u !== null && TypeId in u
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @since 3.4.0
|
|
111
|
+
* @experimental
|
|
112
|
+
* @category models
|
|
113
|
+
*/
|
|
114
|
+
export interface MicroIterator<T extends Micro<any, any, any>> {
|
|
115
|
+
next(...args: ReadonlyArray<any>): IteratorResult<YieldWrap<T>, Micro.Success<T>>
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ----------------------------------------------------------------------------
|
|
119
|
+
// Failures
|
|
120
|
+
// ----------------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @since 3.4.0
|
|
124
|
+
* @experimental
|
|
125
|
+
* @category failure
|
|
126
|
+
*/
|
|
127
|
+
export const FailureTypeId = Symbol.for("effect/Micro/Failure")
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @since 3.4.0
|
|
131
|
+
* @experimental
|
|
132
|
+
* @category failure
|
|
133
|
+
*/
|
|
134
|
+
export type FailureTypeId = typeof FailureTypeId
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* A Micro Failure is a data type that represents the different ways a Micro can fail.
|
|
138
|
+
*
|
|
139
|
+
* @since 3.4.0
|
|
140
|
+
* @experimental
|
|
141
|
+
* @category failure
|
|
142
|
+
*/
|
|
143
|
+
export type Failure<E> = Failure.Unexpected | Failure.Expected<E> | Failure.Aborted
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @since 3.4.0
|
|
147
|
+
* @experimental
|
|
148
|
+
* @category failure
|
|
149
|
+
*/
|
|
150
|
+
export declare namespace Failure {
|
|
151
|
+
/**
|
|
152
|
+
* @since 3.4.0
|
|
153
|
+
* @experimental
|
|
154
|
+
*/
|
|
155
|
+
export interface Proto<Tag extends string, E> extends Pipeable, globalThis.Error {
|
|
156
|
+
readonly [FailureTypeId]: {
|
|
157
|
+
_E: Covariant<E>
|
|
158
|
+
}
|
|
159
|
+
readonly _tag: Tag
|
|
160
|
+
readonly traces: ReadonlyArray<string>
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* @since 3.4.0
|
|
165
|
+
* @experimental
|
|
166
|
+
* @category failure
|
|
167
|
+
*/
|
|
168
|
+
export interface Unexpected extends Proto<"Unexpected", never> {
|
|
169
|
+
readonly defect: unknown
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @since 3.4.0
|
|
174
|
+
* @experimental
|
|
175
|
+
* @category failure
|
|
176
|
+
*/
|
|
177
|
+
export interface Expected<E> extends Proto<"Expected", E> {
|
|
178
|
+
readonly error: E
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @since 3.4.0
|
|
183
|
+
* @experimental
|
|
184
|
+
* @category failure
|
|
185
|
+
*/
|
|
186
|
+
export interface Aborted extends Proto<"Aborted", never> {}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const failureVariance = {
|
|
190
|
+
_E: identity
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
abstract class FailureImpl<Tag extends string, E> extends globalThis.Error implements Failure.Proto<Tag, E> {
|
|
194
|
+
readonly [FailureTypeId]: {
|
|
195
|
+
_E: Covariant<E>
|
|
196
|
+
}
|
|
197
|
+
constructor(
|
|
198
|
+
readonly _tag: Tag,
|
|
199
|
+
originalError: unknown,
|
|
200
|
+
readonly traces: ReadonlyArray<string>
|
|
201
|
+
) {
|
|
202
|
+
const failureName = `Failure${_tag}`
|
|
203
|
+
let name: string
|
|
204
|
+
let message: string
|
|
205
|
+
let stack: string
|
|
206
|
+
if (originalError instanceof globalThis.Error) {
|
|
207
|
+
name = `(${failureName}) ${originalError.name}`
|
|
208
|
+
message = originalError.message as string
|
|
209
|
+
const messageLines = message.split("\n").length
|
|
210
|
+
stack = originalError.stack
|
|
211
|
+
? `(${failureName}) ${originalError.stack.split("\n").slice(0, messageLines + 3).join("\n")}`
|
|
212
|
+
: `${name}: ${message}`
|
|
213
|
+
} else {
|
|
214
|
+
name = failureName
|
|
215
|
+
message = toStringUnknown(originalError, 0)
|
|
216
|
+
stack = `${name}: ${message}`
|
|
217
|
+
}
|
|
218
|
+
if (traces.length > 0) {
|
|
219
|
+
stack += `\n ${traces.join("\n ")}`
|
|
220
|
+
}
|
|
221
|
+
super(message)
|
|
222
|
+
this[FailureTypeId] = failureVariance
|
|
223
|
+
this.name = name
|
|
224
|
+
this.stack = stack
|
|
225
|
+
}
|
|
226
|
+
pipe() {
|
|
227
|
+
return pipeArguments(this, arguments)
|
|
228
|
+
}
|
|
229
|
+
toString() {
|
|
230
|
+
return this.stack
|
|
231
|
+
}
|
|
232
|
+
[NodeInspectSymbol]() {
|
|
233
|
+
return this.stack
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
class FailureExpectedImpl<E> extends FailureImpl<"Expected", E> implements Failure.Expected<E> {
|
|
238
|
+
constructor(readonly error: E, traces: ReadonlyArray<string> = []) {
|
|
239
|
+
super("Expected", error, traces)
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* @since 3.4.0
|
|
245
|
+
* @experimental
|
|
246
|
+
* @category failure
|
|
247
|
+
*/
|
|
248
|
+
export const FailureExpected = <E>(error: E, traces: ReadonlyArray<string> = []): Failure<E> =>
|
|
249
|
+
new FailureExpectedImpl(error, traces)
|
|
250
|
+
|
|
251
|
+
class FailureUnexpectedImpl extends FailureImpl<"Unexpected", never> implements Failure.Unexpected {
|
|
252
|
+
constructor(readonly defect: unknown, traces: ReadonlyArray<string> = []) {
|
|
253
|
+
super("Unexpected", defect, traces)
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* @since 3.4.0
|
|
259
|
+
* @experimental
|
|
260
|
+
* @category failure
|
|
261
|
+
*/
|
|
262
|
+
export const FailureUnexpected = (defect: unknown, traces: ReadonlyArray<string> = []): Failure<never> =>
|
|
263
|
+
new FailureUnexpectedImpl(defect, traces)
|
|
264
|
+
|
|
265
|
+
class FailureAbortedImpl extends FailureImpl<"Aborted", never> implements Failure.Aborted {
|
|
266
|
+
constructor(traces: ReadonlyArray<string> = []) {
|
|
267
|
+
super("Aborted", "aborted", traces)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* @since 3.4.0
|
|
273
|
+
* @experimental
|
|
274
|
+
* @category failure
|
|
275
|
+
*/
|
|
276
|
+
export const FailureAborted = (traces: ReadonlyArray<string> = []): Failure<never> => new FailureAbortedImpl(traces)
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* @since 3.4.0
|
|
280
|
+
* @experimental
|
|
281
|
+
* @category failure
|
|
282
|
+
*/
|
|
283
|
+
export const failureIsExpected = <E>(self: Failure<E>): self is Failure.Expected<E> => self._tag === "Expected"
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @since 3.4.0
|
|
287
|
+
* @experimental
|
|
288
|
+
* @category failure
|
|
289
|
+
*/
|
|
290
|
+
export const failureIsUnexpected = <E>(self: Failure<E>): self is Failure.Unexpected => self._tag === "Unexpected"
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @since 3.4.0
|
|
294
|
+
* @experimental
|
|
295
|
+
* @category failure
|
|
296
|
+
*/
|
|
297
|
+
export const failureIsAborted = <E>(self: Failure<E>): self is Failure.Aborted => self._tag === "Aborted"
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* @since 3.4.0
|
|
301
|
+
* @experimental
|
|
302
|
+
* @category failure
|
|
303
|
+
*/
|
|
304
|
+
export const failureSquash = <E>(self: Failure<E>): unknown =>
|
|
305
|
+
self._tag === "Expected" ? self.error : self._tag === "Unexpected" ? self.defect : self
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* @since 3.4.0
|
|
309
|
+
* @experimental
|
|
310
|
+
* @category failure
|
|
311
|
+
*/
|
|
312
|
+
export const failureWithTrace: {
|
|
313
|
+
(trace: string): <E>(self: Failure<E>) => Failure<E>
|
|
314
|
+
<E>(self: Failure<E>, trace: string): Failure<E>
|
|
315
|
+
} = dual(2, <E>(self: Failure<E>, trace: string): Failure<E> => {
|
|
316
|
+
if (self._tag === "Expected") {
|
|
317
|
+
return FailureExpected(self.error, [...self.traces, trace])
|
|
318
|
+
} else if (self._tag === "Unexpected") {
|
|
319
|
+
return FailureUnexpected(self.defect, [...self.traces, trace])
|
|
320
|
+
}
|
|
321
|
+
return FailureAborted([...self.traces, trace])
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
// ----------------------------------------------------------------------------
|
|
325
|
+
// Result
|
|
326
|
+
// ----------------------------------------------------------------------------
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* The Micro Result type is a data type that represents the result of a Micro
|
|
330
|
+
* computation.
|
|
331
|
+
*
|
|
332
|
+
* It uses the `Either` data type to represent the success and failure cases.
|
|
333
|
+
*
|
|
334
|
+
* @since 3.4.0
|
|
335
|
+
* @experimental
|
|
336
|
+
* @category result
|
|
337
|
+
*/
|
|
338
|
+
export type Result<A, E = never> = Either.Either<A, Failure<E>>
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* @since 3.4.0
|
|
342
|
+
* @experimental
|
|
343
|
+
* @category result
|
|
344
|
+
*/
|
|
345
|
+
export const ResultAborted: Result<never> = Either.left(FailureAborted())
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* @since 3.4.0
|
|
349
|
+
* @experimental
|
|
350
|
+
* @category result
|
|
351
|
+
*/
|
|
352
|
+
export const ResultSuccess: <A>(a: A) => Result<A, never> = Either.right
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* @since 3.4.0
|
|
356
|
+
* @experimental
|
|
357
|
+
* @category result
|
|
358
|
+
*/
|
|
359
|
+
export const ResultFail = <E>(e: E): Result<never, E> => Either.left(FailureExpected(e))
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* @since 3.4.0
|
|
363
|
+
* @experimental
|
|
364
|
+
* @category result
|
|
365
|
+
*/
|
|
366
|
+
export const ResultFailUnexpected = (defect: unknown): Result<never> => Either.left(FailureUnexpected(defect))
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* @since 3.4.0
|
|
370
|
+
* @experimental
|
|
371
|
+
* @category result
|
|
372
|
+
*/
|
|
373
|
+
export const ResultFailWith: <E>(failure: Failure<E>) => Result<never, E> = Either.left
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* @since 3.4.0
|
|
377
|
+
* @experimental
|
|
378
|
+
* @category result
|
|
379
|
+
*/
|
|
380
|
+
export const resultIsSuccess: <A, E>(self: Result<A, E>) => self is Either.Right<Failure<E>, A> = Either.isRight
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* @since 3.4.0
|
|
384
|
+
* @experimental
|
|
385
|
+
* @category result
|
|
386
|
+
*/
|
|
387
|
+
export const resultIsFailure: <A, E>(self: Result<A, E>) => self is Either.Left<Failure<E>, A> = Either.isLeft
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* @since 3.4.0
|
|
391
|
+
* @experimental
|
|
392
|
+
* @category result
|
|
393
|
+
*/
|
|
394
|
+
export const resultIsAborted = <A, E>(self: Result<A, E>): self is Either.Left<Failure.Aborted, A> =>
|
|
395
|
+
resultIsFailure(self) && self.left._tag === "Aborted"
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* @since 3.4.0
|
|
399
|
+
* @experimental
|
|
400
|
+
* @category result
|
|
401
|
+
*/
|
|
402
|
+
export const resultIsFailureExpected = <A, E>(self: Result<A, E>): self is Either.Left<Failure.Expected<E>, A> =>
|
|
403
|
+
resultIsFailure(self) && self.left._tag === "Expected"
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* @since 3.4.0
|
|
407
|
+
* @experimental
|
|
408
|
+
* @category result
|
|
409
|
+
*/
|
|
410
|
+
export const resultIsFailureUnexpected = <A, E>(self: Result<A, E>): self is Either.Left<Failure.Unexpected, A> =>
|
|
411
|
+
resultIsFailure(self) && self.left._tag === "Unexpected"
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* @since 3.4.0
|
|
415
|
+
* @experimental
|
|
416
|
+
* @category result
|
|
417
|
+
*/
|
|
418
|
+
export const resultVoid: Result<void> = ResultSuccess(void 0)
|
|
419
|
+
|
|
420
|
+
// ----------------------------------------------------------------------------
|
|
421
|
+
// env
|
|
422
|
+
// ----------------------------------------------------------------------------
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* @since 3.4.0
|
|
426
|
+
* @experimental
|
|
427
|
+
* @category environment
|
|
428
|
+
*/
|
|
429
|
+
export const EnvTypeId = Symbol.for("effect/Micro/Env")
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* @since 3.4.0
|
|
433
|
+
* @experimental
|
|
434
|
+
* @category environment
|
|
435
|
+
*/
|
|
436
|
+
export type EnvTypeId = typeof EnvTypeId
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* @since 3.4.0
|
|
440
|
+
* @experimental
|
|
441
|
+
* @category environment
|
|
442
|
+
*/
|
|
443
|
+
export interface Env<R> extends Pipeable {
|
|
444
|
+
readonly [EnvTypeId]: {
|
|
445
|
+
_R: Covariant<R>
|
|
446
|
+
}
|
|
447
|
+
readonly refs: ReadonlyRecord<string, unknown>
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* @since 3.4.0
|
|
452
|
+
* @experimental
|
|
453
|
+
* @category environment
|
|
454
|
+
*/
|
|
455
|
+
export const EnvRefTypeId: unique symbol = Symbol.for("effect/Micro/EnvRef")
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* @since 3.4.0
|
|
459
|
+
* @experimental
|
|
460
|
+
* @category environment
|
|
461
|
+
*/
|
|
462
|
+
export type EnvRefTypeId = typeof EnvRefTypeId
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* @since 3.4.0
|
|
466
|
+
* @experimental
|
|
467
|
+
* @category environment
|
|
468
|
+
*/
|
|
469
|
+
export interface EnvRef<A> {
|
|
470
|
+
readonly [EnvRefTypeId]: EnvRefTypeId
|
|
471
|
+
readonly key: string
|
|
472
|
+
readonly initial: A
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const EnvProto = {
|
|
476
|
+
[EnvTypeId]: {
|
|
477
|
+
_R: identity
|
|
478
|
+
},
|
|
479
|
+
pipe() {
|
|
480
|
+
return pipeArguments(this, arguments)
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* @since 3.4.0
|
|
486
|
+
* @experimental
|
|
487
|
+
* @category environment
|
|
488
|
+
*/
|
|
489
|
+
export const envMake = <R = never>(
|
|
490
|
+
refs: Record<string, unknown>
|
|
491
|
+
): Env<R> => {
|
|
492
|
+
const self = Object.create(EnvProto)
|
|
493
|
+
self.refs = refs
|
|
494
|
+
return self
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* @since 3.4.0
|
|
499
|
+
* @experimental
|
|
500
|
+
* @category environment
|
|
501
|
+
*/
|
|
502
|
+
export const envUnsafeMakeEmpty = (): Env<never> => {
|
|
503
|
+
const controller = new AbortController()
|
|
504
|
+
const refs = Object.create(null)
|
|
505
|
+
refs[currentAbortController.key] = controller
|
|
506
|
+
refs[currentAbortSignal.key] = controller.signal
|
|
507
|
+
return envMake(refs)
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* @since 3.4.0
|
|
512
|
+
* @experimental
|
|
513
|
+
* @category environment
|
|
514
|
+
*/
|
|
515
|
+
export const envGet: {
|
|
516
|
+
<A>(ref: EnvRef<A>): <R>(self: Env<R>) => A
|
|
517
|
+
<A, R>(self: Env<R>, ref: EnvRef<A>): A
|
|
518
|
+
} = dual(2, <R, A>(self: Env<R>, ref: EnvRef<A>): A => ref.key in self.refs ? (self.refs[ref.key] as A) : ref.initial)
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* @since 3.4.0
|
|
522
|
+
* @experimental
|
|
523
|
+
* @category environment
|
|
524
|
+
*/
|
|
525
|
+
export const envSet: {
|
|
526
|
+
<A>(ref: EnvRef<A>, value: A): <R>(self: Env<R>) => Env<R>
|
|
527
|
+
<A, R>(self: Env<R>, ref: EnvRef<A>, value: A): Env<R>
|
|
528
|
+
} = dual(3, <R, A>(self: Env<R>, ref: EnvRef<A>, value: A): Env<R> => {
|
|
529
|
+
const refs = Object.assign(Object.create(null), self.refs)
|
|
530
|
+
refs[ref.key] = value
|
|
531
|
+
return envMake(refs)
|
|
532
|
+
})
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* @since 3.4.0
|
|
536
|
+
* @experimental
|
|
537
|
+
* @category environment
|
|
538
|
+
*/
|
|
539
|
+
export const envMutate: {
|
|
540
|
+
(f: (map: Record<string, unknown>) => void): <R>(self: Env<R>) => Env<R>
|
|
541
|
+
<R>(self: Env<R>, f: (map: Record<string, unknown>) => void): Env<R>
|
|
542
|
+
} = dual(
|
|
543
|
+
2,
|
|
544
|
+
<R>(self: Env<R>, f: (map: Record<string, unknown>) => ReadonlyRecord<string, unknown>): Env<R> =>
|
|
545
|
+
envMake(f(Object.assign(Object.create(null), self.refs)))
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Access the given `Context.Tag` from the environment.
|
|
550
|
+
*
|
|
551
|
+
* @since 3.4.0
|
|
552
|
+
* @experimental
|
|
553
|
+
* @category environment
|
|
554
|
+
*/
|
|
555
|
+
export const service = <I, S>(tag: Context.Tag<I, S>): Micro<S, never, I> =>
|
|
556
|
+
make(function(env, onResult) {
|
|
557
|
+
onResult(ResultSuccess(Context.get(envGet(env, currentContext) as Context.Context<I>, tag as any) as S))
|
|
558
|
+
})
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Access the given `Context.Tag` from the environment, without tracking the
|
|
562
|
+
* dependency at the type level.
|
|
563
|
+
*
|
|
564
|
+
* It will return an `Option` of the service, depending on whether it is
|
|
565
|
+
* available in the environment or not.
|
|
566
|
+
*
|
|
567
|
+
* @since 3.4.0
|
|
568
|
+
* @experimental
|
|
569
|
+
* @category environment
|
|
570
|
+
*/
|
|
571
|
+
export const serviceOption = <I, S>(tag: Context.Tag<I, S>): Micro<Option.Option<S>> =>
|
|
572
|
+
make(function(env, onResult) {
|
|
573
|
+
onResult(ResultSuccess(Context.getOption(envGet(env, currentContext) as Context.Context<I>, tag)))
|
|
574
|
+
})
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Retrieve the current value of the given `EnvRef`.
|
|
578
|
+
*
|
|
579
|
+
* @since 3.4.0
|
|
580
|
+
* @experimental
|
|
581
|
+
* @category environment
|
|
582
|
+
*/
|
|
583
|
+
export const getEnvRef = <A>(envRef: EnvRef<A>): Micro<A> =>
|
|
584
|
+
make((env, onResult) => onResult(Either.right(envGet(env, envRef))))
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Set the value of the given `EnvRef` for the duration of the effect.
|
|
588
|
+
*
|
|
589
|
+
* @since 3.4.0
|
|
590
|
+
* @experimental
|
|
591
|
+
* @category environment
|
|
592
|
+
*/
|
|
593
|
+
export const locally: {
|
|
594
|
+
<A>(fiberRef: EnvRef<A>, value: A): <XA, E, R>(self: Micro<XA, E, R>) => Micro<XA, E, R>
|
|
595
|
+
<XA, E, R, A>(self: Micro<XA, E, R>, fiberRef: EnvRef<A>, value: A): Micro<XA, E, R>
|
|
596
|
+
} = dual(
|
|
597
|
+
3,
|
|
598
|
+
<XA, E, R, A>(self: Micro<XA, E, R>, fiberRef: EnvRef<A>, value: A): Micro<XA, E, R> =>
|
|
599
|
+
make((env, onResult) => self[runSymbol](envSet(env, fiberRef, value), onResult))
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Access the current `Context` from the environment.
|
|
604
|
+
*
|
|
605
|
+
* @since 3.4.0
|
|
606
|
+
* @experimental
|
|
607
|
+
* @category environment
|
|
608
|
+
*/
|
|
609
|
+
export const context = <R>(): Micro<Context.Context<R>> => getEnvRef(currentContext) as any
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Merge the given `Context` with the current context.
|
|
613
|
+
*
|
|
614
|
+
* @since 3.4.0
|
|
615
|
+
* @experimental
|
|
616
|
+
* @category environment
|
|
617
|
+
*/
|
|
618
|
+
export const provideContext: {
|
|
619
|
+
<XR>(context: Context.Context<XR>): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, Exclude<R, XR>>
|
|
620
|
+
<A, E, R, XR>(self: Micro<A, E, R>, context: Context.Context<XR>): Micro<A, E, Exclude<R, XR>>
|
|
621
|
+
} = dual(
|
|
622
|
+
2,
|
|
623
|
+
<A, E, R, XR>(self: Micro<A, E, R>, provided: Context.Context<XR>): Micro<A, E, Exclude<R, XR>> =>
|
|
624
|
+
make(function(env, onResult) {
|
|
625
|
+
const context = envGet(env, currentContext)
|
|
626
|
+
const nextEnv = envSet(env, currentContext, Context.merge(context, provided))
|
|
627
|
+
self[runSymbol](nextEnv, onResult)
|
|
628
|
+
})
|
|
629
|
+
)
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Add the provided service to the current context.
|
|
633
|
+
*
|
|
634
|
+
* @since 3.4.0
|
|
635
|
+
* @experimental
|
|
636
|
+
* @category environment
|
|
637
|
+
*/
|
|
638
|
+
export const provideService: {
|
|
639
|
+
<I, S>(tag: Context.Tag<I, S>, service: S): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, Exclude<R, I>>
|
|
640
|
+
<A, E, R, I, S>(self: Micro<A, E, R>, tag: Context.Tag<I, S>, service: S): Micro<A, E, Exclude<R, I>>
|
|
641
|
+
} = dual(
|
|
642
|
+
3,
|
|
643
|
+
<A, E, R, I, S>(self: Micro<A, E, R>, tag: Context.Tag<I, S>, service: S): Micro<A, E, Exclude<R, I>> =>
|
|
644
|
+
make(function(env, onResult) {
|
|
645
|
+
const context = envGet(env, currentContext)
|
|
646
|
+
const nextEnv = envSet(env, currentContext, Context.add(context, tag, service))
|
|
647
|
+
self[runSymbol](nextEnv, onResult)
|
|
648
|
+
})
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Create a service using the provided `Micro` effect, and add it to the
|
|
653
|
+
* current context.
|
|
654
|
+
*
|
|
655
|
+
* @since 3.4.0
|
|
656
|
+
* @experimental
|
|
657
|
+
* @category environment
|
|
658
|
+
*/
|
|
659
|
+
export const provideServiceMicro: {
|
|
660
|
+
<I, S, E2, R2>(
|
|
661
|
+
tag: Context.Tag<I, S>,
|
|
662
|
+
acquire: Micro<S, E2, R2>
|
|
663
|
+
): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E | E2, Exclude<R, I> | R2>
|
|
664
|
+
<A, E, R, I, S, E2, R2>(
|
|
665
|
+
self: Micro<A, E, R>,
|
|
666
|
+
tag: Context.Tag<I, S>,
|
|
667
|
+
acquire: Micro<S, E2, R2>
|
|
668
|
+
): Micro<A, E | E2, Exclude<R, I> | R2>
|
|
669
|
+
} = dual(
|
|
670
|
+
3,
|
|
671
|
+
<A, E, R, I, S, E2, R2>(
|
|
672
|
+
self: Micro<A, E, R>,
|
|
673
|
+
tag: Context.Tag<I, S>,
|
|
674
|
+
acquire: Micro<S, E2, R2>
|
|
675
|
+
): Micro<A, E | E2, Exclude<R, I> | R2> => flatMap(acquire, (service) => provideService(self, tag, service))
|
|
676
|
+
)
|
|
677
|
+
|
|
678
|
+
// ========================================================================
|
|
679
|
+
// Env refs
|
|
680
|
+
// ========================================================================
|
|
681
|
+
|
|
682
|
+
const EnvRefProto = {
|
|
683
|
+
[EnvRefTypeId]: EnvRefTypeId
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* @since 3.4.0
|
|
688
|
+
* @experimental
|
|
689
|
+
* @category environment refs
|
|
690
|
+
*/
|
|
691
|
+
export const envRefMake = <A>(key: string, initial: LazyArg<A>): EnvRef<A> =>
|
|
692
|
+
globalValue(key, () => {
|
|
693
|
+
const self = Object.create(EnvRefProto)
|
|
694
|
+
self.key = key
|
|
695
|
+
self.initial = initial()
|
|
696
|
+
return self
|
|
697
|
+
})
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* @since 3.4.0
|
|
701
|
+
* @experimental
|
|
702
|
+
* @category environment refs
|
|
703
|
+
*/
|
|
704
|
+
export const currentAbortController: EnvRef<AbortController> = envRefMake(
|
|
705
|
+
"effect/Micro/currentAbortController",
|
|
706
|
+
() => new AbortController()
|
|
707
|
+
)
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* @since 3.4.0
|
|
711
|
+
* @experimental
|
|
712
|
+
* @category environment refs
|
|
713
|
+
*/
|
|
714
|
+
export const currentAbortSignal: EnvRef<AbortSignal> = envRefMake(
|
|
715
|
+
"effect/Micro/currentAbortSignal",
|
|
716
|
+
() => currentAbortController.initial.signal
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* @since 3.4.0
|
|
721
|
+
* @experimental
|
|
722
|
+
* @category environment refs
|
|
723
|
+
*/
|
|
724
|
+
export const currentContext: EnvRef<Context.Context<never>> = envRefMake(
|
|
725
|
+
"effect/Micro/currentContext",
|
|
726
|
+
() => Context.empty()
|
|
727
|
+
)
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* @since 3.4.0
|
|
731
|
+
* @experimental
|
|
732
|
+
* @category environment refs
|
|
733
|
+
*/
|
|
734
|
+
export const currentConcurrency: EnvRef<"unbounded" | number> = envRefMake(
|
|
735
|
+
"effect/Micro/currentConcurrency",
|
|
736
|
+
() => "unbounded"
|
|
737
|
+
)
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* @since 3.4.0
|
|
741
|
+
* @experimental
|
|
742
|
+
* @category environment refs
|
|
743
|
+
*/
|
|
744
|
+
export const currentMaxDepthBeforeYield: EnvRef<number> = envRefMake(
|
|
745
|
+
"effect/Micro/currentMaxDepthBeforeYield",
|
|
746
|
+
() => 2048
|
|
747
|
+
)
|
|
748
|
+
|
|
749
|
+
const currentInterruptible: EnvRef<boolean> = envRefMake(
|
|
750
|
+
"effect/Micro/currentInterruptible",
|
|
751
|
+
() => true
|
|
752
|
+
)
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* If you have a `Micro` that uses `concurrency: "inherit"`, you can use this
|
|
756
|
+
* api to control the concurrency of that `Micro` when it is run.
|
|
757
|
+
*
|
|
758
|
+
* @since 3.4.0
|
|
759
|
+
* @experimental
|
|
760
|
+
* @category environment refs
|
|
761
|
+
* @example
|
|
762
|
+
* import * as Micro from "effect/Micro"
|
|
763
|
+
*
|
|
764
|
+
* Micro.forEach([1, 2, 3], (n) => Micro.succeed(n), {
|
|
765
|
+
* concurrency: "inherit"
|
|
766
|
+
* }).pipe(
|
|
767
|
+
* Micro.withConcurrency(2) // use a concurrency of 2
|
|
768
|
+
* )
|
|
769
|
+
*/
|
|
770
|
+
export const withConcurrency: {
|
|
771
|
+
(concurrency: "unbounded" | number): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, R>
|
|
772
|
+
<A, E, R>(self: Micro<A, E, R>, concurrency: "unbounded" | number): Micro<A, E, R>
|
|
773
|
+
} = dual(
|
|
774
|
+
2,
|
|
775
|
+
<A, E, R>(self: Micro<A, E, R>, concurrency: "unbounded" | number): Micro<A, E, R> =>
|
|
776
|
+
locally(self, currentConcurrency, concurrency)
|
|
777
|
+
)
|
|
778
|
+
|
|
779
|
+
// ----------------------------------------------------------------------------
|
|
780
|
+
// constructors
|
|
781
|
+
// ----------------------------------------------------------------------------
|
|
782
|
+
|
|
783
|
+
const MicroProto = {
|
|
784
|
+
...Effectable.EffectPrototype,
|
|
785
|
+
_op: "Micro",
|
|
786
|
+
[TypeId]: {
|
|
787
|
+
_A: identity,
|
|
788
|
+
_E: identity,
|
|
789
|
+
_R: identity
|
|
790
|
+
},
|
|
791
|
+
[Symbol.iterator]() {
|
|
792
|
+
return new SingleShotGen(new YieldWrap(this)) as any
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
const microDepthState = globalValue("effect/Micro/microDepthState", () => ({
|
|
797
|
+
depth: 0,
|
|
798
|
+
maxDepthBeforeYield: currentMaxDepthBeforeYield.initial
|
|
799
|
+
}))
|
|
800
|
+
|
|
801
|
+
const unsafeMake = <A, E, R>(
|
|
802
|
+
run: (env: Env<R>, onResult: (result: Result<A, E>) => void) => void
|
|
803
|
+
): Micro<A, E, R> => {
|
|
804
|
+
const self = Object.create(MicroProto)
|
|
805
|
+
self[runSymbol] = run
|
|
806
|
+
return self
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
const unsafeMakeOptions = <A, E, R>(
|
|
810
|
+
run: (env: Env<R>, onResult: (result: Result<A, E>) => void) => void,
|
|
811
|
+
checkAbort: boolean
|
|
812
|
+
): Micro<A, E, R> =>
|
|
813
|
+
unsafeMake(function execute(env, onResult) {
|
|
814
|
+
if (
|
|
815
|
+
checkAbort && env.refs[currentInterruptible.key] !== false &&
|
|
816
|
+
(env.refs[currentAbortSignal.key] as AbortSignal).aborted
|
|
817
|
+
) {
|
|
818
|
+
return onResult(ResultAborted)
|
|
819
|
+
}
|
|
820
|
+
microDepthState.depth++
|
|
821
|
+
if (microDepthState.depth === 1) {
|
|
822
|
+
microDepthState.maxDepthBeforeYield = envGet(env, currentMaxDepthBeforeYield)
|
|
823
|
+
}
|
|
824
|
+
if (microDepthState.depth >= microDepthState.maxDepthBeforeYield) {
|
|
825
|
+
yieldAdd(() => execute(env, onResult))
|
|
826
|
+
} else {
|
|
827
|
+
try {
|
|
828
|
+
run(env, onResult)
|
|
829
|
+
} catch (err) {
|
|
830
|
+
onResult(ResultFailUnexpected(err))
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
microDepthState.depth--
|
|
834
|
+
})
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* A low-level constructor for creating a `Micro` effect. It takes a function
|
|
838
|
+
* that receives an environment and a callback which should be called with the
|
|
839
|
+
* result of the effect.
|
|
840
|
+
*
|
|
841
|
+
* @since 3.4.0
|
|
842
|
+
* @experimental
|
|
843
|
+
* @category constructors
|
|
844
|
+
*/
|
|
845
|
+
export const make = <A, E, R>(
|
|
846
|
+
run: (env: Env<R>, onResult: (result: Result<A, E>) => void) => void
|
|
847
|
+
): Micro<A, E, R> => unsafeMakeOptions(run, true)
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Converts a `Result` into a `Micro` effect.
|
|
851
|
+
*
|
|
852
|
+
* @since 3.4.0
|
|
853
|
+
* @experimental
|
|
854
|
+
* @category constructors
|
|
855
|
+
*/
|
|
856
|
+
export const fromResult = <A, E>(self: Result<A, E>): Micro<A, E> =>
|
|
857
|
+
make(function(_env, onResult) {
|
|
858
|
+
onResult(self)
|
|
859
|
+
})
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* Converts a lazy `Result` into a `Micro` effect.
|
|
863
|
+
*
|
|
864
|
+
* @since 3.4.0
|
|
865
|
+
* @experimental
|
|
866
|
+
* @category constructors
|
|
867
|
+
*/
|
|
868
|
+
export const fromResultSync = <A, E>(self: LazyArg<Result<A, E>>): Micro<A, E> =>
|
|
869
|
+
make(function(_env, onResult) {
|
|
870
|
+
onResult(self())
|
|
871
|
+
})
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* Creates a `Micro` effect that will succeed with the specified constant value.
|
|
875
|
+
*
|
|
876
|
+
* @since 3.4.0
|
|
877
|
+
* @experimental
|
|
878
|
+
* @category constructors
|
|
879
|
+
*/
|
|
880
|
+
export const succeed = <A>(a: A): Micro<A> => fromResult(ResultSuccess(a))
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* Creates a `Micro` effect that will succeed with `Option.Some` of the value.
|
|
884
|
+
*
|
|
885
|
+
* @since 3.4.0
|
|
886
|
+
* @experimental
|
|
887
|
+
* @category constructors
|
|
888
|
+
*/
|
|
889
|
+
export const succeedSome = <A>(a: A): Micro<Option.Option<A>> => succeed(Option.some(a))
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* Creates a `Micro` effect that will succeed with `Option.None`.
|
|
893
|
+
*
|
|
894
|
+
* @since 3.4.0
|
|
895
|
+
* @experimental
|
|
896
|
+
* @category constructors
|
|
897
|
+
*/
|
|
898
|
+
export const succeedNone: Micro<Option.Option<never>> = succeed(Option.none())
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* Creates a `Micro` effect that will fail with the specified error.
|
|
902
|
+
*
|
|
903
|
+
* This will result in a `FailureExpected`, where the error is tracked at the
|
|
904
|
+
* type level.
|
|
905
|
+
*
|
|
906
|
+
* @since 3.4.0
|
|
907
|
+
* @experimental
|
|
908
|
+
* @category constructors
|
|
909
|
+
*/
|
|
910
|
+
export const fail = <E>(e: E): Micro<never, E> => fromResult(ResultFail(e))
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* Creates a `Micro` effect that will fail with the lazily evaluated error.
|
|
914
|
+
*
|
|
915
|
+
* This will result in a `FailureExpected`, where the error is tracked at the
|
|
916
|
+
* type level.
|
|
917
|
+
*
|
|
918
|
+
* @since 3.4.0
|
|
919
|
+
* @experimental
|
|
920
|
+
* @category constructors
|
|
921
|
+
*/
|
|
922
|
+
export const failSync = <E>(e: LazyArg<E>): Micro<never, E> =>
|
|
923
|
+
make(function(_env, onResult) {
|
|
924
|
+
onResult(ResultFail(e()))
|
|
925
|
+
})
|
|
926
|
+
|
|
927
|
+
/**
|
|
928
|
+
* Creates a `Micro` effect that will die with the specified error.
|
|
929
|
+
*
|
|
930
|
+
* This will result in a `FailureUnexpected`, where the error is not tracked at
|
|
931
|
+
* the type level.
|
|
932
|
+
*
|
|
933
|
+
* @since 3.4.0
|
|
934
|
+
* @experimental
|
|
935
|
+
* @category constructors
|
|
936
|
+
*/
|
|
937
|
+
export const die = (defect: unknown): Micro<never> => fromResult(ResultFailUnexpected(defect))
|
|
938
|
+
|
|
939
|
+
/**
|
|
940
|
+
* Creates a `Micro` effect that will fail with the specified `Failure`.
|
|
941
|
+
*
|
|
942
|
+
* @since 3.4.0
|
|
943
|
+
* @experimental
|
|
944
|
+
* @category constructors
|
|
945
|
+
*/
|
|
946
|
+
export const failWith = <E>(failure: Failure<E>): Micro<never, E> => fromResult(ResultFailWith(failure))
|
|
947
|
+
|
|
948
|
+
/**
|
|
949
|
+
* Creates a `Micro` effect that will fail with the lazily evaluated `Failure`.
|
|
950
|
+
*
|
|
951
|
+
* @since 3.4.0
|
|
952
|
+
* @experimental
|
|
953
|
+
* @category constructors
|
|
954
|
+
*/
|
|
955
|
+
export const failWithSync = <E>(failure: LazyArg<Failure<E>>): Micro<never, E> =>
|
|
956
|
+
fromResultSync(() => ResultFailWith(failure()))
|
|
957
|
+
|
|
958
|
+
/**
|
|
959
|
+
* Creates a `Micro` effect that will succeed with the lazily evaluated value.
|
|
960
|
+
*
|
|
961
|
+
* If the evaluation of the value throws an error, the effect will fail with
|
|
962
|
+
* `FailureUnexpected`.
|
|
963
|
+
*
|
|
964
|
+
* @since 3.4.0
|
|
965
|
+
* @experimental
|
|
966
|
+
* @category constructors
|
|
967
|
+
*/
|
|
968
|
+
export const sync = <A>(evaluate: LazyArg<A>): Micro<A> =>
|
|
969
|
+
make(function(_env, onResult) {
|
|
970
|
+
onResult(ResultSuccess(evaluate()))
|
|
971
|
+
})
|
|
972
|
+
|
|
973
|
+
/**
|
|
974
|
+
* Converts an `Option` into a `Micro` effect, that will fail with a
|
|
975
|
+
* `Option.None` if the option is `None`. Otherwise, it will succeed with the
|
|
976
|
+
* value of the option.
|
|
977
|
+
*
|
|
978
|
+
* @since 3.4.0
|
|
979
|
+
* @experimental
|
|
980
|
+
* @category constructors
|
|
981
|
+
*/
|
|
982
|
+
export const fromOption = <A>(option: Option.Option<A>): Micro<A, Option.None<never>> =>
|
|
983
|
+
make(function(_env, onResult) {
|
|
984
|
+
onResult(option._tag === "Some" ? ResultSuccess(option.value) : ResultFail(Option.none()) as any)
|
|
985
|
+
})
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* Converts an `Either` into a `Micro` effect, that will fail with the left side
|
|
989
|
+
* of the either if it is a `Left`. Otherwise, it will succeed with the right
|
|
990
|
+
* side of the either.
|
|
991
|
+
*
|
|
992
|
+
* @since 3.4.0
|
|
993
|
+
* @experimental
|
|
994
|
+
* @category constructors
|
|
995
|
+
*/
|
|
996
|
+
export const fromEither = <R, L>(either: Either.Either<R, L>): Micro<R, L> =>
|
|
997
|
+
make(function(_env, onResult) {
|
|
998
|
+
onResult(either._tag === "Right" ? either : ResultFail(either.left) as any)
|
|
999
|
+
})
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Lazily creates a `Micro` effect from the given side-effect.
|
|
1003
|
+
*
|
|
1004
|
+
* @since 3.4.0
|
|
1005
|
+
* @experimental
|
|
1006
|
+
* @category constructors
|
|
1007
|
+
*/
|
|
1008
|
+
export const suspend = <A, E, R>(evaluate: LazyArg<Micro<A, E, R>>): Micro<A, E, R> =>
|
|
1009
|
+
make(function(env, onResult) {
|
|
1010
|
+
evaluate()[runSymbol](env, onResult)
|
|
1011
|
+
})
|
|
1012
|
+
|
|
1013
|
+
const void_: Micro<void> = succeed(void 0)
|
|
1014
|
+
export {
|
|
1015
|
+
/**
|
|
1016
|
+
* A `Micro` effect that will succeed with `void` (`undefined`).
|
|
1017
|
+
*
|
|
1018
|
+
* @since 3.4.0
|
|
1019
|
+
* @experimental
|
|
1020
|
+
* @category constructors
|
|
1021
|
+
*/
|
|
1022
|
+
void_ as void
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Create a `Micro` effect from an asynchronous computation.
|
|
1027
|
+
*
|
|
1028
|
+
* You can return a cleanup effect that will be run when the effect is aborted.
|
|
1029
|
+
* It is also passed an `AbortSignal` that is triggered when the effect is
|
|
1030
|
+
* aborted.
|
|
1031
|
+
*
|
|
1032
|
+
* @since 3.4.0
|
|
1033
|
+
* @experimental
|
|
1034
|
+
* @category constructors
|
|
1035
|
+
*/
|
|
1036
|
+
export const async = <A, E = never, R = never>(
|
|
1037
|
+
register: (resume: (effect: Micro<A, E, R>) => void, signal: AbortSignal) => void | Micro<void, never, R>
|
|
1038
|
+
): Micro<A, E, R> =>
|
|
1039
|
+
make(function(env, onResult) {
|
|
1040
|
+
let resumed = false
|
|
1041
|
+
const controller = register.length > 1 ? new AbortController() : undefined
|
|
1042
|
+
const signal = envGet(env, currentAbortSignal)
|
|
1043
|
+
let cleanup: Micro<void, never, R> | void = undefined
|
|
1044
|
+
function onAbort() {
|
|
1045
|
+
if (cleanup) {
|
|
1046
|
+
resume(uninterruptible(andThen(cleanup, fromResult(ResultAborted))))
|
|
1047
|
+
} else {
|
|
1048
|
+
resume(fromResult(ResultAborted))
|
|
1049
|
+
}
|
|
1050
|
+
if (controller !== undefined) {
|
|
1051
|
+
controller.abort()
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
function resume(effect: Micro<A, E, R>) {
|
|
1055
|
+
if (resumed) {
|
|
1056
|
+
return
|
|
1057
|
+
}
|
|
1058
|
+
resumed = true
|
|
1059
|
+
signal.removeEventListener("abort", onAbort)
|
|
1060
|
+
effect[runSymbol](env, onResult)
|
|
1061
|
+
}
|
|
1062
|
+
cleanup = controller === undefined
|
|
1063
|
+
? (register as any)(resume)
|
|
1064
|
+
: register(resume, controller.signal)
|
|
1065
|
+
if (resumed) return
|
|
1066
|
+
signal.addEventListener("abort", onAbort)
|
|
1067
|
+
})
|
|
1068
|
+
|
|
1069
|
+
const try_ = <A, E>(options: {
|
|
1070
|
+
try: LazyArg<A>
|
|
1071
|
+
catch: (error: unknown) => E
|
|
1072
|
+
}): Micro<A, E> =>
|
|
1073
|
+
make(function(_env, onResult) {
|
|
1074
|
+
try {
|
|
1075
|
+
onResult(ResultSuccess(options.try()))
|
|
1076
|
+
} catch (err) {
|
|
1077
|
+
onResult(ResultFail(options.catch(err)))
|
|
1078
|
+
}
|
|
1079
|
+
})
|
|
1080
|
+
export {
|
|
1081
|
+
/**
|
|
1082
|
+
* The `Micro` equivalent of a try / catch block, which allows you to map
|
|
1083
|
+
* thrown errors to a specific error type.
|
|
1084
|
+
*
|
|
1085
|
+
* @since 3.4.0
|
|
1086
|
+
* @experimental
|
|
1087
|
+
* @category constructors
|
|
1088
|
+
* @example
|
|
1089
|
+
* import { Micro } from "effect"
|
|
1090
|
+
*
|
|
1091
|
+
* Micro.try({
|
|
1092
|
+
* try: () => throw new Error("boom"),
|
|
1093
|
+
* catch: (cause) => new Error("caught", { cause })
|
|
1094
|
+
* })
|
|
1095
|
+
*/
|
|
1096
|
+
try_ as try
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/**
|
|
1100
|
+
* Wrap a `Promise` into a `Micro` effect. Any errors will result in a
|
|
1101
|
+
* `FailureUnexpected`.
|
|
1102
|
+
*
|
|
1103
|
+
* @since 3.4.0
|
|
1104
|
+
* @experimental
|
|
1105
|
+
* @category constructors
|
|
1106
|
+
*/
|
|
1107
|
+
export const promise = <A>(evaluate: (signal: AbortSignal) => PromiseLike<A>): Micro<A> =>
|
|
1108
|
+
async<A>(function(resume, signal) {
|
|
1109
|
+
evaluate(signal).then(
|
|
1110
|
+
(a) => resume(succeed(a)),
|
|
1111
|
+
(e) => resume(die(e))
|
|
1112
|
+
)
|
|
1113
|
+
})
|
|
1114
|
+
|
|
1115
|
+
/**
|
|
1116
|
+
* Wrap a `Promise` into a `Micro` effect. Any errors will be caught and
|
|
1117
|
+
* converted into a specific error type.
|
|
1118
|
+
*
|
|
1119
|
+
* @since 3.4.0
|
|
1120
|
+
* @experimental
|
|
1121
|
+
* @category constructors
|
|
1122
|
+
* @example
|
|
1123
|
+
* import { Micro } from "effect"
|
|
1124
|
+
*
|
|
1125
|
+
* Micro.tryPromise({
|
|
1126
|
+
* try: () => Promise.resolve("success"),
|
|
1127
|
+
* catch: (cause) => new Error("caught", { cause })
|
|
1128
|
+
* })
|
|
1129
|
+
*/
|
|
1130
|
+
export const tryPromise = <A, E>(options: {
|
|
1131
|
+
readonly try: (signal: AbortSignal) => PromiseLike<A>
|
|
1132
|
+
readonly catch: (error: unknown) => E
|
|
1133
|
+
}): Micro<A, E> =>
|
|
1134
|
+
async<A, E>(function(resume, signal) {
|
|
1135
|
+
try {
|
|
1136
|
+
options.try(signal).then(
|
|
1137
|
+
(a) => resume(succeed(a)),
|
|
1138
|
+
(e) => resume(fail(options.catch(e)))
|
|
1139
|
+
)
|
|
1140
|
+
} catch (err) {
|
|
1141
|
+
resume(fail(options.catch(err)))
|
|
1142
|
+
}
|
|
1143
|
+
})
|
|
1144
|
+
|
|
1145
|
+
const yieldState: {
|
|
1146
|
+
tasks: Array<() => void>
|
|
1147
|
+
working: boolean
|
|
1148
|
+
} = globalValue("effect/Micro/yieldState", () => ({
|
|
1149
|
+
tasks: [],
|
|
1150
|
+
working: false
|
|
1151
|
+
}))
|
|
1152
|
+
|
|
1153
|
+
const yieldRunTasks = () => {
|
|
1154
|
+
const tasks = yieldState.tasks
|
|
1155
|
+
yieldState.tasks = []
|
|
1156
|
+
for (let i = 0, len = tasks.length; i < len; i++) {
|
|
1157
|
+
tasks[i]()
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
const setImmediate = "setImmediate" in globalThis ? globalThis.setImmediate : (f: () => void) => setTimeout(f, 0)
|
|
1162
|
+
|
|
1163
|
+
const yieldAdd = (task: () => void) => {
|
|
1164
|
+
yieldState.tasks.push(task)
|
|
1165
|
+
if (!yieldState.working) {
|
|
1166
|
+
yieldState.working = true
|
|
1167
|
+
setImmediate(() => {
|
|
1168
|
+
yieldState.working = false
|
|
1169
|
+
yieldRunTasks()
|
|
1170
|
+
})
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
/**
|
|
1175
|
+
* Pause the execution of the current `Micro` effect, and resume it on the next
|
|
1176
|
+
* iteration of the event loop.
|
|
1177
|
+
*
|
|
1178
|
+
* @since 3.4.0
|
|
1179
|
+
* @experimental
|
|
1180
|
+
* @category constructors
|
|
1181
|
+
*/
|
|
1182
|
+
export const yieldNow: Micro<void> = make(function(_env, onResult) {
|
|
1183
|
+
yieldAdd(() => onResult(resultVoid))
|
|
1184
|
+
})
|
|
1185
|
+
|
|
1186
|
+
/**
|
|
1187
|
+
* Flush any yielded effects that are waiting to be executed.
|
|
1188
|
+
*
|
|
1189
|
+
* @since 3.4.0
|
|
1190
|
+
* @experimental
|
|
1191
|
+
* @category constructors
|
|
1192
|
+
*/
|
|
1193
|
+
export const yieldFlush: Micro<void> = sync(function() {
|
|
1194
|
+
while (yieldState.tasks.length > 0) {
|
|
1195
|
+
yieldRunTasks()
|
|
1196
|
+
}
|
|
1197
|
+
})
|
|
1198
|
+
|
|
1199
|
+
/**
|
|
1200
|
+
* A `Micro` that will never succeed or fail. It wraps `setInterval` to prevent
|
|
1201
|
+
* the Javascript runtime from exiting.
|
|
1202
|
+
*
|
|
1203
|
+
* @since 3.4.0
|
|
1204
|
+
* @experimental
|
|
1205
|
+
* @category constructors
|
|
1206
|
+
*/
|
|
1207
|
+
export const never: Micro<never> = async<never>(function() {
|
|
1208
|
+
const interval = setInterval(constVoid, 2147483646)
|
|
1209
|
+
return sync(() => clearInterval(interval))
|
|
1210
|
+
})
|
|
1211
|
+
|
|
1212
|
+
/**
|
|
1213
|
+
* @since 3.4.0
|
|
1214
|
+
* @experimental
|
|
1215
|
+
* @category constructors
|
|
1216
|
+
*/
|
|
1217
|
+
export const gen = <Eff extends YieldWrap<Micro<any, any, any>>, AEff>(
|
|
1218
|
+
f: () => Generator<Eff, AEff, never>
|
|
1219
|
+
): Micro<
|
|
1220
|
+
AEff,
|
|
1221
|
+
[Eff] extends [never] ? never : [Eff] extends [YieldWrap<Micro<infer _A, infer E, infer _R>>] ? E : never,
|
|
1222
|
+
[Eff] extends [never] ? never : [Eff] extends [YieldWrap<Micro<infer _A, infer _E, infer R>>] ? R : never
|
|
1223
|
+
> =>
|
|
1224
|
+
make(function(env, onResult) {
|
|
1225
|
+
const iterator = f() as Iterator<YieldWrap<Micro<any, any, any>>, AEff, any>
|
|
1226
|
+
let running = false
|
|
1227
|
+
let value: any = undefined
|
|
1228
|
+
function run() {
|
|
1229
|
+
running = true
|
|
1230
|
+
try {
|
|
1231
|
+
let shouldContinue = true
|
|
1232
|
+
while (shouldContinue) {
|
|
1233
|
+
const result = iterator.next(value)
|
|
1234
|
+
if (result.done) {
|
|
1235
|
+
return onResult(ResultSuccess(result.value))
|
|
1236
|
+
}
|
|
1237
|
+
shouldContinue = false
|
|
1238
|
+
yieldWrapGet(result.value)[runSymbol](env, function(result) {
|
|
1239
|
+
if (result._tag === "Left") {
|
|
1240
|
+
onResult(result)
|
|
1241
|
+
} else {
|
|
1242
|
+
shouldContinue = true
|
|
1243
|
+
value = result.right
|
|
1244
|
+
if (!running) run()
|
|
1245
|
+
}
|
|
1246
|
+
})
|
|
1247
|
+
}
|
|
1248
|
+
} catch (err) {
|
|
1249
|
+
onResult(ResultFailUnexpected(err))
|
|
1250
|
+
}
|
|
1251
|
+
running = false
|
|
1252
|
+
}
|
|
1253
|
+
run()
|
|
1254
|
+
})
|
|
1255
|
+
|
|
1256
|
+
// ----------------------------------------------------------------------------
|
|
1257
|
+
// mapping & sequencing
|
|
1258
|
+
// ----------------------------------------------------------------------------
|
|
1259
|
+
|
|
1260
|
+
/**
|
|
1261
|
+
* Flattens any nested `Micro` effects, merging the error and requirement types.
|
|
1262
|
+
*
|
|
1263
|
+
* @since 3.4.0
|
|
1264
|
+
* @experimental
|
|
1265
|
+
* @category mapping & sequencing
|
|
1266
|
+
*/
|
|
1267
|
+
export const flatten = <A, E, R, E2, R2>(self: Micro<Micro<A, E, R>, E2, R2>): Micro<A, E | E2, R | R2> =>
|
|
1268
|
+
make(function(env, onResult) {
|
|
1269
|
+
self[runSymbol](
|
|
1270
|
+
env,
|
|
1271
|
+
(result) => result._tag === "Left" ? onResult(result as any) : result.right[runSymbol](env, onResult)
|
|
1272
|
+
)
|
|
1273
|
+
})
|
|
1274
|
+
|
|
1275
|
+
/**
|
|
1276
|
+
* Transforms the success value of the `Micro` effect with the specified
|
|
1277
|
+
* function.
|
|
1278
|
+
*
|
|
1279
|
+
* @since 3.4.0
|
|
1280
|
+
* @experimental
|
|
1281
|
+
* @category mapping & sequencing
|
|
1282
|
+
*/
|
|
1283
|
+
export const map: {
|
|
1284
|
+
<A, B>(f: (a: A) => B): <E, R>(self: Micro<A, E, R>) => Micro<B, E, R>
|
|
1285
|
+
<A, E, R, B>(self: Micro<A, E, R>, f: (a: A) => B): Micro<B, E, R>
|
|
1286
|
+
} = dual(2, <A, E, R, B>(self: Micro<A, E, R>, f: (a: A) => B): Micro<B, E, R> =>
|
|
1287
|
+
make(function(env, onResult) {
|
|
1288
|
+
self[runSymbol](env, function(result) {
|
|
1289
|
+
onResult(result._tag === "Left" ? result as any : ResultSuccess(f(result.right)))
|
|
1290
|
+
})
|
|
1291
|
+
}))
|
|
1292
|
+
|
|
1293
|
+
/**
|
|
1294
|
+
* Create a `Micro` effect that will replace the success value of the given
|
|
1295
|
+
* effect.
|
|
1296
|
+
*
|
|
1297
|
+
* @since 3.4.0
|
|
1298
|
+
* @experimental
|
|
1299
|
+
* @category mapping & sequencing
|
|
1300
|
+
*/
|
|
1301
|
+
export const as: {
|
|
1302
|
+
<A, B>(value: B): <E, R>(self: Micro<A, E, R>) => Micro<B, E, R>
|
|
1303
|
+
<A, E, R, B>(self: Micro<A, E, R>, value: B): Micro<B, E, R>
|
|
1304
|
+
} = dual(2, <A, E, R, B>(self: Micro<A, E, R>, value: B): Micro<B, E, R> => map(self, (_) => value))
|
|
1305
|
+
|
|
1306
|
+
/**
|
|
1307
|
+
* Wrap the success value of this `Micro` effect in an `Option.Some`.
|
|
1308
|
+
*
|
|
1309
|
+
* @since 3.4.0
|
|
1310
|
+
* @experimental
|
|
1311
|
+
* @category mapping & sequencing
|
|
1312
|
+
*/
|
|
1313
|
+
export const asSome = <A, E, R>(self: Micro<A, E, R>): Micro<Option.Option<A>, E, R> => map(self, Option.some) as any
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* Map the success value of this `Micro` effect to another `Micro` effect, then
|
|
1317
|
+
* flatten the result.
|
|
1318
|
+
*
|
|
1319
|
+
* @since 3.4.0
|
|
1320
|
+
* @experimental
|
|
1321
|
+
* @category mapping & sequencing
|
|
1322
|
+
*/
|
|
1323
|
+
export const flatMap: {
|
|
1324
|
+
<A, B, E2, R2>(f: (a: A) => Micro<B, E2, R2>): <E, R>(self: Micro<A, E, R>) => Micro<B, E | E2, R | R2>
|
|
1325
|
+
<A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<B, E | E2, R | R2>
|
|
1326
|
+
} = dual(
|
|
1327
|
+
2,
|
|
1328
|
+
<A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<B, E | E2, R | R2> =>
|
|
1329
|
+
make(function(env, onResult) {
|
|
1330
|
+
self[runSymbol](env, function(result) {
|
|
1331
|
+
if (result._tag === "Left") {
|
|
1332
|
+
return onResult(result as any)
|
|
1333
|
+
}
|
|
1334
|
+
f(result.right)[runSymbol](env, onResult)
|
|
1335
|
+
})
|
|
1336
|
+
})
|
|
1337
|
+
)
|
|
1338
|
+
|
|
1339
|
+
/**
|
|
1340
|
+
* Swap the error and success types of the `Micro` effect.
|
|
1341
|
+
*
|
|
1342
|
+
* @since 3.4.0
|
|
1343
|
+
* @experimental
|
|
1344
|
+
* @category mapping & sequencing
|
|
1345
|
+
*/
|
|
1346
|
+
export const flip = <A, E, R>(self: Micro<A, E, R>): Micro<E, A, R> =>
|
|
1347
|
+
matchMicro(self, {
|
|
1348
|
+
onFailure: succeed,
|
|
1349
|
+
onSuccess: fail
|
|
1350
|
+
})
|
|
1351
|
+
|
|
1352
|
+
/**
|
|
1353
|
+
* A more flexible version of `flatMap`, that combines `map` and `flatMap` into
|
|
1354
|
+
* a single api.
|
|
1355
|
+
*
|
|
1356
|
+
* It also allows you to pass in a `Micro` effect directly, which will be
|
|
1357
|
+
* executed after the current effect.
|
|
1358
|
+
*
|
|
1359
|
+
* @since 3.4.0
|
|
1360
|
+
* @experimental
|
|
1361
|
+
* @category mapping & sequencing
|
|
1362
|
+
*/
|
|
1363
|
+
export const andThen: {
|
|
1364
|
+
<A, X>(
|
|
1365
|
+
f: (a: A) => X
|
|
1366
|
+
): <E, R>(
|
|
1367
|
+
self: Micro<A, E, R>
|
|
1368
|
+
) => [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
|
|
1369
|
+
: Micro<X, E, R>
|
|
1370
|
+
<X>(
|
|
1371
|
+
f: NotFunction<X>
|
|
1372
|
+
): <A, E, R>(
|
|
1373
|
+
self: Micro<A, E, R>
|
|
1374
|
+
) => [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
|
|
1375
|
+
: Micro<X, E, R>
|
|
1376
|
+
<A, E, R, X>(
|
|
1377
|
+
self: Micro<A, E, R>,
|
|
1378
|
+
f: (a: A) => X
|
|
1379
|
+
): [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
|
|
1380
|
+
: Micro<X, E, R>
|
|
1381
|
+
<A, E, R, X>(
|
|
1382
|
+
self: Micro<A, E, R>,
|
|
1383
|
+
f: NotFunction<X>
|
|
1384
|
+
): [X] extends [Micro<infer A1, infer E1, infer R1>] ? Micro<A1, E | E1, R | R1>
|
|
1385
|
+
: Micro<X, E, R>
|
|
1386
|
+
} = dual(
|
|
1387
|
+
2,
|
|
1388
|
+
<A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: any): Micro<B, E | E2, R | R2> =>
|
|
1389
|
+
make(function(env, onResult) {
|
|
1390
|
+
self[runSymbol](env, function(result) {
|
|
1391
|
+
if (result._tag === "Left") {
|
|
1392
|
+
return onResult(result as any)
|
|
1393
|
+
} else if (envGet(env, currentAbortSignal).aborted) {
|
|
1394
|
+
return onResult(ResultAborted)
|
|
1395
|
+
}
|
|
1396
|
+
const value = isMicro(f) ? f : typeof f === "function" ? f(result.right) : f
|
|
1397
|
+
if (isMicro(value)) {
|
|
1398
|
+
value[runSymbol](env, onResult)
|
|
1399
|
+
} else {
|
|
1400
|
+
onResult(ResultSuccess(value))
|
|
1401
|
+
}
|
|
1402
|
+
})
|
|
1403
|
+
})
|
|
1404
|
+
)
|
|
1405
|
+
|
|
1406
|
+
/**
|
|
1407
|
+
* Execute a side effect from the success value of the `Micro` effect.
|
|
1408
|
+
*
|
|
1409
|
+
* It is similar to the `andThen` api, but the success value is ignored.
|
|
1410
|
+
*
|
|
1411
|
+
* @since 3.4.0
|
|
1412
|
+
* @experimental
|
|
1413
|
+
* @category mapping & sequencing
|
|
1414
|
+
*/
|
|
1415
|
+
export const tap: {
|
|
1416
|
+
<A, X>(
|
|
1417
|
+
f: (a: NoInfer<A>) => X
|
|
1418
|
+
): <E, R>(
|
|
1419
|
+
self: Micro<A, E, R>
|
|
1420
|
+
) => [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
|
|
1421
|
+
: Micro<A, E, R>
|
|
1422
|
+
<X>(
|
|
1423
|
+
f: NotFunction<X>
|
|
1424
|
+
): <A, E, R>(
|
|
1425
|
+
self: Micro<A, E, R>
|
|
1426
|
+
) => [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
|
|
1427
|
+
: Micro<A, E, R>
|
|
1428
|
+
<A, E, R, X>(
|
|
1429
|
+
self: Micro<A, E, R>,
|
|
1430
|
+
f: (a: NoInfer<A>) => X
|
|
1431
|
+
): [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
|
|
1432
|
+
: Micro<A, E, R>
|
|
1433
|
+
<A, E, R, X>(
|
|
1434
|
+
self: Micro<A, E, R>,
|
|
1435
|
+
f: NotFunction<X>
|
|
1436
|
+
): [X] extends [Micro<infer _A1, infer E1, infer R1>] ? Micro<A, E | E1, R | R1>
|
|
1437
|
+
: Micro<A, E, R>
|
|
1438
|
+
} = dual(
|
|
1439
|
+
2,
|
|
1440
|
+
<A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: A) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2> =>
|
|
1441
|
+
make(function(env, onResult) {
|
|
1442
|
+
self[runSymbol](env, function(selfResult) {
|
|
1443
|
+
if (selfResult._tag === "Left") {
|
|
1444
|
+
return onResult(selfResult as any)
|
|
1445
|
+
} else if (envGet(env, currentAbortSignal).aborted) {
|
|
1446
|
+
return onResult(ResultAborted)
|
|
1447
|
+
}
|
|
1448
|
+
const value = isMicro(f) ? f : typeof f === "function" ? f(selfResult.right) : f
|
|
1449
|
+
if (isMicro(value)) {
|
|
1450
|
+
value[runSymbol](env, function(tapResult) {
|
|
1451
|
+
if (tapResult._tag === "Left") {
|
|
1452
|
+
return onResult(tapResult)
|
|
1453
|
+
}
|
|
1454
|
+
onResult(selfResult)
|
|
1455
|
+
})
|
|
1456
|
+
} else {
|
|
1457
|
+
onResult(selfResult)
|
|
1458
|
+
}
|
|
1459
|
+
})
|
|
1460
|
+
})
|
|
1461
|
+
)
|
|
1462
|
+
|
|
1463
|
+
/**
|
|
1464
|
+
* Replace the success value of the `Micro` effect with `void`.
|
|
1465
|
+
*
|
|
1466
|
+
* @since 3.4.0
|
|
1467
|
+
* @experimental
|
|
1468
|
+
* @category mapping & sequencing
|
|
1469
|
+
*/
|
|
1470
|
+
export const asVoid = <A, E, R>(self: Micro<A, E, R>): Micro<void, E, R> => map(self, (_) => void 0)
|
|
1471
|
+
|
|
1472
|
+
/**
|
|
1473
|
+
* Access the `Result` of the given `Micro` effect.
|
|
1474
|
+
*
|
|
1475
|
+
* @since 3.4.0
|
|
1476
|
+
* @experimental
|
|
1477
|
+
* @category mapping & sequencing
|
|
1478
|
+
*/
|
|
1479
|
+
export const asResult = <A, E, R>(self: Micro<A, E, R>): Micro<Result<A, E>, never, R> =>
|
|
1480
|
+
make(function(env, onResult) {
|
|
1481
|
+
self[runSymbol](env, function(result) {
|
|
1482
|
+
onResult(ResultSuccess(result))
|
|
1483
|
+
})
|
|
1484
|
+
})
|
|
1485
|
+
|
|
1486
|
+
/**
|
|
1487
|
+
* Replace the error type of the given `Micro` with the full `Failure` object.
|
|
1488
|
+
*
|
|
1489
|
+
* @since 3.4.0
|
|
1490
|
+
* @experimental
|
|
1491
|
+
* @category mapping & sequencing
|
|
1492
|
+
*/
|
|
1493
|
+
export const sandbox = <A, E, R>(self: Micro<A, E, R>): Micro<A, Failure<E>, R> =>
|
|
1494
|
+
catchFailure(self, (failure) => fail(failure))
|
|
1495
|
+
|
|
1496
|
+
function forkSignal(env: Env<any>) {
|
|
1497
|
+
const controller = new AbortController()
|
|
1498
|
+
const parentSignal = envGet(env, currentAbortSignal)
|
|
1499
|
+
function onAbort() {
|
|
1500
|
+
controller.abort()
|
|
1501
|
+
parentSignal.removeEventListener("abort", onAbort)
|
|
1502
|
+
}
|
|
1503
|
+
parentSignal.addEventListener("abort", onAbort)
|
|
1504
|
+
const envWithSignal = envMutate(env, function(refs) {
|
|
1505
|
+
refs[currentAbortController.key] = controller
|
|
1506
|
+
refs[currentAbortSignal.key] = controller.signal
|
|
1507
|
+
return refs
|
|
1508
|
+
})
|
|
1509
|
+
return [envWithSignal, onAbort] as const
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
/**
|
|
1513
|
+
* Returns an effect that races all the specified effects,
|
|
1514
|
+
* yielding the value of the first effect to succeed with a value. Losers of
|
|
1515
|
+
* the race will be interrupted immediately
|
|
1516
|
+
*
|
|
1517
|
+
* @since 3.4.0
|
|
1518
|
+
* @experimental
|
|
1519
|
+
* @category sequencing
|
|
1520
|
+
*/
|
|
1521
|
+
export const raceAll = <Eff extends Micro<any, any, any>>(
|
|
1522
|
+
all: Iterable<Eff>
|
|
1523
|
+
): Micro<Micro.Success<Eff>, Micro.Error<Eff>, Micro.Context<Eff>> =>
|
|
1524
|
+
make(function(env, onResult) {
|
|
1525
|
+
const [envWithSignal, onAbort] = forkSignal(env)
|
|
1526
|
+
|
|
1527
|
+
const effects = Array.from(all)
|
|
1528
|
+
let len = effects.length
|
|
1529
|
+
let index = 0
|
|
1530
|
+
let done = 0
|
|
1531
|
+
let result: Result<any, any> | undefined = undefined
|
|
1532
|
+
const failures: Array<Failure<any>> = []
|
|
1533
|
+
function onDone(result_: Result<any, any>) {
|
|
1534
|
+
done++
|
|
1535
|
+
if (result_._tag === "Right" && result === undefined) {
|
|
1536
|
+
len = index
|
|
1537
|
+
result = result_
|
|
1538
|
+
onAbort()
|
|
1539
|
+
} else if (result_._tag === "Left") {
|
|
1540
|
+
failures.push(result_.left)
|
|
1541
|
+
}
|
|
1542
|
+
if (done >= len) {
|
|
1543
|
+
onResult(result ?? Either.left(failures[0]))
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
for (; index < len; index++) {
|
|
1548
|
+
effects[index][runSymbol](envWithSignal, onDone)
|
|
1549
|
+
}
|
|
1550
|
+
})
|
|
1551
|
+
|
|
1552
|
+
/**
|
|
1553
|
+
* Returns an effect that races all the specified effects,
|
|
1554
|
+
* yielding the value of the first effect to succeed or fail. Losers of
|
|
1555
|
+
* the race will be interrupted immediately
|
|
1556
|
+
*
|
|
1557
|
+
* @since 3.4.0
|
|
1558
|
+
* @experimental
|
|
1559
|
+
* @category sequencing
|
|
1560
|
+
*/
|
|
1561
|
+
export const raceAllFirst = <Eff extends Micro<any, any, any>>(
|
|
1562
|
+
all: Iterable<Eff>
|
|
1563
|
+
): Micro<Micro.Success<Eff>, Micro.Error<Eff>, Micro.Context<Eff>> =>
|
|
1564
|
+
make(function(env, onResult) {
|
|
1565
|
+
const [envWithSignal, onAbort] = forkSignal(env)
|
|
1566
|
+
|
|
1567
|
+
const effects = Array.from(all)
|
|
1568
|
+
let len = effects.length
|
|
1569
|
+
let index = 0
|
|
1570
|
+
let done = 0
|
|
1571
|
+
let result: Result<any, any> | undefined = undefined
|
|
1572
|
+
const failures: Array<Failure<any>> = []
|
|
1573
|
+
function onDone(result_: Result<any, any>) {
|
|
1574
|
+
done++
|
|
1575
|
+
if (result === undefined) {
|
|
1576
|
+
len = index
|
|
1577
|
+
result = result_
|
|
1578
|
+
onAbort()
|
|
1579
|
+
}
|
|
1580
|
+
if (done >= len) {
|
|
1581
|
+
onResult(result ?? Either.left(failures[0]))
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
for (; index < len; index++) {
|
|
1586
|
+
effects[index][runSymbol](envWithSignal, onDone)
|
|
1587
|
+
}
|
|
1588
|
+
})
|
|
1589
|
+
|
|
1590
|
+
/**
|
|
1591
|
+
* Returns an effect that races two effects, yielding the value of the first
|
|
1592
|
+
* effect to succeed. Losers of the race will be interrupted immediately
|
|
1593
|
+
*
|
|
1594
|
+
* @since 3.4.0
|
|
1595
|
+
* @experimental
|
|
1596
|
+
* @category sequencing
|
|
1597
|
+
*/
|
|
1598
|
+
export const race: {
|
|
1599
|
+
<A2, E2, R2>(that: Micro<A2, E2, R2>): <A, E, R>(self: Micro<A, E, R>) => Micro<A | A2, E | E2, R | R2>
|
|
1600
|
+
<A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2>
|
|
1601
|
+
} = dual(
|
|
1602
|
+
2,
|
|
1603
|
+
<A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2> =>
|
|
1604
|
+
raceAll([self, that])
|
|
1605
|
+
)
|
|
1606
|
+
|
|
1607
|
+
/**
|
|
1608
|
+
* Returns an effect that races two effects, yielding the value of the first
|
|
1609
|
+
* effect to succeed *or* fail. Losers of the race will be interrupted immediately
|
|
1610
|
+
*
|
|
1611
|
+
* @since 3.4.0
|
|
1612
|
+
* @experimental
|
|
1613
|
+
* @category sequencing
|
|
1614
|
+
*/
|
|
1615
|
+
export const raceFirst: {
|
|
1616
|
+
<A2, E2, R2>(that: Micro<A2, E2, R2>): <A, E, R>(self: Micro<A, E, R>) => Micro<A | A2, E | E2, R | R2>
|
|
1617
|
+
<A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2>
|
|
1618
|
+
} = dual(
|
|
1619
|
+
2,
|
|
1620
|
+
<A, E, R, A2, E2, R2>(self: Micro<A, E, R>, that: Micro<A2, E2, R2>): Micro<A | A2, E | E2, R | R2> =>
|
|
1621
|
+
raceAllFirst([self, that])
|
|
1622
|
+
)
|
|
1623
|
+
|
|
1624
|
+
// ----------------------------------------------------------------------------
|
|
1625
|
+
// zipping
|
|
1626
|
+
// ----------------------------------------------------------------------------
|
|
1627
|
+
|
|
1628
|
+
/**
|
|
1629
|
+
* Combine two `Micro` effects into a single effect that produces a tuple of
|
|
1630
|
+
* their results.
|
|
1631
|
+
*
|
|
1632
|
+
* @since 3.4.0
|
|
1633
|
+
* @experimental
|
|
1634
|
+
* @category zipping
|
|
1635
|
+
*/
|
|
1636
|
+
export const zip: {
|
|
1637
|
+
<A2, E2, R2>(
|
|
1638
|
+
that: Micro<A2, E2, R2>,
|
|
1639
|
+
options?:
|
|
1640
|
+
| { readonly concurrent?: boolean | undefined }
|
|
1641
|
+
| undefined
|
|
1642
|
+
): <A, E, R>(self: Micro<A, E, R>) => Micro<[A, A2], E2 | E, R2 | R>
|
|
1643
|
+
<A, E, R, A2, E2, R2>(
|
|
1644
|
+
self: Micro<A, E, R>,
|
|
1645
|
+
that: Micro<A2, E2, R2>,
|
|
1646
|
+
options?:
|
|
1647
|
+
| { readonly concurrent?: boolean | undefined }
|
|
1648
|
+
| undefined
|
|
1649
|
+
): Micro<[A, A2], E | E2, R | R2>
|
|
1650
|
+
} = dual((args) => isMicro(args[1]), <A, E, R, A2, E2, R2>(
|
|
1651
|
+
self: Micro<A, E, R>,
|
|
1652
|
+
that: Micro<A2, E2, R2>,
|
|
1653
|
+
options?:
|
|
1654
|
+
| { readonly concurrent?: boolean | undefined }
|
|
1655
|
+
| undefined
|
|
1656
|
+
): Micro<[A, A2], E | E2, R | R2> => {
|
|
1657
|
+
if (options?.concurrent) {
|
|
1658
|
+
return all([self, that], { concurrency: "unbounded" })
|
|
1659
|
+
}
|
|
1660
|
+
return flatMap(self, (a) => map(that, (a2) => [a, a2]))
|
|
1661
|
+
})
|
|
1662
|
+
|
|
1663
|
+
// ----------------------------------------------------------------------------
|
|
1664
|
+
// filtering & conditionals
|
|
1665
|
+
// ----------------------------------------------------------------------------
|
|
1666
|
+
|
|
1667
|
+
/**
|
|
1668
|
+
* Filter the specified effect with the provided function, failing with specified
|
|
1669
|
+
* `Failure` if the predicate fails.
|
|
1670
|
+
*
|
|
1671
|
+
* In addition to the filtering capabilities discussed earlier, you have the option to further
|
|
1672
|
+
* refine and narrow down the type of the success channel by providing a
|
|
1673
|
+
*
|
|
1674
|
+
* @since 3.4.0
|
|
1675
|
+
* @experimental
|
|
1676
|
+
* @category filtering & conditionals
|
|
1677
|
+
*/
|
|
1678
|
+
export const filterOrFailWith: {
|
|
1679
|
+
<A, B extends A, E2>(
|
|
1680
|
+
refinement: Refinement<A, B>,
|
|
1681
|
+
orFailWith: (a: NoInfer<A>) => Failure<E2>
|
|
1682
|
+
): <E, R>(self: Micro<A, E, R>) => Micro<B, E2 | E, R>
|
|
1683
|
+
<A, E2>(
|
|
1684
|
+
predicate: Predicate<NoInfer<A>>,
|
|
1685
|
+
orFailWith: (a: NoInfer<A>) => Failure<E2>
|
|
1686
|
+
): <E, R>(self: Micro<A, E, R>) => Micro<A, E2 | E, R>
|
|
1687
|
+
<A, E, R, B extends A, E2>(
|
|
1688
|
+
self: Micro<A, E, R>,
|
|
1689
|
+
refinement: Refinement<A, B>,
|
|
1690
|
+
orFailWith: (a: A) => Failure<E2>
|
|
1691
|
+
): Micro<B, E | E2, R>
|
|
1692
|
+
<A, E, R, E2>(self: Micro<A, E, R>, predicate: Predicate<A>, orFailWith: (a: A) => Failure<E2>): Micro<A, E | E2, R>
|
|
1693
|
+
} = dual((args) => isMicro(args[0]), <A, E, R, B extends A, E2>(
|
|
1694
|
+
self: Micro<A, E, R>,
|
|
1695
|
+
refinement: Refinement<A, B>,
|
|
1696
|
+
orFailWith: (a: A) => Failure<E2>
|
|
1697
|
+
): Micro<B, E | E2, R> => flatMap(self, (a) => refinement(a) ? succeed(a as any) : failWith(orFailWith(a))))
|
|
1698
|
+
|
|
1699
|
+
/**
|
|
1700
|
+
* Filter the specified effect with the provided function, failing with specified
|
|
1701
|
+
* error if the predicate fails.
|
|
1702
|
+
*
|
|
1703
|
+
* In addition to the filtering capabilities discussed earlier, you have the option to further
|
|
1704
|
+
* refine and narrow down the type of the success channel by providing a
|
|
1705
|
+
*
|
|
1706
|
+
* @since 3.4.0
|
|
1707
|
+
* @experimental
|
|
1708
|
+
* @category filtering & conditionals
|
|
1709
|
+
*/
|
|
1710
|
+
export const filterOrFail: {
|
|
1711
|
+
<A, B extends A, E2>(
|
|
1712
|
+
refinement: Refinement<A, B>,
|
|
1713
|
+
orFailWith: (a: NoInfer<A>) => E2
|
|
1714
|
+
): <E, R>(self: Micro<A, E, R>) => Micro<B, E2 | E, R>
|
|
1715
|
+
<A, E2>(
|
|
1716
|
+
predicate: Predicate<NoInfer<A>>,
|
|
1717
|
+
orFailWith: (a: NoInfer<A>) => E2
|
|
1718
|
+
): <E, R>(self: Micro<A, E, R>) => Micro<A, E2 | E, R>
|
|
1719
|
+
<A, E, R, B extends A, E2>(
|
|
1720
|
+
self: Micro<A, E, R>,
|
|
1721
|
+
refinement: Refinement<A, B>,
|
|
1722
|
+
orFailWith: (a: A) => E2
|
|
1723
|
+
): Micro<B, E | E2, R>
|
|
1724
|
+
<A, E, R, E2>(self: Micro<A, E, R>, predicate: Predicate<A>, orFailWith: (a: A) => E2): Micro<A, E | E2, R>
|
|
1725
|
+
} = dual((args) => isMicro(args[0]), <A, E, R, B extends A, E2>(
|
|
1726
|
+
self: Micro<A, E, R>,
|
|
1727
|
+
refinement: Refinement<A, B>,
|
|
1728
|
+
orFailWith: (a: A) => E2
|
|
1729
|
+
): Micro<B, E | E2, R> => flatMap(self, (a) => refinement(a) ? succeed(a as any) : fail(orFailWith(a))))
|
|
1730
|
+
|
|
1731
|
+
/**
|
|
1732
|
+
* The moral equivalent of `if (p) exp`.
|
|
1733
|
+
*
|
|
1734
|
+
* @since 3.4.0
|
|
1735
|
+
* @experimental
|
|
1736
|
+
* @category filtering & conditionals
|
|
1737
|
+
*/
|
|
1738
|
+
export const when: {
|
|
1739
|
+
<E2 = never, R2 = never>(
|
|
1740
|
+
condition: LazyArg<boolean> | Micro<boolean, E2, R2>
|
|
1741
|
+
): <A, E, R>(self: Micro<A, E, R>) => Micro<Option.Option<A>, E | E2, R | R2>
|
|
1742
|
+
<A, E, R, E2 = never, R2 = never>(
|
|
1743
|
+
self: Micro<A, E, R>,
|
|
1744
|
+
condition: LazyArg<boolean> | Micro<boolean, E2, R2>
|
|
1745
|
+
): Micro<Option.Option<A>, E | E2, R | R2>
|
|
1746
|
+
} = dual(
|
|
1747
|
+
2,
|
|
1748
|
+
<A, E, R, E2 = never, R2 = never>(
|
|
1749
|
+
self: Micro<A, E, R>,
|
|
1750
|
+
condition: LazyArg<boolean> | Micro<boolean, E2, R2>
|
|
1751
|
+
): Micro<Option.Option<A>, E | E2, R | R2> =>
|
|
1752
|
+
flatMap(isMicro(condition) ? condition : sync(condition), (pass) => pass ? asSome(self) : succeed(Option.none()))
|
|
1753
|
+
)
|
|
1754
|
+
|
|
1755
|
+
// ----------------------------------------------------------------------------
|
|
1756
|
+
// repetition
|
|
1757
|
+
// ----------------------------------------------------------------------------
|
|
1758
|
+
|
|
1759
|
+
/**
|
|
1760
|
+
* Repeat the given `Micro` using the provided options.
|
|
1761
|
+
*
|
|
1762
|
+
* The `while` predicate will be checked after each iteration, and can use the
|
|
1763
|
+
* fall `Result` of the effect to determine if the repetition should continue.
|
|
1764
|
+
*
|
|
1765
|
+
* @since 3.4.0
|
|
1766
|
+
* @experimental
|
|
1767
|
+
* @category repetition
|
|
1768
|
+
*/
|
|
1769
|
+
export const repeatResult: {
|
|
1770
|
+
<A, E>(options: {
|
|
1771
|
+
while: Predicate<Result<A, E>>
|
|
1772
|
+
times?: number | undefined
|
|
1773
|
+
delay?: DelayFn | undefined
|
|
1774
|
+
}): <R>(self: Micro<A, E, R>) => Micro<A, E, R>
|
|
1775
|
+
<A, E, R>(self: Micro<A, E, R>, options: {
|
|
1776
|
+
while: Predicate<Result<A, E>>
|
|
1777
|
+
times?: number | undefined
|
|
1778
|
+
delay?: DelayFn | undefined
|
|
1779
|
+
}): Micro<A, E, R>
|
|
1780
|
+
} = dual(2, <A, E, R>(self: Micro<A, E, R>, options: {
|
|
1781
|
+
while: Predicate<Result<A, E>>
|
|
1782
|
+
times?: number | undefined
|
|
1783
|
+
delay?: DelayFn | undefined
|
|
1784
|
+
}): Micro<A, E, R> =>
|
|
1785
|
+
make(function(env, onResult) {
|
|
1786
|
+
const startedAt = options.delay ? Date.now() : 0
|
|
1787
|
+
let attempt = 0
|
|
1788
|
+
self[runSymbol](env, function loop(result) {
|
|
1789
|
+
if (options.while !== undefined && !options.while(result)) {
|
|
1790
|
+
return onResult(result)
|
|
1791
|
+
} else if (options.times !== undefined && attempt >= options.times) {
|
|
1792
|
+
return onResult(result)
|
|
1793
|
+
}
|
|
1794
|
+
attempt++
|
|
1795
|
+
let delayEffect = yieldNow
|
|
1796
|
+
if (options.delay !== undefined) {
|
|
1797
|
+
const elapsed = Date.now() - startedAt
|
|
1798
|
+
const duration = options.delay(attempt, elapsed)
|
|
1799
|
+
if (Option.isNone(duration)) {
|
|
1800
|
+
return onResult(result)
|
|
1801
|
+
}
|
|
1802
|
+
delayEffect = sleep(duration.value)
|
|
1803
|
+
}
|
|
1804
|
+
delayEffect[runSymbol](env, function(result) {
|
|
1805
|
+
if (result._tag === "Left") {
|
|
1806
|
+
return onResult(result as any)
|
|
1807
|
+
}
|
|
1808
|
+
self[runSymbol](env, loop)
|
|
1809
|
+
})
|
|
1810
|
+
})
|
|
1811
|
+
}))
|
|
1812
|
+
|
|
1813
|
+
/**
|
|
1814
|
+
* Repeat the given `Micro` effect using the provided options. Only successful
|
|
1815
|
+
* results will be repeated.
|
|
1816
|
+
*
|
|
1817
|
+
* @since 3.4.0
|
|
1818
|
+
* @experimental
|
|
1819
|
+
* @category repetition
|
|
1820
|
+
*/
|
|
1821
|
+
export const repeat: {
|
|
1822
|
+
<A, E>(
|
|
1823
|
+
options?: {
|
|
1824
|
+
while?: Predicate<A> | undefined
|
|
1825
|
+
times?: number | undefined
|
|
1826
|
+
delay?: DelayFn | undefined
|
|
1827
|
+
} | undefined
|
|
1828
|
+
): <R>(self: Micro<A, E, R>) => Micro<A, E, R>
|
|
1829
|
+
<A, E, R>(
|
|
1830
|
+
self: Micro<A, E, R>,
|
|
1831
|
+
options?: {
|
|
1832
|
+
while?: Predicate<A> | undefined
|
|
1833
|
+
times?: number | undefined
|
|
1834
|
+
delay?: DelayFn | undefined
|
|
1835
|
+
} | undefined
|
|
1836
|
+
): Micro<A, E, R>
|
|
1837
|
+
} = dual((args) => isMicro(args[0]), <A, E, R>(
|
|
1838
|
+
self: Micro<A, E, R>,
|
|
1839
|
+
options?: {
|
|
1840
|
+
while?: Predicate<A> | undefined
|
|
1841
|
+
times?: number | undefined
|
|
1842
|
+
delay?: DelayFn | undefined
|
|
1843
|
+
} | undefined
|
|
1844
|
+
): Micro<A, E, R> =>
|
|
1845
|
+
repeatResult(self, {
|
|
1846
|
+
...options,
|
|
1847
|
+
while: (result) => result._tag === "Right" && (options?.while === undefined || options.while(result.right))
|
|
1848
|
+
}))
|
|
1849
|
+
|
|
1850
|
+
/**
|
|
1851
|
+
* Repeat the given `Micro` effect forever, only stopping if the effect fails.
|
|
1852
|
+
*
|
|
1853
|
+
* @since 3.4.0
|
|
1854
|
+
* @experimental
|
|
1855
|
+
* @category repetition
|
|
1856
|
+
*/
|
|
1857
|
+
export const forever = <A, E, R>(self: Micro<A, E, R>): Micro<never, E, R> => repeat(self) as any
|
|
1858
|
+
|
|
1859
|
+
// ----------------------------------------------------------------------------
|
|
1860
|
+
// delay fn
|
|
1861
|
+
// ----------------------------------------------------------------------------
|
|
1862
|
+
|
|
1863
|
+
/**
|
|
1864
|
+
* Represents a function that can be used to calculate the delay between
|
|
1865
|
+
* repeats.
|
|
1866
|
+
*
|
|
1867
|
+
* The function takes the current attempt number and the elapsed time since
|
|
1868
|
+
* the first attempt, and returns the delay for the next attempt. If the
|
|
1869
|
+
* function returns `None`, the repetition will stop.
|
|
1870
|
+
*
|
|
1871
|
+
* @since 3.4.0
|
|
1872
|
+
* @experimental
|
|
1873
|
+
* @category delay fn
|
|
1874
|
+
*/
|
|
1875
|
+
export type DelayFn = (attempt: number, elapsed: number) => Option.Option<number>
|
|
1876
|
+
|
|
1877
|
+
/**
|
|
1878
|
+
* Create a `DelayFn` that will generate a duration with an exponential backoff.
|
|
1879
|
+
*
|
|
1880
|
+
* @since 3.4.0
|
|
1881
|
+
* @experimental
|
|
1882
|
+
* @category delay fn
|
|
1883
|
+
*/
|
|
1884
|
+
export const delayExponential = (baseMillis: number, factor = 2): DelayFn => (attempt) =>
|
|
1885
|
+
Option.some(attempt ** factor * baseMillis)
|
|
1886
|
+
|
|
1887
|
+
/**
|
|
1888
|
+
* Create a `DelayFn` that will generate a duration with fixed intervals.
|
|
1889
|
+
*
|
|
1890
|
+
* @since 3.4.0
|
|
1891
|
+
* @experimental
|
|
1892
|
+
* @category delay fn
|
|
1893
|
+
*/
|
|
1894
|
+
export const delaySpaced = (millis: number): DelayFn => (_) => Option.some(millis)
|
|
1895
|
+
|
|
1896
|
+
/**
|
|
1897
|
+
* Transform a `DelayFn` to one that will have a duration that will never exceed
|
|
1898
|
+
* the specified maximum.
|
|
1899
|
+
*
|
|
1900
|
+
* @since 3.4.0
|
|
1901
|
+
* @experimental
|
|
1902
|
+
* @category delay fn
|
|
1903
|
+
*/
|
|
1904
|
+
export const delayWithMax: {
|
|
1905
|
+
(max: number): (self: DelayFn) => DelayFn
|
|
1906
|
+
(self: DelayFn, max: number): DelayFn
|
|
1907
|
+
} = dual(
|
|
1908
|
+
2,
|
|
1909
|
+
(self: DelayFn, max: number): DelayFn => (attempt, elapsed) =>
|
|
1910
|
+
Option.map(self(attempt, elapsed), (duration) => Math.min(duration, max))
|
|
1911
|
+
)
|
|
1912
|
+
|
|
1913
|
+
/**
|
|
1914
|
+
* Transform a `DelayFn` to one that will stop repeating after the specified
|
|
1915
|
+
* amount of time.
|
|
1916
|
+
*
|
|
1917
|
+
* @since 3.4.0
|
|
1918
|
+
* @experimental
|
|
1919
|
+
* @category delay fn
|
|
1920
|
+
*/
|
|
1921
|
+
export const delayWithMaxElapsed: {
|
|
1922
|
+
(max: number): (self: DelayFn) => DelayFn
|
|
1923
|
+
(self: DelayFn, max: number): DelayFn
|
|
1924
|
+
} = dual(
|
|
1925
|
+
2,
|
|
1926
|
+
(self: DelayFn, max: number): DelayFn => (attempt, elapsed) => elapsed < max ? self(attempt, elapsed) : Option.none()
|
|
1927
|
+
)
|
|
1928
|
+
|
|
1929
|
+
/**
|
|
1930
|
+
* Transform a `DelayFn` to one that will stop repeating after the specified
|
|
1931
|
+
* number of attempts.
|
|
1932
|
+
*
|
|
1933
|
+
* @since 3.4.0
|
|
1934
|
+
* @experimental
|
|
1935
|
+
* @category delay fn
|
|
1936
|
+
*/
|
|
1937
|
+
export const delayWithRecurs: {
|
|
1938
|
+
(n: number): (self: DelayFn) => DelayFn
|
|
1939
|
+
(self: DelayFn, n: number): DelayFn
|
|
1940
|
+
} = dual(
|
|
1941
|
+
2,
|
|
1942
|
+
(self: DelayFn, n: number): DelayFn => (attempt, elapsed) => Option.filter(self(attempt, elapsed), () => attempt <= n)
|
|
1943
|
+
)
|
|
1944
|
+
|
|
1945
|
+
// ----------------------------------------------------------------------------
|
|
1946
|
+
// error handling
|
|
1947
|
+
// ----------------------------------------------------------------------------
|
|
1948
|
+
|
|
1949
|
+
/**
|
|
1950
|
+
* Catch the full `Failure` object of the given `Micro` effect, allowing you to
|
|
1951
|
+
* recover from any kind of failure.
|
|
1952
|
+
*
|
|
1953
|
+
* @since 3.4.0
|
|
1954
|
+
* @experimental
|
|
1955
|
+
* @category error handling
|
|
1956
|
+
*/
|
|
1957
|
+
export const catchFailure: {
|
|
1958
|
+
<E, B, E2, R2>(
|
|
1959
|
+
f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
|
|
1960
|
+
): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
|
|
1961
|
+
<A, E, R, B, E2, R2>(
|
|
1962
|
+
self: Micro<A, E, R>,
|
|
1963
|
+
f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
|
|
1964
|
+
): Micro<A | B, E2, R | R2>
|
|
1965
|
+
} = dual(
|
|
1966
|
+
2,
|
|
1967
|
+
<A, E, R, B, E2, R2>(
|
|
1968
|
+
self: Micro<A, E, R>,
|
|
1969
|
+
f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
|
|
1970
|
+
): Micro<A | B, E2, R | R2> => catchFailureIf(self, constTrue, f)
|
|
1971
|
+
)
|
|
1972
|
+
|
|
1973
|
+
/**
|
|
1974
|
+
* Selectively catch a `Failure` object of the given `Micro` effect,
|
|
1975
|
+
* using the provided predicate to determine if the failure should be caught.
|
|
1976
|
+
*
|
|
1977
|
+
* @since 3.4.0
|
|
1978
|
+
* @experimental
|
|
1979
|
+
* @category error handling
|
|
1980
|
+
*/
|
|
1981
|
+
export const catchFailureIf: {
|
|
1982
|
+
<E, B, E2, R2, EB extends Failure<E>>(
|
|
1983
|
+
refinement: Refinement<Failure<E>, EB>,
|
|
1984
|
+
f: (failure: EB) => Micro<B, E2, R2>
|
|
1985
|
+
): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
|
|
1986
|
+
<E, B, E2, R2>(
|
|
1987
|
+
predicate: Predicate<Failure<NoInfer<E>>>,
|
|
1988
|
+
f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
|
|
1989
|
+
): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
|
|
1990
|
+
<A, E, R, B, E2, R2, EB extends Failure<E>>(
|
|
1991
|
+
self: Micro<A, E, R>,
|
|
1992
|
+
refinement: Refinement<Failure<E>, EB>,
|
|
1993
|
+
f: (failure: EB) => Micro<B, E2, R2>
|
|
1994
|
+
): Micro<A | B, E2, R | R2>
|
|
1995
|
+
<A, E, R, B, E2, R2>(
|
|
1996
|
+
self: Micro<A, E, R>,
|
|
1997
|
+
predicate: Predicate<Failure<NoInfer<E>>>,
|
|
1998
|
+
f: (failure: NoInfer<Failure<E>>) => Micro<B, E2, R2>
|
|
1999
|
+
): Micro<A | B, E2, R | R2>
|
|
2000
|
+
} = dual(3, <A, E, R, B, E2, R2, EB extends Failure<E>>(
|
|
2001
|
+
self: Micro<A, E, R>,
|
|
2002
|
+
refinement: Refinement<Failure<E>, EB>,
|
|
2003
|
+
f: (failure: EB) => Micro<B, E2, R2>
|
|
2004
|
+
): Micro<A | B, E2, R | R2> =>
|
|
2005
|
+
make(function(env, onResult) {
|
|
2006
|
+
self[runSymbol](env, function(result) {
|
|
2007
|
+
if (result._tag === "Right" || !refinement(result.left)) {
|
|
2008
|
+
return onResult(result as any)
|
|
2009
|
+
}
|
|
2010
|
+
f(result.left)[runSymbol](env, onResult)
|
|
2011
|
+
})
|
|
2012
|
+
}))
|
|
2013
|
+
|
|
2014
|
+
/**
|
|
2015
|
+
* Catch the error of the given `Micro` effect, allowing you to recover from it.
|
|
2016
|
+
*
|
|
2017
|
+
* It only catches expected (`FailureExpected`) errors.
|
|
2018
|
+
*
|
|
2019
|
+
* @since 3.4.0
|
|
2020
|
+
* @experimental
|
|
2021
|
+
* @category error handling
|
|
2022
|
+
*/
|
|
2023
|
+
export const catchExpected: {
|
|
2024
|
+
<E, B, E2, R2>(
|
|
2025
|
+
f: (e: NoInfer<E>) => Micro<B, E2, R2>
|
|
2026
|
+
): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
|
|
2027
|
+
<A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (e: NoInfer<E>) => Micro<B, E2, R2>): Micro<A | B, E2, R | R2>
|
|
2028
|
+
} = dual(
|
|
2029
|
+
2,
|
|
2030
|
+
<A, E, R, B, E2, R2>(
|
|
2031
|
+
self: Micro<A, E, R>,
|
|
2032
|
+
f: (a: NoInfer<E>) => Micro<B, E2, R2>
|
|
2033
|
+
): Micro<A | B, E2, R | R2> => catchFailureIf(self, failureIsExpected, (failure) => f(failure.error))
|
|
2034
|
+
)
|
|
2035
|
+
|
|
2036
|
+
/**
|
|
2037
|
+
* Catch any unexpected errors of the given `Micro` effect, allowing you to recover from them.
|
|
2038
|
+
*
|
|
2039
|
+
* @since 3.4.0
|
|
2040
|
+
* @experimental
|
|
2041
|
+
* @category error handling
|
|
2042
|
+
*/
|
|
2043
|
+
export const catchUnexpected: {
|
|
2044
|
+
<E, B, E2, R2>(
|
|
2045
|
+
f: (defect: unknown) => Micro<B, E2, R2>
|
|
2046
|
+
): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E | E2, R | R2>
|
|
2047
|
+
<A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (defect: unknown) => Micro<B, E2, R2>): Micro<A | B, E | E2, R | R2>
|
|
2048
|
+
} = dual(
|
|
2049
|
+
2,
|
|
2050
|
+
<A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (defect: unknown) => Micro<B, E2, R2>): Micro<A | B, E | E2, R | R2> =>
|
|
2051
|
+
catchFailureIf(self, failureIsUnexpected, (failure) => f(failure.defect))
|
|
2052
|
+
)
|
|
2053
|
+
|
|
2054
|
+
/**
|
|
2055
|
+
* Perform a side effect using the full `Failure` object of the given `Micro`.
|
|
2056
|
+
*
|
|
2057
|
+
* @since 3.4.0
|
|
2058
|
+
* @experimental
|
|
2059
|
+
* @category error handling
|
|
2060
|
+
*/
|
|
2061
|
+
export const tapFailure: {
|
|
2062
|
+
<E, B, E2, R2>(
|
|
2063
|
+
f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>
|
|
2064
|
+
): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
|
|
2065
|
+
<A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2>
|
|
2066
|
+
} = dual(
|
|
2067
|
+
2,
|
|
2068
|
+
<A, E, R, B, E2, R2>(
|
|
2069
|
+
self: Micro<A, E, R>,
|
|
2070
|
+
f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>
|
|
2071
|
+
): Micro<A, E | E2, R | R2> => tapFailureIf(self, constTrue, f)
|
|
2072
|
+
)
|
|
2073
|
+
|
|
2074
|
+
/**
|
|
2075
|
+
* Perform a side effect using if a `Failure` object matches the specified
|
|
2076
|
+
* predicate.
|
|
2077
|
+
*
|
|
2078
|
+
* @since 3.4.0
|
|
2079
|
+
* @experimental
|
|
2080
|
+
* @category error handling
|
|
2081
|
+
*/
|
|
2082
|
+
export const tapFailureIf: {
|
|
2083
|
+
<E, B, E2, R2, EB extends Failure<E>>(
|
|
2084
|
+
refinement: Refinement<Failure<E>, EB>,
|
|
2085
|
+
f: (a: EB) => Micro<B, E2, R2>
|
|
2086
|
+
): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
|
|
2087
|
+
<E, B, E2, R2>(
|
|
2088
|
+
predicate: (failure: NoInfer<Failure<E>>) => boolean,
|
|
2089
|
+
f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>
|
|
2090
|
+
): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
|
|
2091
|
+
<A, E, R, B, E2, R2, EB extends Failure<E>>(
|
|
2092
|
+
self: Micro<A, E, R>,
|
|
2093
|
+
refinement: Refinement<Failure<E>, EB>,
|
|
2094
|
+
f: (a: EB) => Micro<B, E2, R2>
|
|
2095
|
+
): Micro<A, E | E2, R | R2>
|
|
2096
|
+
<A, E, R, B, E2, R2>(
|
|
2097
|
+
self: Micro<A, E, R>,
|
|
2098
|
+
predicate: (failure: NoInfer<Failure<E>>) => boolean,
|
|
2099
|
+
f: (a: NoInfer<Failure<E>>) => Micro<B, E2, R2>
|
|
2100
|
+
): Micro<A, E | E2, R | R2>
|
|
2101
|
+
} = dual(
|
|
2102
|
+
3,
|
|
2103
|
+
<A, E, R, B, E2, R2, EB extends Failure<E>>(
|
|
2104
|
+
self: Micro<A, E, R>,
|
|
2105
|
+
refinement: Refinement<Failure<E>, EB>,
|
|
2106
|
+
f: (a: EB) => Micro<B, E2, R2>
|
|
2107
|
+
): Micro<A, E | E2, R | R2> =>
|
|
2108
|
+
catchFailureIf(self, refinement, (failure) => andThen(f(failure as any), failWith(failure)))
|
|
2109
|
+
)
|
|
2110
|
+
|
|
2111
|
+
/**
|
|
2112
|
+
* Perform a side effect from expected errors of the given `Micro`.
|
|
2113
|
+
*
|
|
2114
|
+
* @since 3.4.0
|
|
2115
|
+
* @experimental
|
|
2116
|
+
* @category error handling
|
|
2117
|
+
*/
|
|
2118
|
+
export const tapExpected: {
|
|
2119
|
+
<E, B, E2, R2>(
|
|
2120
|
+
f: (a: NoInfer<E>) => Micro<B, E2, R2>
|
|
2121
|
+
): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
|
|
2122
|
+
<A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: NoInfer<E>) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2>
|
|
2123
|
+
} = dual(
|
|
2124
|
+
2,
|
|
2125
|
+
<A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (a: NoInfer<E>) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2> =>
|
|
2126
|
+
tapFailureIf(self, failureIsExpected, (failure) => f(failure.error))
|
|
2127
|
+
)
|
|
2128
|
+
|
|
2129
|
+
/**
|
|
2130
|
+
* Perform a side effect from unexpected errors of the given `Micro`.
|
|
2131
|
+
*
|
|
2132
|
+
* @since 3.4.0
|
|
2133
|
+
* @experimental
|
|
2134
|
+
* @category error handling
|
|
2135
|
+
*/
|
|
2136
|
+
export const tapUnexpected: {
|
|
2137
|
+
<E, B, E2, R2>(
|
|
2138
|
+
f: (defect: unknown) => Micro<B, E2, R2>
|
|
2139
|
+
): <A, R>(self: Micro<A, E, R>) => Micro<A, E | E2, R | R2>
|
|
2140
|
+
<A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (defect: unknown) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2>
|
|
2141
|
+
} = dual(
|
|
2142
|
+
2,
|
|
2143
|
+
<A, E, R, B, E2, R2>(self: Micro<A, E, R>, f: (defect: unknown) => Micro<B, E2, R2>): Micro<A, E | E2, R | R2> =>
|
|
2144
|
+
tapFailureIf(self, failureIsUnexpected, (failure) => f(failure.defect))
|
|
2145
|
+
)
|
|
2146
|
+
|
|
2147
|
+
/**
|
|
2148
|
+
* Catch any expected errors that match the specified predicate.
|
|
2149
|
+
*
|
|
2150
|
+
* @since 3.4.0
|
|
2151
|
+
* @experimental
|
|
2152
|
+
* @category error handling
|
|
2153
|
+
*/
|
|
2154
|
+
export const catchIf: {
|
|
2155
|
+
<E, EB extends E, B, E2, R2>(
|
|
2156
|
+
pred: Refinement<E, EB>,
|
|
2157
|
+
f: (a: NoInfer<EB>) => Micro<B, E2, R2>
|
|
2158
|
+
): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
|
|
2159
|
+
<E, B, E2, R2>(
|
|
2160
|
+
pred: Predicate<NoInfer<E>>,
|
|
2161
|
+
f: (a: NoInfer<E>) => Micro<B, E2, R2>
|
|
2162
|
+
): <A, R>(self: Micro<A, E, R>) => Micro<A | B, E2, R | R2>
|
|
2163
|
+
<A, E, R, EB extends E, B, E2, R2>(
|
|
2164
|
+
self: Micro<A, E, R>,
|
|
2165
|
+
pred: Refinement<E, EB>,
|
|
2166
|
+
f: (a: NoInfer<EB>) => Micro<B, E2, R2>
|
|
2167
|
+
): Micro<A | B, E2, R | R2>
|
|
2168
|
+
<A, E, R, B, E2, R2>(
|
|
2169
|
+
self: Micro<A, E, R>,
|
|
2170
|
+
pred: Predicate<NoInfer<E>>,
|
|
2171
|
+
f: (a: NoInfer<E>) => Micro<B, E2, R2>
|
|
2172
|
+
): Micro<A | B, E2, R | R2>
|
|
2173
|
+
} = dual(
|
|
2174
|
+
3,
|
|
2175
|
+
<A, E, R, EB extends E, B, E2, R2>(
|
|
2176
|
+
self: Micro<A, E, R>,
|
|
2177
|
+
pred: Refinement<E, EB>,
|
|
2178
|
+
f: (a: NoInfer<EB>) => Micro<B, E2, R2>
|
|
2179
|
+
): Micro<A | B, E2, R | R2> =>
|
|
2180
|
+
catchFailureIf(
|
|
2181
|
+
self,
|
|
2182
|
+
(f): f is Failure.Expected<EB> => failureIsExpected(f) && pred(f.error),
|
|
2183
|
+
(failure) => f(failure.error)
|
|
2184
|
+
)
|
|
2185
|
+
)
|
|
2186
|
+
|
|
2187
|
+
/**
|
|
2188
|
+
* Recovers from the specified tagged error.
|
|
2189
|
+
*
|
|
2190
|
+
* @since 3.4.0
|
|
2191
|
+
* @experimental
|
|
2192
|
+
* @category error handling
|
|
2193
|
+
*/
|
|
2194
|
+
export const catchTag: {
|
|
2195
|
+
<K extends E extends { _tag: string } ? E["_tag"] : never, E, A1, E1, R1>(
|
|
2196
|
+
k: K,
|
|
2197
|
+
f: (e: Extract<E, { _tag: K }>) => Micro<A1, E1, R1>
|
|
2198
|
+
): <A, R>(self: Micro<A, E, R>) => Micro<A1 | A, E1 | Exclude<E, { _tag: K }>, R1 | R>
|
|
2199
|
+
<A, E, R, K extends E extends { _tag: string } ? E["_tag"] : never, R1, E1, A1>(
|
|
2200
|
+
self: Micro<A, E, R>,
|
|
2201
|
+
k: K,
|
|
2202
|
+
f: (e: Extract<E, { _tag: K }>) => Micro<A1, E1, R1>
|
|
2203
|
+
): Micro<A | A1, E1 | Exclude<E, { _tag: K }>, R | R1>
|
|
2204
|
+
} = dual(3, <A, E, R, K extends E extends { _tag: string } ? E["_tag"] : never, R1, E1, A1>(
|
|
2205
|
+
self: Micro<A, E, R>,
|
|
2206
|
+
k: K,
|
|
2207
|
+
f: (e: Extract<E, { _tag: K }>) => Micro<A1, E1, R1>
|
|
2208
|
+
): Micro<A | A1, E1 | Exclude<E, { _tag: K }>, R | R1> => catchIf(self, (error) => isTagged(error, k), f as any))
|
|
2209
|
+
|
|
2210
|
+
/**
|
|
2211
|
+
* Transform the full `Failure` object of the given `Micro` effect.
|
|
2212
|
+
*
|
|
2213
|
+
* @since 3.4.0
|
|
2214
|
+
* @experimental
|
|
2215
|
+
* @category error handling
|
|
2216
|
+
*/
|
|
2217
|
+
export const mapFailure: {
|
|
2218
|
+
<E, E2>(f: (a: Failure<E>) => Failure<E2>): <A, R>(self: Micro<A, E, R>) => Micro<A, E2, R>
|
|
2219
|
+
<A, E, R, E2>(self: Micro<A, E, R>, f: (a: Failure<E>) => Failure<E2>): Micro<A, E2, R>
|
|
2220
|
+
} = dual(
|
|
2221
|
+
2,
|
|
2222
|
+
<A, E, R, E2>(self: Micro<A, E, R>, f: (a: Failure<E>) => Failure<E2>): Micro<A, E2, R> =>
|
|
2223
|
+
catchFailure(self, (failure) => failWith(f(failure)))
|
|
2224
|
+
)
|
|
2225
|
+
|
|
2226
|
+
/**
|
|
2227
|
+
* Transform any expected errors of the given `Micro` effect.
|
|
2228
|
+
*
|
|
2229
|
+
* @since 3.4.0
|
|
2230
|
+
* @experimental
|
|
2231
|
+
* @category error handling
|
|
2232
|
+
*/
|
|
2233
|
+
export const mapError: {
|
|
2234
|
+
<E, E2>(f: (a: E) => E2): <A, R>(self: Micro<A, E, R>) => Micro<A, E2, R>
|
|
2235
|
+
<A, E, R, E2>(self: Micro<A, E, R>, f: (a: E) => E2): Micro<A, E2, R>
|
|
2236
|
+
} = dual(
|
|
2237
|
+
2,
|
|
2238
|
+
<A, E, R, E2>(self: Micro<A, E, R>, f: (a: E) => E2): Micro<A, E2, R> =>
|
|
2239
|
+
catchExpected(self, (error) => fail(f(error)))
|
|
2240
|
+
)
|
|
2241
|
+
|
|
2242
|
+
/**
|
|
2243
|
+
* Elevate any expected errors of the given `Micro` effect to unexpected errors,
|
|
2244
|
+
* resulting in an error type of `never`.
|
|
2245
|
+
*
|
|
2246
|
+
* @since 3.4.0
|
|
2247
|
+
* @experimental
|
|
2248
|
+
* @category error handling
|
|
2249
|
+
*/
|
|
2250
|
+
export const orDie = <A, E, R>(self: Micro<A, E, R>): Micro<A, never, R> => catchExpected(self, die)
|
|
2251
|
+
|
|
2252
|
+
/**
|
|
2253
|
+
* Recover from all errors by succeeding with the given value.
|
|
2254
|
+
*
|
|
2255
|
+
* @since 3.4.0
|
|
2256
|
+
* @experimental
|
|
2257
|
+
* @category error handling
|
|
2258
|
+
*/
|
|
2259
|
+
export const orElseSucceed: {
|
|
2260
|
+
<B>(f: LazyArg<B>): <A, E, R>(self: Micro<A, E, R>) => Micro<A | B, never, R>
|
|
2261
|
+
<A, E, R, B>(self: Micro<A, E, R>, f: LazyArg<B>): Micro<A | B, never, R>
|
|
2262
|
+
} = dual(
|
|
2263
|
+
2,
|
|
2264
|
+
<A, E, R, B>(self: Micro<A, E, R>, f: LazyArg<B>): Micro<A | B, never, R> => catchExpected(self, (_) => sync(f))
|
|
2265
|
+
)
|
|
2266
|
+
|
|
2267
|
+
/**
|
|
2268
|
+
* Ignore any expected errors of the given `Micro` effect, returning `void`.
|
|
2269
|
+
*
|
|
2270
|
+
* @since 3.4.0
|
|
2271
|
+
* @experimental
|
|
2272
|
+
* @category error handling
|
|
2273
|
+
*/
|
|
2274
|
+
export const ignore = <A, E, R>(self: Micro<A, E, R>): Micro<void, never, R> =>
|
|
2275
|
+
matchMicro(self, { onFailure: (_) => void_, onSuccess: (_) => void_ })
|
|
2276
|
+
|
|
2277
|
+
/**
|
|
2278
|
+
* Ignore any expected errors of the given `Micro` effect, returning `void`.
|
|
2279
|
+
*
|
|
2280
|
+
* @since 3.4.0
|
|
2281
|
+
* @experimental
|
|
2282
|
+
* @category error handling
|
|
2283
|
+
*/
|
|
2284
|
+
export const ignoreLogged = <A, E, R>(self: Micro<A, E, R>): Micro<void, never, R> =>
|
|
2285
|
+
matchMicro(self, {
|
|
2286
|
+
onFailure: (failure) => sync(() => console.error(failure)),
|
|
2287
|
+
onSuccess: (_) => void_
|
|
2288
|
+
})
|
|
2289
|
+
|
|
2290
|
+
/**
|
|
2291
|
+
* Replace the success value of the given `Micro` effect with an `Option`,
|
|
2292
|
+
* wrapping the success value in `Some` and returning `None` if the effect fails
|
|
2293
|
+
* with an expected error.
|
|
2294
|
+
*
|
|
2295
|
+
* @since 3.4.0
|
|
2296
|
+
* @experimental
|
|
2297
|
+
* @category error handling
|
|
2298
|
+
*/
|
|
2299
|
+
export const option = <A, E, R>(self: Micro<A, E, R>): Micro<Option.Option<A>, never, R> =>
|
|
2300
|
+
match(self, { onFailure: (_) => Option.none(), onSuccess: Option.some })
|
|
2301
|
+
|
|
2302
|
+
/**
|
|
2303
|
+
* Replace the success value of the given `Micro` effect with an `Either`,
|
|
2304
|
+
* wrapping the success value in `Right` and wrapping any expected errors with
|
|
2305
|
+
* a `Left`.
|
|
2306
|
+
*
|
|
2307
|
+
* @since 3.4.0
|
|
2308
|
+
* @experimental
|
|
2309
|
+
* @category error handling
|
|
2310
|
+
*/
|
|
2311
|
+
export const either = <A, E, R>(self: Micro<A, E, R>): Micro<Either.Either<A, E>, never, R> =>
|
|
2312
|
+
match(self, { onFailure: Either.left, onSuccess: Either.right })
|
|
2313
|
+
|
|
2314
|
+
/**
|
|
2315
|
+
* Retry the given `Micro` effect using the provided options.
|
|
2316
|
+
*
|
|
2317
|
+
* @since 3.4.0
|
|
2318
|
+
* @experimental
|
|
2319
|
+
* @category error handling
|
|
2320
|
+
*/
|
|
2321
|
+
export const retry: {
|
|
2322
|
+
<A, E>(
|
|
2323
|
+
options?: {
|
|
2324
|
+
while?: Predicate<E> | undefined
|
|
2325
|
+
times?: number | undefined
|
|
2326
|
+
delay?: DelayFn | undefined
|
|
2327
|
+
} | undefined
|
|
2328
|
+
): <R>(self: Micro<A, E, R>) => Micro<A, E, R>
|
|
2329
|
+
<A, E, R>(
|
|
2330
|
+
self: Micro<A, E, R>,
|
|
2331
|
+
options?: {
|
|
2332
|
+
while?: Predicate<E> | undefined
|
|
2333
|
+
times?: number | undefined
|
|
2334
|
+
delay?: DelayFn | undefined
|
|
2335
|
+
} | undefined
|
|
2336
|
+
): Micro<A, E, R>
|
|
2337
|
+
} = dual((args) => isMicro(args[0]), <A, E, R>(
|
|
2338
|
+
self: Micro<A, E, R>,
|
|
2339
|
+
options?: {
|
|
2340
|
+
while?: Predicate<E> | undefined
|
|
2341
|
+
times?: number | undefined
|
|
2342
|
+
delay?: DelayFn | undefined
|
|
2343
|
+
} | undefined
|
|
2344
|
+
): Micro<A, E, R> =>
|
|
2345
|
+
repeatResult(self, {
|
|
2346
|
+
...options,
|
|
2347
|
+
while: (result) =>
|
|
2348
|
+
result._tag === "Left" && result.left._tag === "Expected" &&
|
|
2349
|
+
(options?.while === undefined || options.while(result.left.error))
|
|
2350
|
+
}))
|
|
2351
|
+
|
|
2352
|
+
/**
|
|
2353
|
+
* Add a stack trace to any failures that occur in the effect. The trace will be
|
|
2354
|
+
* added to the `traces` field of the `Failure` object.
|
|
2355
|
+
*
|
|
2356
|
+
* @since 3.4.0
|
|
2357
|
+
* @experimental
|
|
2358
|
+
* @category error handling
|
|
2359
|
+
*/
|
|
2360
|
+
export const withTrace: {
|
|
2361
|
+
(name: string): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, R>
|
|
2362
|
+
<A, E, R>(self: Micro<A, E, R>, name: string): Micro<A, E, R>
|
|
2363
|
+
} = function() {
|
|
2364
|
+
const prevLimit = globalThis.Error.stackTraceLimit
|
|
2365
|
+
globalThis.Error.stackTraceLimit = 2
|
|
2366
|
+
const error = new globalThis.Error()
|
|
2367
|
+
globalThis.Error.stackTraceLimit = prevLimit
|
|
2368
|
+
function generate(name: string, failure: Failure<any>) {
|
|
2369
|
+
const stack = error.stack
|
|
2370
|
+
if (!stack) {
|
|
2371
|
+
return failure
|
|
2372
|
+
}
|
|
2373
|
+
const line = stack.split("\n")[2]?.trim().replace(/^at /, "")
|
|
2374
|
+
if (!line) {
|
|
2375
|
+
return failure
|
|
2376
|
+
}
|
|
2377
|
+
const lineMatch = line.match(/\((.*)\)$/)
|
|
2378
|
+
return failureWithTrace(failure, `at ${name} (${lineMatch ? lineMatch[1] : line})`)
|
|
2379
|
+
}
|
|
2380
|
+
const f = (name: string) => (self: Micro<any, any, any>) =>
|
|
2381
|
+
unsafeMakeOptions(function(env, onResult) {
|
|
2382
|
+
self[runSymbol](env, function(result) {
|
|
2383
|
+
onResult(result._tag === "Left" ? Either.left(generate(name, result.left)) : result)
|
|
2384
|
+
})
|
|
2385
|
+
}, false)
|
|
2386
|
+
if (arguments.length === 2) {
|
|
2387
|
+
return f(arguments[1])(arguments[0])
|
|
2388
|
+
}
|
|
2389
|
+
return f(arguments[0])
|
|
2390
|
+
} as any
|
|
2391
|
+
|
|
2392
|
+
// ----------------------------------------------------------------------------
|
|
2393
|
+
// pattern matching
|
|
2394
|
+
// ----------------------------------------------------------------------------
|
|
2395
|
+
|
|
2396
|
+
/**
|
|
2397
|
+
* @since 3.4.0
|
|
2398
|
+
* @experimental
|
|
2399
|
+
* @category pattern matching
|
|
2400
|
+
*/
|
|
2401
|
+
export const matchFailureMicro: {
|
|
2402
|
+
<E, A2, E2, R2, A, A3, E3, R3>(
|
|
2403
|
+
options: {
|
|
2404
|
+
readonly onFailure: (failure: Failure<E>) => Micro<A2, E2, R2>
|
|
2405
|
+
readonly onSuccess: (a: A) => Micro<A3, E3, R3>
|
|
2406
|
+
}
|
|
2407
|
+
): <R>(self: Micro<A, E, R>) => Micro<A2 | A3, E2 | E3, R2 | R3 | R>
|
|
2408
|
+
<A, E, R, A2, E2, R2, A3, E3, R3>(
|
|
2409
|
+
self: Micro<A, E, R>,
|
|
2410
|
+
options: {
|
|
2411
|
+
readonly onFailure: (failure: Failure<E>) => Micro<A2, E2, R2>
|
|
2412
|
+
readonly onSuccess: (a: A) => Micro<A3, E3, R3>
|
|
2413
|
+
}
|
|
2414
|
+
): Micro<A2 | A3, E2 | E3, R2 | R3 | R>
|
|
2415
|
+
} = dual(
|
|
2416
|
+
2,
|
|
2417
|
+
<A, E, R, A2, E2, R2, A3, E3, R3>(
|
|
2418
|
+
self: Micro<A, E, R>,
|
|
2419
|
+
options: {
|
|
2420
|
+
readonly onFailure: (failure: Failure<E>) => Micro<A2, E2, R2>
|
|
2421
|
+
readonly onSuccess: (a: A) => Micro<A3, E3, R3>
|
|
2422
|
+
}
|
|
2423
|
+
): Micro<A2 | A3, E2 | E3, R2 | R3 | R> =>
|
|
2424
|
+
make(function(env, onResult) {
|
|
2425
|
+
self[runSymbol](env, function(result) {
|
|
2426
|
+
try {
|
|
2427
|
+
const next = result._tag === "Left" ? options.onFailure(result.left) : options.onSuccess(result.right)
|
|
2428
|
+
next[runSymbol](env, onResult)
|
|
2429
|
+
} catch (err) {
|
|
2430
|
+
onResult(ResultFailUnexpected(err))
|
|
2431
|
+
}
|
|
2432
|
+
})
|
|
2433
|
+
})
|
|
2434
|
+
)
|
|
2435
|
+
|
|
2436
|
+
/**
|
|
2437
|
+
* @since 3.4.0
|
|
2438
|
+
* @experimental
|
|
2439
|
+
* @category pattern matching
|
|
2440
|
+
*/
|
|
2441
|
+
export const matchFailure: {
|
|
2442
|
+
<E, A2, A, A3>(
|
|
2443
|
+
options: {
|
|
2444
|
+
readonly onFailure: (failure: Failure<E>) => A2
|
|
2445
|
+
readonly onSuccess: (a: A) => A3
|
|
2446
|
+
}
|
|
2447
|
+
): <R>(self: Micro<A, E, R>) => Micro<A2 | A3, never, R>
|
|
2448
|
+
<A, E, R, A2, A3>(
|
|
2449
|
+
self: Micro<A, E, R>,
|
|
2450
|
+
options: {
|
|
2451
|
+
readonly onFailure: (failure: Failure<E>) => A2
|
|
2452
|
+
readonly onSuccess: (a: A) => A3
|
|
2453
|
+
}
|
|
2454
|
+
): Micro<A2 | A3, never, R>
|
|
2455
|
+
} = dual(
|
|
2456
|
+
2,
|
|
2457
|
+
<A, E, R, A2, A3>(
|
|
2458
|
+
self: Micro<A, E, R>,
|
|
2459
|
+
options: {
|
|
2460
|
+
readonly onFailure: (failure: Failure<E>) => A2
|
|
2461
|
+
readonly onSuccess: (a: A) => A3
|
|
2462
|
+
}
|
|
2463
|
+
): Micro<A2 | A3, never, R> =>
|
|
2464
|
+
matchFailureMicro(self, {
|
|
2465
|
+
onFailure: (failure) => sync(() => options.onFailure(failure)),
|
|
2466
|
+
onSuccess: (value) => sync(() => options.onSuccess(value))
|
|
2467
|
+
})
|
|
2468
|
+
)
|
|
2469
|
+
|
|
2470
|
+
/**
|
|
2471
|
+
* @since 3.4.0
|
|
2472
|
+
* @experimental
|
|
2473
|
+
* @category pattern matching
|
|
2474
|
+
*/
|
|
2475
|
+
export const matchMicro: {
|
|
2476
|
+
<E, A2, E2, R2, A, A3, E3, R3>(
|
|
2477
|
+
options: {
|
|
2478
|
+
readonly onFailure: (e: E) => Micro<A2, E2, R2>
|
|
2479
|
+
readonly onSuccess: (a: A) => Micro<A3, E3, R3>
|
|
2480
|
+
}
|
|
2481
|
+
): <R>(self: Micro<A, E, R>) => Micro<A2 | A3, E2 | E3, R2 | R3 | R>
|
|
2482
|
+
<A, E, R, A2, E2, R2, A3, E3, R3>(
|
|
2483
|
+
self: Micro<A, E, R>,
|
|
2484
|
+
options: {
|
|
2485
|
+
readonly onFailure: (e: E) => Micro<A2, E2, R2>
|
|
2486
|
+
readonly onSuccess: (a: A) => Micro<A3, E3, R3>
|
|
2487
|
+
}
|
|
2488
|
+
): Micro<A2 | A3, E2 | E3, R2 | R3 | R>
|
|
2489
|
+
} = dual(
|
|
2490
|
+
2,
|
|
2491
|
+
<A, E, R, A2, E2, R2, A3, E3, R3>(
|
|
2492
|
+
self: Micro<A, E, R>,
|
|
2493
|
+
options: {
|
|
2494
|
+
readonly onFailure: (e: E) => Micro<A2, E2, R2>
|
|
2495
|
+
readonly onSuccess: (a: A) => Micro<A3, E3, R3>
|
|
2496
|
+
}
|
|
2497
|
+
): Micro<A2 | A3, E2 | E3, R2 | R3 | R> =>
|
|
2498
|
+
matchFailureMicro(self, {
|
|
2499
|
+
onFailure: (failure) => failure._tag === "Expected" ? options.onFailure(failure.error) : failWith(failure),
|
|
2500
|
+
onSuccess: options.onSuccess
|
|
2501
|
+
})
|
|
2502
|
+
)
|
|
2503
|
+
|
|
2504
|
+
/**
|
|
2505
|
+
* @since 3.4.0
|
|
2506
|
+
* @experimental
|
|
2507
|
+
* @category pattern matching
|
|
2508
|
+
*/
|
|
2509
|
+
export const match: {
|
|
2510
|
+
<E, A2, A, A3>(
|
|
2511
|
+
options: {
|
|
2512
|
+
readonly onFailure: (error: E) => A2
|
|
2513
|
+
readonly onSuccess: (value: A) => A3
|
|
2514
|
+
}
|
|
2515
|
+
): <R>(self: Micro<A, E, R>) => Micro<A2 | A3, never, R>
|
|
2516
|
+
<A, E, R, A2, A3>(
|
|
2517
|
+
self: Micro<A, E, R>,
|
|
2518
|
+
options: {
|
|
2519
|
+
readonly onFailure: (error: E) => A2
|
|
2520
|
+
readonly onSuccess: (value: A) => A3
|
|
2521
|
+
}
|
|
2522
|
+
): Micro<A2 | A3, never, R>
|
|
2523
|
+
} = dual(
|
|
2524
|
+
2,
|
|
2525
|
+
<A, E, R, A2, A3>(
|
|
2526
|
+
self: Micro<A, E, R>,
|
|
2527
|
+
options: {
|
|
2528
|
+
readonly onFailure: (error: E) => A2
|
|
2529
|
+
readonly onSuccess: (value: A) => A3
|
|
2530
|
+
}
|
|
2531
|
+
): Micro<A2 | A3, never, R> =>
|
|
2532
|
+
matchMicro(self, {
|
|
2533
|
+
onFailure: (error) => sync(() => options.onFailure(error)),
|
|
2534
|
+
onSuccess: (value) => sync(() => options.onSuccess(value))
|
|
2535
|
+
})
|
|
2536
|
+
)
|
|
2537
|
+
|
|
2538
|
+
// ----------------------------------------------------------------------------
|
|
2539
|
+
// delays & timeouts
|
|
2540
|
+
// ----------------------------------------------------------------------------
|
|
2541
|
+
|
|
2542
|
+
/**
|
|
2543
|
+
* Create a `Micro` effect that will sleep for the specified duration.
|
|
2544
|
+
*
|
|
2545
|
+
* @since 3.4.0
|
|
2546
|
+
* @experimental
|
|
2547
|
+
* @category delays & timeouts
|
|
2548
|
+
*/
|
|
2549
|
+
export const sleep = (millis: number): Micro<void> =>
|
|
2550
|
+
async(function(resume) {
|
|
2551
|
+
const timeout = setTimeout(function() {
|
|
2552
|
+
resume(void_)
|
|
2553
|
+
}, millis)
|
|
2554
|
+
return sync(() => {
|
|
2555
|
+
return clearTimeout(timeout)
|
|
2556
|
+
})
|
|
2557
|
+
})
|
|
2558
|
+
|
|
2559
|
+
/**
|
|
2560
|
+
* Returns an effect that will delay the execution of this effect by the
|
|
2561
|
+
* specified duration.
|
|
2562
|
+
*
|
|
2563
|
+
* @since 3.4.0
|
|
2564
|
+
* @experimental
|
|
2565
|
+
* @category delays & timeouts
|
|
2566
|
+
*/
|
|
2567
|
+
export const delay: {
|
|
2568
|
+
(millis: number): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, R>
|
|
2569
|
+
<A, E, R>(self: Micro<A, E, R>, millis: number): Micro<A, E, R>
|
|
2570
|
+
} = dual(
|
|
2571
|
+
2,
|
|
2572
|
+
<A, E, R>(self: Micro<A, E, R>, millis: number): Micro<A, E, R> => andThen(sleep(millis), self)
|
|
2573
|
+
)
|
|
2574
|
+
|
|
2575
|
+
/**
|
|
2576
|
+
* Returns an effect that will timeout this effect, that will execute the
|
|
2577
|
+
* fallback effect if the timeout elapses before the effect has produced a value.
|
|
2578
|
+
*
|
|
2579
|
+
* If the timeout elapses, the running effect will be safely interrupted.
|
|
2580
|
+
*
|
|
2581
|
+
* @since 3.4.0
|
|
2582
|
+
* @experimental
|
|
2583
|
+
* @category delays & timeouts
|
|
2584
|
+
*/
|
|
2585
|
+
export const timeoutOrElse: {
|
|
2586
|
+
<A2, E2, R2>(options: {
|
|
2587
|
+
readonly duration: number
|
|
2588
|
+
readonly onTimeout: LazyArg<Micro<A2, E2, R2>>
|
|
2589
|
+
}): <A, E, R>(self: Micro<A, E, R>) => Micro<A | A2, E | E2, R | R2>
|
|
2590
|
+
<A, E, R, A2, E2, R2>(self: Micro<A, E, R>, options: {
|
|
2591
|
+
readonly duration: number
|
|
2592
|
+
readonly onTimeout: LazyArg<Micro<A2, E2, R2>>
|
|
2593
|
+
}): Micro<A | A2, E | E2, R | R2>
|
|
2594
|
+
} = dual(
|
|
2595
|
+
2,
|
|
2596
|
+
<A, E, R, A2, E2, R2>(self: Micro<A, E, R>, options: {
|
|
2597
|
+
readonly duration: number
|
|
2598
|
+
readonly onTimeout: LazyArg<Micro<A2, E2, R2>>
|
|
2599
|
+
}): Micro<A | A2, E | E2, R | R2> =>
|
|
2600
|
+
raceFirst(self, andThen(interruptible(sleep(options.duration)), options.onTimeout))
|
|
2601
|
+
)
|
|
2602
|
+
|
|
2603
|
+
/**
|
|
2604
|
+
* Returns an effect that will timeout this effect, succeeding with a `None`
|
|
2605
|
+
* if the timeout elapses before the effect has produced a value; and `Some` of
|
|
2606
|
+
* the produced value otherwise.
|
|
2607
|
+
*
|
|
2608
|
+
* If the timeout elapses, the running effect will be safely interrupted.
|
|
2609
|
+
*
|
|
2610
|
+
* @since 3.4.0
|
|
2611
|
+
* @experimental
|
|
2612
|
+
* @category delays & timeouts
|
|
2613
|
+
*/
|
|
2614
|
+
export const timeout: {
|
|
2615
|
+
(millis: number): <A, E, R>(self: Micro<A, E, R>) => Micro<Option.Option<A>, E, R>
|
|
2616
|
+
<A, E, R>(self: Micro<A, E, R>, millis: number): Micro<Option.Option<A>, E, R>
|
|
2617
|
+
} = dual(
|
|
2618
|
+
2,
|
|
2619
|
+
<A, E, R>(self: Micro<A, E, R>, millis: number): Micro<Option.Option<A>, E, R> =>
|
|
2620
|
+
raceFirst(
|
|
2621
|
+
asSome(self),
|
|
2622
|
+
as(interruptible(sleep(millis)), Option.none())
|
|
2623
|
+
)
|
|
2624
|
+
)
|
|
2625
|
+
|
|
2626
|
+
// ----------------------------------------------------------------------------
|
|
2627
|
+
// resources & finalization
|
|
2628
|
+
// ----------------------------------------------------------------------------
|
|
2629
|
+
|
|
2630
|
+
/**
|
|
2631
|
+
* @since 3.4.0
|
|
2632
|
+
* @experimental
|
|
2633
|
+
* @category resources & finalization
|
|
2634
|
+
*/
|
|
2635
|
+
export const MicroScopeTypeId: unique symbol = Symbol.for("effect/Micro/MicroScope")
|
|
2636
|
+
|
|
2637
|
+
/**
|
|
2638
|
+
* @since 3.4.0
|
|
2639
|
+
* @experimental
|
|
2640
|
+
* @category resources & finalization
|
|
2641
|
+
*/
|
|
2642
|
+
export type MicroScopeTypeId = typeof MicroScopeTypeId
|
|
2643
|
+
|
|
2644
|
+
/**
|
|
2645
|
+
* @since 3.4.0
|
|
2646
|
+
* @experimental
|
|
2647
|
+
* @category resources & finalization
|
|
2648
|
+
*/
|
|
2649
|
+
export interface MicroScope {
|
|
2650
|
+
readonly [MicroScopeTypeId]: MicroScopeTypeId
|
|
2651
|
+
readonly addFinalizer: (finalizer: (result: Result<unknown, unknown>) => Micro<void>) => Micro<void>
|
|
2652
|
+
readonly fork: Micro<MicroScope.Closeable>
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2655
|
+
/**
|
|
2656
|
+
* @since 3.4.0
|
|
2657
|
+
* @experimental
|
|
2658
|
+
* @category resources & finalization
|
|
2659
|
+
*/
|
|
2660
|
+
export declare namespace MicroScope {
|
|
2661
|
+
/**
|
|
2662
|
+
* @since 3.4.0
|
|
2663
|
+
* @experimental
|
|
2664
|
+
* @category resources & finalization
|
|
2665
|
+
*/
|
|
2666
|
+
export interface Closeable extends MicroScope {
|
|
2667
|
+
readonly close: (result: Result<any, any>) => Micro<void>
|
|
2668
|
+
}
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
/**
|
|
2672
|
+
* @since 3.4.0
|
|
2673
|
+
* @experimental
|
|
2674
|
+
* @category resources & finalization
|
|
2675
|
+
*/
|
|
2676
|
+
export const MicroScope: Context.Tag<MicroScope, MicroScope> = Context.GenericTag<MicroScope>("effect/Micro/MicroScope")
|
|
2677
|
+
|
|
2678
|
+
class ScopeImpl implements MicroScope.Closeable {
|
|
2679
|
+
readonly [MicroScopeTypeId]: MicroScopeTypeId
|
|
2680
|
+
state: {
|
|
2681
|
+
readonly _tag: "Open"
|
|
2682
|
+
readonly finalizers: Set<(result: Result<any, any>) => Micro<void>>
|
|
2683
|
+
} | {
|
|
2684
|
+
readonly _tag: "Closed"
|
|
2685
|
+
readonly result: Result<any, any>
|
|
2686
|
+
} = { _tag: "Open", finalizers: new Set() }
|
|
2687
|
+
|
|
2688
|
+
constructor() {
|
|
2689
|
+
this[MicroScopeTypeId] = MicroScopeTypeId
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
unsafeAddFinalizer(finalizer: (result: Result<any, any>) => Micro<void>): void {
|
|
2693
|
+
if (this.state._tag === "Open") {
|
|
2694
|
+
this.state.finalizers.add(finalizer)
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
addFinalizer(finalizer: (result: Result<any, any>) => Micro<void>): Micro<void> {
|
|
2698
|
+
return suspend(() => {
|
|
2699
|
+
if (this.state._tag === "Open") {
|
|
2700
|
+
this.state.finalizers.add(finalizer)
|
|
2701
|
+
return void_
|
|
2702
|
+
}
|
|
2703
|
+
return finalizer(this.state.result)
|
|
2704
|
+
})
|
|
2705
|
+
}
|
|
2706
|
+
unsafeRemoveFinalizer(finalizer: (result: Result<any, any>) => Micro<void>): void {
|
|
2707
|
+
if (this.state._tag === "Open") {
|
|
2708
|
+
this.state.finalizers.delete(finalizer)
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
close(result: Result<any, any>): Micro<void> {
|
|
2712
|
+
return suspend(() => {
|
|
2713
|
+
if (this.state._tag === "Open") {
|
|
2714
|
+
const finalizers = Array.from(this.state.finalizers).reverse()
|
|
2715
|
+
this.state = { _tag: "Closed", result }
|
|
2716
|
+
return flatMap(
|
|
2717
|
+
forEach(finalizers, (finalizer) => asResult(finalizer(result))),
|
|
2718
|
+
(results) => asVoid(fromResult(Either.all(results)))
|
|
2719
|
+
)
|
|
2720
|
+
}
|
|
2721
|
+
return void_
|
|
2722
|
+
})
|
|
2723
|
+
}
|
|
2724
|
+
get fork() {
|
|
2725
|
+
return sync(() => {
|
|
2726
|
+
const newScope = new ScopeImpl()
|
|
2727
|
+
if (this.state._tag === "Closed") {
|
|
2728
|
+
newScope.state = this.state
|
|
2729
|
+
return newScope
|
|
2730
|
+
}
|
|
2731
|
+
function fin(result: Result<any, any>) {
|
|
2732
|
+
return newScope.close(result)
|
|
2733
|
+
}
|
|
2734
|
+
this.state.finalizers.add(fin)
|
|
2735
|
+
newScope.unsafeAddFinalizer((_) => sync(() => this.unsafeRemoveFinalizer(fin)))
|
|
2736
|
+
return newScope
|
|
2737
|
+
})
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
/**
|
|
2742
|
+
* @since 3.4.0
|
|
2743
|
+
* @experimental
|
|
2744
|
+
* @category resources & finalization
|
|
2745
|
+
*/
|
|
2746
|
+
export const scopeMake: Micro<MicroScope.Closeable> = sync(() => new ScopeImpl())
|
|
2747
|
+
|
|
2748
|
+
/**
|
|
2749
|
+
* @since 3.4.0
|
|
2750
|
+
* @experimental
|
|
2751
|
+
* @category resources & finalization
|
|
2752
|
+
*/
|
|
2753
|
+
export const scopeUnsafeMake = (): MicroScope.Closeable => new ScopeImpl()
|
|
2754
|
+
|
|
2755
|
+
/**
|
|
2756
|
+
* Access the current `MicroScope`.
|
|
2757
|
+
*
|
|
2758
|
+
* @since 3.4.0
|
|
2759
|
+
* @experimental
|
|
2760
|
+
* @category resources & finalization
|
|
2761
|
+
*/
|
|
2762
|
+
export const scope: Micro<MicroScope, never, MicroScope> = service(MicroScope)
|
|
2763
|
+
|
|
2764
|
+
/**
|
|
2765
|
+
* Provide a `MicroScope` to an effect.
|
|
2766
|
+
*
|
|
2767
|
+
* @since 3.4.0
|
|
2768
|
+
* @experimental
|
|
2769
|
+
* @category resources & finalization
|
|
2770
|
+
*/
|
|
2771
|
+
export const provideScope: {
|
|
2772
|
+
(scope: MicroScope): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E, Exclude<R, MicroScope>>
|
|
2773
|
+
<A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<A, E, Exclude<R, MicroScope>>
|
|
2774
|
+
} = dual(
|
|
2775
|
+
2,
|
|
2776
|
+
<A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<A, E, Exclude<R, MicroScope>> =>
|
|
2777
|
+
provideService(self, MicroScope, scope)
|
|
2778
|
+
)
|
|
2779
|
+
|
|
2780
|
+
/**
|
|
2781
|
+
* Provide a `MicroScope` to the given effect, closing it after the effect has
|
|
2782
|
+
* finished executing.
|
|
2783
|
+
*
|
|
2784
|
+
* @since 3.4.0
|
|
2785
|
+
* @experimental
|
|
2786
|
+
* @category resources & finalization
|
|
2787
|
+
*/
|
|
2788
|
+
export const scoped = <A, E, R>(self: Micro<A, E, R>): Micro<A, E, Exclude<R, MicroScope>> =>
|
|
2789
|
+
suspend(function() {
|
|
2790
|
+
const scope = new ScopeImpl()
|
|
2791
|
+
return onResult(provideService(self, MicroScope, scope), (result) => scope.close(result))
|
|
2792
|
+
})
|
|
2793
|
+
|
|
2794
|
+
/**
|
|
2795
|
+
* Create a resource with a cleanup `Micro` effect, ensuring the cleanup is
|
|
2796
|
+
* executed when the `MicroScope` is closed.
|
|
2797
|
+
*
|
|
2798
|
+
* @since 3.4.0
|
|
2799
|
+
* @experimental
|
|
2800
|
+
* @category resources & finalization
|
|
2801
|
+
*/
|
|
2802
|
+
export const acquireRelease = <A, E, R>(
|
|
2803
|
+
acquire: Micro<A, E, R>,
|
|
2804
|
+
release: (a: A, result: Result<unknown, unknown>) => Micro<void>
|
|
2805
|
+
): Micro<A, E, R | MicroScope> =>
|
|
2806
|
+
uninterruptible(flatMap(
|
|
2807
|
+
scope,
|
|
2808
|
+
(scope) => tap(acquire, (a) => scope.addFinalizer((result) => release(a, result)))
|
|
2809
|
+
))
|
|
2810
|
+
|
|
2811
|
+
/**
|
|
2812
|
+
* Add a finalizer to the current `MicroScope`.
|
|
2813
|
+
*
|
|
2814
|
+
* @since 3.4.0
|
|
2815
|
+
* @experimental
|
|
2816
|
+
* @category resources & finalization
|
|
2817
|
+
*/
|
|
2818
|
+
export const addFinalizer = (
|
|
2819
|
+
finalizer: (result: Result<unknown, unknown>) => Micro<void>
|
|
2820
|
+
): Micro<void, never, MicroScope> => flatMap(scope, (scope) => scope.addFinalizer(finalizer))
|
|
2821
|
+
|
|
2822
|
+
/**
|
|
2823
|
+
* When the `Micro` effect is completed, run the given finalizer effect with the
|
|
2824
|
+
* `Result` of the executed effect.
|
|
2825
|
+
*
|
|
2826
|
+
* @since 3.4.0
|
|
2827
|
+
* @experimental
|
|
2828
|
+
* @category resources & finalization
|
|
2829
|
+
*/
|
|
2830
|
+
export const onResult: {
|
|
2831
|
+
<A, E, XE, XR>(
|
|
2832
|
+
f: (result: Result<A, E>) => Micro<void, XE, XR>
|
|
2833
|
+
): <R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
|
|
2834
|
+
<A, E, R, XE, XR>(self: Micro<A, E, R>, f: (result: Result<A, E>) => Micro<void, XE, XR>): Micro<A, E | XE, R | XR>
|
|
2835
|
+
} = dual(
|
|
2836
|
+
2,
|
|
2837
|
+
<A, E, R, XE, XR>(self: Micro<A, E, R>, f: (result: Result<A, E>) => Micro<void, XE, XR>): Micro<A, E | XE, R | XR> =>
|
|
2838
|
+
onResultIf(self, constTrue, f)
|
|
2839
|
+
)
|
|
2840
|
+
|
|
2841
|
+
/**
|
|
2842
|
+
* When the `Micro` effect is completed, run the given finalizer effect if it
|
|
2843
|
+
* matches the specified predicate.
|
|
2844
|
+
*
|
|
2845
|
+
* @since 3.4.0
|
|
2846
|
+
* @experimental
|
|
2847
|
+
* @category resources & finalization
|
|
2848
|
+
*/
|
|
2849
|
+
export const onResultIf: {
|
|
2850
|
+
<A, E, XE, XR, B extends Result<A, E>>(
|
|
2851
|
+
refinement: Refinement<Result<A, E>, B>,
|
|
2852
|
+
f: (result: B) => Micro<void, XE, XR>
|
|
2853
|
+
): <R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
|
|
2854
|
+
<A, E, XE, XR>(
|
|
2855
|
+
predicate: Predicate<Result<NoInfer<A>, NoInfer<E>>>,
|
|
2856
|
+
f: (result: Result<NoInfer<A>, NoInfer<E>>) => Micro<void, XE, XR>
|
|
2857
|
+
): <R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
|
|
2858
|
+
<A, E, R, XE, XR, B extends Result<A, E>>(
|
|
2859
|
+
self: Micro<A, E, R>,
|
|
2860
|
+
refinement: Refinement<Result<A, E>, B>,
|
|
2861
|
+
f: (result: B) => Micro<void, XE, XR>
|
|
2862
|
+
): Micro<A, E | XE, R | XR>
|
|
2863
|
+
<A, E, R, XE, XR>(
|
|
2864
|
+
self: Micro<A, E, R>,
|
|
2865
|
+
predicate: Predicate<Result<NoInfer<A>, NoInfer<E>>>,
|
|
2866
|
+
f: (result: Result<NoInfer<A>, NoInfer<E>>) => Micro<void, XE, XR>
|
|
2867
|
+
): Micro<A, E | XE, R | XR>
|
|
2868
|
+
} = dual(
|
|
2869
|
+
3,
|
|
2870
|
+
<A, E, R, XE, XR, B extends Result<A, E>>(
|
|
2871
|
+
self: Micro<A, E, R>,
|
|
2872
|
+
refinement: Refinement<Result<A, E>, B>,
|
|
2873
|
+
f: (result: B) => Micro<void, XE, XR>
|
|
2874
|
+
): Micro<A, E | XE, R | XR> =>
|
|
2875
|
+
uninterruptibleMask((restore) =>
|
|
2876
|
+
make(function(env, onResult) {
|
|
2877
|
+
restore(self)[runSymbol](env, function(result) {
|
|
2878
|
+
if (!refinement(result)) {
|
|
2879
|
+
return onResult(result)
|
|
2880
|
+
}
|
|
2881
|
+
f(result)[runSymbol](env, function(finalizerResult) {
|
|
2882
|
+
if (finalizerResult._tag === "Left") {
|
|
2883
|
+
return onResult(finalizerResult as any)
|
|
2884
|
+
}
|
|
2885
|
+
onResult(result)
|
|
2886
|
+
})
|
|
2887
|
+
})
|
|
2888
|
+
})
|
|
2889
|
+
)
|
|
2890
|
+
)
|
|
2891
|
+
|
|
2892
|
+
/**
|
|
2893
|
+
* Regardless of the result of the this `Micro` effect, run the finalizer effect.
|
|
2894
|
+
*
|
|
2895
|
+
* @since 3.4.0
|
|
2896
|
+
* @experimental
|
|
2897
|
+
* @category resources & finalization
|
|
2898
|
+
*/
|
|
2899
|
+
export const ensuring: {
|
|
2900
|
+
<XE, XR>(
|
|
2901
|
+
finalizer: Micro<void, XE, XR>
|
|
2902
|
+
): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
|
|
2903
|
+
<A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR>
|
|
2904
|
+
} = dual(
|
|
2905
|
+
2,
|
|
2906
|
+
<A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR> =>
|
|
2907
|
+
onResult(self, (_) => finalizer)
|
|
2908
|
+
)
|
|
2909
|
+
|
|
2910
|
+
/**
|
|
2911
|
+
* When the `Micro` effect fails, run the given finalizer effect with the
|
|
2912
|
+
* `Failure` of the executed effect.
|
|
2913
|
+
*
|
|
2914
|
+
* @since 3.4.0
|
|
2915
|
+
* @experimental
|
|
2916
|
+
* @category resources & finalization
|
|
2917
|
+
*/
|
|
2918
|
+
export const onFailure: {
|
|
2919
|
+
<A, E, XE, XR>(
|
|
2920
|
+
f: (failure: Failure<NoInfer<E>>) => Micro<void, XE, XR>
|
|
2921
|
+
): <R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
|
|
2922
|
+
<A, E, R, XE, XR>(
|
|
2923
|
+
self: Micro<A, E, R>,
|
|
2924
|
+
f: (failure: Failure<NoInfer<E>>) => Micro<void, XE, XR>
|
|
2925
|
+
): Micro<A, E | XE, R | XR>
|
|
2926
|
+
} = dual(
|
|
2927
|
+
2,
|
|
2928
|
+
<A, E, R, XE, XR>(
|
|
2929
|
+
self: Micro<A, E, R>,
|
|
2930
|
+
f: (failure: Failure<NoInfer<E>>) => Micro<void, XE, XR>
|
|
2931
|
+
): Micro<A, E | XE, R | XR> => onResultIf(self, resultIsFailure, (result) => f(result.left))
|
|
2932
|
+
)
|
|
2933
|
+
|
|
2934
|
+
/**
|
|
2935
|
+
* If this `Micro` effect is aborted, run the finalizer effect.
|
|
2936
|
+
*
|
|
2937
|
+
* @since 3.4.0
|
|
2938
|
+
* @experimental
|
|
2939
|
+
* @category resources & finalization
|
|
2940
|
+
*/
|
|
2941
|
+
export const onAbort: {
|
|
2942
|
+
<XE, XR>(
|
|
2943
|
+
finalizer: Micro<void, XE, XR>
|
|
2944
|
+
): <A, E, R>(self: Micro<A, E, R>) => Micro<A, E | XE, R | XR>
|
|
2945
|
+
<A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR>
|
|
2946
|
+
} = dual(
|
|
2947
|
+
2,
|
|
2948
|
+
<A, E, R, XE, XR>(self: Micro<A, E, R>, finalizer: Micro<void, XE, XR>): Micro<A, E | XE, R | XR> =>
|
|
2949
|
+
onResultIf(self, resultIsAborted, (_) => finalizer)
|
|
2950
|
+
)
|
|
2951
|
+
|
|
2952
|
+
/**
|
|
2953
|
+
* Acquire a resource, use it, and then release the resource when the `use`
|
|
2954
|
+
* effect has completed.
|
|
2955
|
+
*
|
|
2956
|
+
* @since 3.4.0
|
|
2957
|
+
* @experimental
|
|
2958
|
+
* @category resources & finalization
|
|
2959
|
+
*/
|
|
2960
|
+
export const acquireUseRelease = <Resource, E, R, A, E2, R2, E3, R3>(
|
|
2961
|
+
acquire: Micro<Resource, E, R>,
|
|
2962
|
+
use: (a: Resource) => Micro<A, E2, R2>,
|
|
2963
|
+
release: (a: Resource, result: Result<A, E2>) => Micro<void, E3, R3>
|
|
2964
|
+
): Micro<A, E | E2 | E3, R | R2 | R3> =>
|
|
2965
|
+
uninterruptibleMask((restore) =>
|
|
2966
|
+
flatMap(
|
|
2967
|
+
acquire,
|
|
2968
|
+
(a) =>
|
|
2969
|
+
flatMap(
|
|
2970
|
+
asResult(restore(use(a))),
|
|
2971
|
+
(result) => andThen(release(a, result), fromResult(result))
|
|
2972
|
+
)
|
|
2973
|
+
)
|
|
2974
|
+
)
|
|
2975
|
+
|
|
2976
|
+
// ----------------------------------------------------------------------------
|
|
2977
|
+
// interruption
|
|
2978
|
+
// ----------------------------------------------------------------------------
|
|
2979
|
+
|
|
2980
|
+
/**
|
|
2981
|
+
* Abort the current `Micro` effect.
|
|
2982
|
+
*
|
|
2983
|
+
* @since 3.4.0
|
|
2984
|
+
* @experimental
|
|
2985
|
+
* @category interruption
|
|
2986
|
+
*/
|
|
2987
|
+
export const abort: Micro<never> = make(function(env, onResult) {
|
|
2988
|
+
const controller = envGet(env, currentAbortController)
|
|
2989
|
+
controller.abort()
|
|
2990
|
+
onResult(ResultAborted)
|
|
2991
|
+
})
|
|
2992
|
+
|
|
2993
|
+
/**
|
|
2994
|
+
* Wrap the given `Micro` effect in an uninterruptible region, preventing the
|
|
2995
|
+
* effect from being aborted.
|
|
2996
|
+
*
|
|
2997
|
+
* @since 3.4.0
|
|
2998
|
+
* @experimental
|
|
2999
|
+
* @category interruption
|
|
3000
|
+
*/
|
|
3001
|
+
export const uninterruptible = <A, E, R>(self: Micro<A, E, R>): Micro<A, E, R> =>
|
|
3002
|
+
unsafeMakeOptions(function(env, onResult) {
|
|
3003
|
+
const nextEnv = envMutate(env, function(env) {
|
|
3004
|
+
env[currentInterruptible.key] = false
|
|
3005
|
+
env[currentAbortSignal.key] = new AbortController().signal
|
|
3006
|
+
return env
|
|
3007
|
+
})
|
|
3008
|
+
self[runSymbol](nextEnv, onResult)
|
|
3009
|
+
}, false)
|
|
3010
|
+
|
|
3011
|
+
/**
|
|
3012
|
+
* Wrap the given `Micro` effect in an uninterruptible region, preventing the
|
|
3013
|
+
* effect from being aborted.
|
|
3014
|
+
*
|
|
3015
|
+
* You can use the `restore` function to restore a `Micro` effect to the
|
|
3016
|
+
* interruptibility state before the `uninterruptibleMask` was applied.
|
|
3017
|
+
*
|
|
3018
|
+
* @since 3.4.0
|
|
3019
|
+
* @experimental
|
|
3020
|
+
* @category interruption
|
|
3021
|
+
* @example
|
|
3022
|
+
* import * as Micro from "effect/Micro"
|
|
3023
|
+
*
|
|
3024
|
+
* Micro.uninterruptibleMask((restore) =>
|
|
3025
|
+
* Micro.sleep(1000).pipe( // uninterruptible
|
|
3026
|
+
* Micro.andThen(restore(Micro.sleep(1000))) // interruptible
|
|
3027
|
+
* )
|
|
3028
|
+
* )
|
|
3029
|
+
*/
|
|
3030
|
+
export const uninterruptibleMask = <A, E, R>(
|
|
3031
|
+
f: (restore: <A, E, R>(effect: Micro<A, E, R>) => Micro<A, E, R>) => Micro<A, E, R>
|
|
3032
|
+
): Micro<A, E, R> =>
|
|
3033
|
+
unsafeMakeOptions((env, onResult) => {
|
|
3034
|
+
const isInterruptible = envGet(env, currentInterruptible)
|
|
3035
|
+
const effect = isInterruptible ? f(interruptible) : f(identity)
|
|
3036
|
+
const nextEnv = isInterruptible ?
|
|
3037
|
+
envMutate(env, function(env) {
|
|
3038
|
+
env[currentInterruptible.key] = false
|
|
3039
|
+
env[currentAbortSignal.key] = new AbortController().signal
|
|
3040
|
+
return env
|
|
3041
|
+
}) :
|
|
3042
|
+
env
|
|
3043
|
+
effect[runSymbol](nextEnv, onResult)
|
|
3044
|
+
}, false)
|
|
3045
|
+
|
|
3046
|
+
/**
|
|
3047
|
+
* Wrap the given `Micro` effect in an interruptible region, allowing the effect
|
|
3048
|
+
* to be aborted.
|
|
3049
|
+
*
|
|
3050
|
+
* @since 3.4.0
|
|
3051
|
+
* @experimental
|
|
3052
|
+
* @category interruption
|
|
3053
|
+
*/
|
|
3054
|
+
export const interruptible = <A, E, R>(self: Micro<A, E, R>): Micro<A, E, R> =>
|
|
3055
|
+
make((env, onResult) => {
|
|
3056
|
+
const isInterruptible = envGet(env, currentInterruptible)
|
|
3057
|
+
let newEnv = env
|
|
3058
|
+
if (!isInterruptible) {
|
|
3059
|
+
const controller = envGet(env, currentAbortController)
|
|
3060
|
+
newEnv = envMutate(env, function(env) {
|
|
3061
|
+
env[currentInterruptible.key] = true
|
|
3062
|
+
env[currentAbortSignal.key] = controller.signal
|
|
3063
|
+
return env
|
|
3064
|
+
})
|
|
3065
|
+
}
|
|
3066
|
+
self[runSymbol](newEnv, onResult)
|
|
3067
|
+
})
|
|
3068
|
+
|
|
3069
|
+
// ========================================================================
|
|
3070
|
+
// collecting & elements
|
|
3071
|
+
// ========================================================================
|
|
3072
|
+
|
|
3073
|
+
/**
|
|
3074
|
+
* @since 3.4.0
|
|
3075
|
+
* @experimental
|
|
3076
|
+
*/
|
|
3077
|
+
export declare namespace All {
|
|
3078
|
+
/**
|
|
3079
|
+
* @since 3.4.0
|
|
3080
|
+
* @experimental
|
|
3081
|
+
*/
|
|
3082
|
+
export type MicroAny = Micro<any, any, any>
|
|
3083
|
+
|
|
3084
|
+
/**
|
|
3085
|
+
* @since 3.4.0
|
|
3086
|
+
* @experimental
|
|
3087
|
+
*/
|
|
3088
|
+
export type ReturnIterable<T extends Iterable<MicroAny>, Discard extends boolean> = [T] extends
|
|
3089
|
+
[Iterable<Micro<infer A, infer E, infer R>>] ? Micro<
|
|
3090
|
+
Discard extends true ? void : Array<A>,
|
|
3091
|
+
E,
|
|
3092
|
+
R
|
|
3093
|
+
>
|
|
3094
|
+
: never
|
|
3095
|
+
|
|
3096
|
+
/**
|
|
3097
|
+
* @since 3.4.0
|
|
3098
|
+
* @experimental
|
|
3099
|
+
*/
|
|
3100
|
+
export type ReturnTuple<T extends ReadonlyArray<unknown>, Discard extends boolean> = Micro<
|
|
3101
|
+
Discard extends true ? void
|
|
3102
|
+
: T[number] extends never ? []
|
|
3103
|
+
: { -readonly [K in keyof T]: T[K] extends Micro<infer _A, infer _E, infer _R> ? _A : never },
|
|
3104
|
+
T[number] extends never ? never
|
|
3105
|
+
: T[number] extends Micro<infer _A, infer _E, infer _R> ? _E
|
|
3106
|
+
: never,
|
|
3107
|
+
T[number] extends never ? never
|
|
3108
|
+
: T[number] extends Micro<infer _A, infer _E, infer _R> ? _R
|
|
3109
|
+
: never
|
|
3110
|
+
> extends infer X ? X : never
|
|
3111
|
+
|
|
3112
|
+
/**
|
|
3113
|
+
* @since 3.4.0
|
|
3114
|
+
* @experimental
|
|
3115
|
+
*/
|
|
3116
|
+
export type ReturnObject<T, Discard extends boolean> = [T] extends [{ [K: string]: MicroAny }] ? Micro<
|
|
3117
|
+
Discard extends true ? void :
|
|
3118
|
+
{ -readonly [K in keyof T]: [T[K]] extends [Micro<infer _A, infer _E, infer _R>] ? _A : never },
|
|
3119
|
+
keyof T extends never ? never
|
|
3120
|
+
: T[keyof T] extends Micro<infer _A, infer _E, infer _R> ? _E
|
|
3121
|
+
: never,
|
|
3122
|
+
keyof T extends never ? never
|
|
3123
|
+
: T[keyof T] extends Micro<infer _A, infer _E, infer _R> ? _R
|
|
3124
|
+
: never
|
|
3125
|
+
>
|
|
3126
|
+
: never
|
|
3127
|
+
|
|
3128
|
+
/**
|
|
3129
|
+
* @since 3.4.0
|
|
3130
|
+
* @experimental
|
|
3131
|
+
*/
|
|
3132
|
+
export type IsDiscard<A> = [Extract<A, { readonly discard: true }>] extends [never] ? false : true
|
|
3133
|
+
|
|
3134
|
+
/**
|
|
3135
|
+
* @since 3.4.0
|
|
3136
|
+
* @experimental
|
|
3137
|
+
*/
|
|
3138
|
+
export type Return<
|
|
3139
|
+
Arg extends Iterable<MicroAny> | Record<string, MicroAny>,
|
|
3140
|
+
O extends {
|
|
3141
|
+
readonly concurrency?: Concurrency | undefined
|
|
3142
|
+
readonly discard?: boolean | undefined
|
|
3143
|
+
}
|
|
3144
|
+
> = [Arg] extends [ReadonlyArray<MicroAny>] ? ReturnTuple<Arg, IsDiscard<O>>
|
|
3145
|
+
: [Arg] extends [Iterable<MicroAny>] ? ReturnIterable<Arg, IsDiscard<O>>
|
|
3146
|
+
: [Arg] extends [Record<string, MicroAny>] ? ReturnObject<Arg, IsDiscard<O>>
|
|
3147
|
+
: never
|
|
3148
|
+
}
|
|
3149
|
+
|
|
3150
|
+
/**
|
|
3151
|
+
* Runs all the provided effects in sequence respecting the structure provided in input.
|
|
3152
|
+
*
|
|
3153
|
+
* Supports multiple arguments, a single argument tuple / array or record / struct.
|
|
3154
|
+
*
|
|
3155
|
+
* @since 3.4.0
|
|
3156
|
+
* @experimental
|
|
3157
|
+
* @category collecting & elements
|
|
3158
|
+
*/
|
|
3159
|
+
export const all = <
|
|
3160
|
+
const Arg extends Iterable<Micro<any, any, any>> | Record<string, Micro<any, any, any>>,
|
|
3161
|
+
O extends {
|
|
3162
|
+
readonly concurrency?: Concurrency | undefined
|
|
3163
|
+
readonly discard?: boolean | undefined
|
|
3164
|
+
}
|
|
3165
|
+
>(arg: Arg, options?: O): All.Return<Arg, O> => {
|
|
3166
|
+
if (Array.isArray(arg) || isIterable(arg)) {
|
|
3167
|
+
return (forEach as any)(arg, identity, options)
|
|
3168
|
+
} else if (options?.discard) {
|
|
3169
|
+
return (forEach as any)(Object.values(arg), identity, options)
|
|
3170
|
+
}
|
|
3171
|
+
return suspend(() => {
|
|
3172
|
+
const out: Record<string, unknown> = {}
|
|
3173
|
+
return as(
|
|
3174
|
+
forEach(Object.entries(arg), ([key, effect]) =>
|
|
3175
|
+
map(effect, (value) => {
|
|
3176
|
+
out[key] = value
|
|
3177
|
+
}), {
|
|
3178
|
+
discard: true,
|
|
3179
|
+
concurrency: options?.concurrency
|
|
3180
|
+
}),
|
|
3181
|
+
out
|
|
3182
|
+
)
|
|
3183
|
+
}) as any
|
|
3184
|
+
}
|
|
3185
|
+
|
|
3186
|
+
/**
|
|
3187
|
+
* For each element of the provided iterable, run the effect and collect the results.
|
|
3188
|
+
*
|
|
3189
|
+
* If the `discard` option is set to `true`, the results will be discarded and
|
|
3190
|
+
* the effect will return `void`.
|
|
3191
|
+
*
|
|
3192
|
+
* The `concurrency` option can be set to control how many effects are run in
|
|
3193
|
+
* parallel. By default, the effects are run sequentially.
|
|
3194
|
+
*
|
|
3195
|
+
* @since 3.4.0
|
|
3196
|
+
* @experimental
|
|
3197
|
+
* @category collecting & elements
|
|
3198
|
+
*/
|
|
3199
|
+
export const forEach: {
|
|
3200
|
+
<A, B, E, R>(iterable: Iterable<A>, f: (a: A, index: number) => Micro<B, E, R>, options?: {
|
|
3201
|
+
readonly concurrency?: Concurrency | undefined
|
|
3202
|
+
readonly discard?: false | undefined
|
|
3203
|
+
}): Micro<Array<B>, E, R>
|
|
3204
|
+
<A, B, E, R>(iterable: Iterable<A>, f: (a: A, index: number) => Micro<B, E, R>, options: {
|
|
3205
|
+
readonly concurrency?: Concurrency | undefined
|
|
3206
|
+
readonly discard: true
|
|
3207
|
+
}): Micro<void, E, R>
|
|
3208
|
+
} = <
|
|
3209
|
+
A,
|
|
3210
|
+
B,
|
|
3211
|
+
E,
|
|
3212
|
+
R
|
|
3213
|
+
>(iterable: Iterable<A>, f: (a: A, index: number) => Micro<B, E, R>, options?: {
|
|
3214
|
+
readonly concurrency?: Concurrency | undefined
|
|
3215
|
+
readonly discard?: boolean | undefined
|
|
3216
|
+
}): Micro<any, E, R> =>
|
|
3217
|
+
make(function(env, onResult) {
|
|
3218
|
+
const concurrencyOption = options?.concurrency === "inherit"
|
|
3219
|
+
? envGet(env, currentConcurrency)
|
|
3220
|
+
: options?.concurrency ?? 1
|
|
3221
|
+
const concurrency = concurrencyOption === "unbounded"
|
|
3222
|
+
? Number.POSITIVE_INFINITY
|
|
3223
|
+
: Math.max(1, concurrencyOption)
|
|
3224
|
+
|
|
3225
|
+
// abort
|
|
3226
|
+
const [envWithSignal, onAbort] = forkSignal(env)
|
|
3227
|
+
|
|
3228
|
+
// iterate
|
|
3229
|
+
let failure: Result<any, any> | undefined = undefined
|
|
3230
|
+
const items = Array.from(iterable)
|
|
3231
|
+
let length = items.length
|
|
3232
|
+
const out: Array<B> | undefined = options?.discard ? undefined : new Array(length)
|
|
3233
|
+
let index = 0
|
|
3234
|
+
let inProgress = 0
|
|
3235
|
+
let doneCount = 0
|
|
3236
|
+
let pumping = false
|
|
3237
|
+
function pump() {
|
|
3238
|
+
pumping = true
|
|
3239
|
+
while (inProgress < concurrency && index < length) {
|
|
3240
|
+
const currentIndex = index
|
|
3241
|
+
const item = items[currentIndex]
|
|
3242
|
+
index++
|
|
3243
|
+
inProgress++
|
|
3244
|
+
try {
|
|
3245
|
+
f(item, currentIndex)[runSymbol](envWithSignal, function(result) {
|
|
3246
|
+
if (result._tag === "Left") {
|
|
3247
|
+
if (failure === undefined) {
|
|
3248
|
+
failure = result
|
|
3249
|
+
length = index
|
|
3250
|
+
onAbort()
|
|
3251
|
+
}
|
|
3252
|
+
} else if (out !== undefined) {
|
|
3253
|
+
out[currentIndex] = result.right
|
|
3254
|
+
}
|
|
3255
|
+
doneCount++
|
|
3256
|
+
inProgress--
|
|
3257
|
+
if (doneCount === length) {
|
|
3258
|
+
onResult(failure ?? Either.right(out))
|
|
3259
|
+
} else if (!pumping && inProgress < concurrency) {
|
|
3260
|
+
pump()
|
|
3261
|
+
}
|
|
3262
|
+
})
|
|
3263
|
+
} catch (err) {
|
|
3264
|
+
failure = ResultFailUnexpected(err)
|
|
3265
|
+
length = index
|
|
3266
|
+
onAbort()
|
|
3267
|
+
}
|
|
3268
|
+
}
|
|
3269
|
+
pumping = false
|
|
3270
|
+
}
|
|
3271
|
+
pump()
|
|
3272
|
+
})
|
|
3273
|
+
|
|
3274
|
+
/**
|
|
3275
|
+
* Effectfully filter the elements of the provided iterable.
|
|
3276
|
+
*
|
|
3277
|
+
* Use the `concurrency` option to control how many elements are processed in parallel.
|
|
3278
|
+
*
|
|
3279
|
+
* @since 3.4.0
|
|
3280
|
+
* @experimental
|
|
3281
|
+
* @category collecting & elements
|
|
3282
|
+
*/
|
|
3283
|
+
export const filter = <A, E, R>(iterable: Iterable<A>, f: (a: NoInfer<A>) => Micro<boolean, E, R>, options?: {
|
|
3284
|
+
readonly concurrency?: Concurrency | undefined
|
|
3285
|
+
readonly negate?: boolean | undefined
|
|
3286
|
+
}): Micro<Array<A>, E, R> =>
|
|
3287
|
+
filterMap(iterable, (a) =>
|
|
3288
|
+
map(f(a), (pass) => {
|
|
3289
|
+
pass = options?.negate ? !pass : pass
|
|
3290
|
+
return pass ? Option.some(a) : Option.none()
|
|
3291
|
+
}))
|
|
3292
|
+
|
|
3293
|
+
/**
|
|
3294
|
+
* Effectfully filter the elements of the provided iterable.
|
|
3295
|
+
*
|
|
3296
|
+
* Use the `concurrency` option to control how many elements are processed in parallel.
|
|
3297
|
+
*
|
|
3298
|
+
* @since 3.4.0
|
|
3299
|
+
* @experimental
|
|
3300
|
+
* @category collecting & elements
|
|
3301
|
+
*/
|
|
3302
|
+
export const filterMap = <A, B, E, R>(
|
|
3303
|
+
iterable: Iterable<A>,
|
|
3304
|
+
f: (a: NoInfer<A>) => Micro<Option.Option<B>, E, R>,
|
|
3305
|
+
options?: {
|
|
3306
|
+
readonly concurrency?: Concurrency | undefined
|
|
3307
|
+
}
|
|
3308
|
+
): Micro<Array<B>, E, R> =>
|
|
3309
|
+
suspend(() => {
|
|
3310
|
+
const out: Array<B> = []
|
|
3311
|
+
return as(
|
|
3312
|
+
forEach(iterable, (a) =>
|
|
3313
|
+
map(f(a), (o) => {
|
|
3314
|
+
if (o._tag === "Some") {
|
|
3315
|
+
out.push(o.value)
|
|
3316
|
+
}
|
|
3317
|
+
}), {
|
|
3318
|
+
discard: true,
|
|
3319
|
+
concurrency: options?.concurrency
|
|
3320
|
+
}),
|
|
3321
|
+
out
|
|
3322
|
+
)
|
|
3323
|
+
})
|
|
3324
|
+
|
|
3325
|
+
// ----------------------------------------------------------------------------
|
|
3326
|
+
// do notation
|
|
3327
|
+
// ----------------------------------------------------------------------------
|
|
3328
|
+
|
|
3329
|
+
/**
|
|
3330
|
+
* Start a do notation block.
|
|
3331
|
+
*
|
|
3332
|
+
* @since 3.4.0
|
|
3333
|
+
* @experimental
|
|
3334
|
+
* @category do notation
|
|
3335
|
+
*/
|
|
3336
|
+
export const Do: Micro<{}> = succeed({})
|
|
3337
|
+
|
|
3338
|
+
/**
|
|
3339
|
+
* Bind the success value of this `Micro` effect to the provided name.
|
|
3340
|
+
*
|
|
3341
|
+
* @since 3.4.0
|
|
3342
|
+
* @experimental
|
|
3343
|
+
* @category do notation
|
|
3344
|
+
*/
|
|
3345
|
+
export const bindTo: {
|
|
3346
|
+
<N extends string>(name: N): <A, E, R>(self: Micro<A, E, R>) => Micro<{ [K in N]: A }, E, R>
|
|
3347
|
+
<A, E, R, N extends string>(self: Micro<A, E, R>, name: N): Micro<{ [K in N]: A }, E, R>
|
|
3348
|
+
} = dual(2, <A, E, R, N extends string>(self: Micro<A, E, R>, name: N): Micro<{ [K in N]: A }, E, R> =>
|
|
3349
|
+
map(
|
|
3350
|
+
self,
|
|
3351
|
+
(f) => ({ [name]: f } as any)
|
|
3352
|
+
))
|
|
3353
|
+
|
|
3354
|
+
/**
|
|
3355
|
+
* Bind the success value of this `Micro` effect to the provided name.
|
|
3356
|
+
*
|
|
3357
|
+
* @since 3.4.0
|
|
3358
|
+
* @experimental
|
|
3359
|
+
* @category do notation
|
|
3360
|
+
*/
|
|
3361
|
+
export const bind: {
|
|
3362
|
+
<N extends string, A extends Record<string, any>, B, E2, R2>(
|
|
3363
|
+
name: N,
|
|
3364
|
+
f: (a: A) => Micro<B, E2, R2>
|
|
3365
|
+
): <E, R>(self: Micro<A, E, R>) => Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E | E2, R | R2>
|
|
3366
|
+
<A extends Record<string, any>, E, R, B, E2, R2, N extends string>(
|
|
3367
|
+
self: Micro<A, E, R>,
|
|
3368
|
+
name: N,
|
|
3369
|
+
f: (a: A) => Micro<B, E2, R2>
|
|
3370
|
+
): Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E | E2, R | R2>
|
|
3371
|
+
} = dual(3, <A extends Record<string, any>, E, R, B, E2, R2, N extends string>(
|
|
3372
|
+
self: Micro<A, E, R>,
|
|
3373
|
+
name: N,
|
|
3374
|
+
f: (a: A) => Micro<B, E2, R2>
|
|
3375
|
+
): Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E | E2, R | R2> =>
|
|
3376
|
+
flatMap(
|
|
3377
|
+
self,
|
|
3378
|
+
(a) => map(f(a), (b) => ({ ...a, [name]: b } as any))
|
|
3379
|
+
))
|
|
3380
|
+
|
|
3381
|
+
const let_: {
|
|
3382
|
+
<N extends string, A extends Record<string, any>, B>(
|
|
3383
|
+
name: N,
|
|
3384
|
+
f: (a: A) => B
|
|
3385
|
+
): <E, R>(self: Micro<A, E, R>) => Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E, R>
|
|
3386
|
+
<A extends Record<string, any>, E, R, B, N extends string>(
|
|
3387
|
+
self: Micro<A, E, R>,
|
|
3388
|
+
name: N,
|
|
3389
|
+
f: (a: A) => B
|
|
3390
|
+
): Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E, R>
|
|
3391
|
+
} = dual(3, <A extends Record<string, any>, E, R, B, N extends string>(
|
|
3392
|
+
self: Micro<A, E, R>,
|
|
3393
|
+
name: N,
|
|
3394
|
+
f: (a: A) => B
|
|
3395
|
+
): Micro<Simplify<Omit<A, N> & { [K in N]: B }>, E, R> =>
|
|
3396
|
+
map(
|
|
3397
|
+
self,
|
|
3398
|
+
(a) => ({ ...a, [name]: f(a) } as any)
|
|
3399
|
+
))
|
|
3400
|
+
export {
|
|
3401
|
+
/**
|
|
3402
|
+
* Bind the result of a synchronous computation to the given name.
|
|
3403
|
+
*
|
|
3404
|
+
* @since 3.4.0
|
|
3405
|
+
* @experimental
|
|
3406
|
+
* @category do notation
|
|
3407
|
+
*/
|
|
3408
|
+
let_ as let
|
|
3409
|
+
}
|
|
3410
|
+
|
|
3411
|
+
// ----------------------------------------------------------------------------
|
|
3412
|
+
// handle & forking
|
|
3413
|
+
// ----------------------------------------------------------------------------
|
|
3414
|
+
|
|
3415
|
+
/**
|
|
3416
|
+
* @since 3.4.0
|
|
3417
|
+
* @experimental
|
|
3418
|
+
* @category handle & forking
|
|
3419
|
+
*/
|
|
3420
|
+
export const HandleTypeId: unique symbol = Symbol.for("effect/Micro/Handle")
|
|
3421
|
+
|
|
3422
|
+
/**
|
|
3423
|
+
* @since 3.4.0
|
|
3424
|
+
* @experimental
|
|
3425
|
+
* @category handle & forking
|
|
3426
|
+
*/
|
|
3427
|
+
export type HandleTypeId = typeof HandleTypeId
|
|
3428
|
+
|
|
3429
|
+
/**
|
|
3430
|
+
* @since 3.4.0
|
|
3431
|
+
* @experimental
|
|
3432
|
+
* @category handle & forking
|
|
3433
|
+
*/
|
|
3434
|
+
export interface Handle<A, E = never> {
|
|
3435
|
+
readonly [HandleTypeId]: HandleTypeId
|
|
3436
|
+
readonly await: Micro<Result<A, E>>
|
|
3437
|
+
readonly join: Micro<A, E>
|
|
3438
|
+
readonly abort: Micro<Result<A, E>>
|
|
3439
|
+
readonly unsafeAbort: () => void
|
|
3440
|
+
readonly addObserver: (observer: (result: Result<A, E>) => void) => void
|
|
3441
|
+
readonly removeObserver: (observer: (result: Result<A, E>) => void) => void
|
|
3442
|
+
readonly unsafePoll: () => Result<A, E> | null
|
|
3443
|
+
}
|
|
3444
|
+
|
|
3445
|
+
/**
|
|
3446
|
+
* @since 3.4.0
|
|
3447
|
+
* @experimental
|
|
3448
|
+
* @category handle & forking
|
|
3449
|
+
*/
|
|
3450
|
+
export const isHandle = (u: unknown): u is Handle<unknown, unknown> =>
|
|
3451
|
+
typeof u === "object" && u !== null && HandleTypeId in u
|
|
3452
|
+
|
|
3453
|
+
class HandleImpl<A, E> implements Handle<A, E> {
|
|
3454
|
+
readonly [HandleTypeId]: HandleTypeId
|
|
3455
|
+
|
|
3456
|
+
readonly observers: Set<(result: Result<A, E>) => void> = new Set()
|
|
3457
|
+
private _result: Result<A, E> | undefined = undefined
|
|
3458
|
+
_controller: AbortController
|
|
3459
|
+
readonly isRoot: boolean
|
|
3460
|
+
|
|
3461
|
+
constructor(readonly parentSignal: AbortSignal, controller?: AbortController) {
|
|
3462
|
+
this[HandleTypeId] = HandleTypeId
|
|
3463
|
+
this.isRoot = controller !== undefined
|
|
3464
|
+
this._controller = controller ?? new AbortController()
|
|
3465
|
+
if (!this.isRoot) {
|
|
3466
|
+
parentSignal.addEventListener("abort", this.unsafeAbort)
|
|
3467
|
+
}
|
|
3468
|
+
}
|
|
3469
|
+
|
|
3470
|
+
unsafePoll(): Result<A, E> | null {
|
|
3471
|
+
return this._result ?? null
|
|
3472
|
+
}
|
|
3473
|
+
|
|
3474
|
+
unsafeAbort = () => {
|
|
3475
|
+
this._controller.abort()
|
|
3476
|
+
}
|
|
3477
|
+
|
|
3478
|
+
emit(result: Result<A, E>): void {
|
|
3479
|
+
if (this._result) {
|
|
3480
|
+
return
|
|
3481
|
+
}
|
|
3482
|
+
this._result = result
|
|
3483
|
+
if (!this.isRoot) {
|
|
3484
|
+
this.parentSignal.removeEventListener("abort", this.unsafeAbort)
|
|
3485
|
+
}
|
|
3486
|
+
this.observers.forEach((observer) => observer(result))
|
|
3487
|
+
this.observers.clear()
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3490
|
+
addObserver(observer: (result: Result<A, E>) => void): void {
|
|
3491
|
+
if (this._result) {
|
|
3492
|
+
return observer(this._result)
|
|
3493
|
+
}
|
|
3494
|
+
this.observers.add(observer)
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3497
|
+
removeObserver(observer: (result: Result<A, E>) => void): void {
|
|
3498
|
+
this.observers.delete(observer)
|
|
3499
|
+
}
|
|
3500
|
+
|
|
3501
|
+
get await(): Micro<Result<A, E>> {
|
|
3502
|
+
return suspend(() => {
|
|
3503
|
+
if (this._result) {
|
|
3504
|
+
return succeed(this._result)
|
|
3505
|
+
}
|
|
3506
|
+
return async((resume) => {
|
|
3507
|
+
function observer(result: Result<A, E>) {
|
|
3508
|
+
resume(succeed(result))
|
|
3509
|
+
}
|
|
3510
|
+
this.addObserver(observer)
|
|
3511
|
+
return sync(() => {
|
|
3512
|
+
this.removeObserver(observer)
|
|
3513
|
+
})
|
|
3514
|
+
})
|
|
3515
|
+
})
|
|
3516
|
+
}
|
|
3517
|
+
|
|
3518
|
+
get join(): Micro<A, E> {
|
|
3519
|
+
return flatMap(this.await, fromResult)
|
|
3520
|
+
}
|
|
3521
|
+
|
|
3522
|
+
get abort(): Micro<Result<A, E>> {
|
|
3523
|
+
return suspend(() => {
|
|
3524
|
+
this.unsafeAbort()
|
|
3525
|
+
return this.await
|
|
3526
|
+
})
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
|
|
3530
|
+
/**
|
|
3531
|
+
* Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
|
|
3532
|
+
* aborted.
|
|
3533
|
+
*
|
|
3534
|
+
* When the parent `Micro` finishes, this `Micro` will be aborted.
|
|
3535
|
+
*
|
|
3536
|
+
* @since 3.4.0
|
|
3537
|
+
* @experimental
|
|
3538
|
+
* @category handle & forking
|
|
3539
|
+
*/
|
|
3540
|
+
export const fork = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never, R> =>
|
|
3541
|
+
make(function(env, onResult) {
|
|
3542
|
+
const signal = envGet(env, currentAbortSignal)
|
|
3543
|
+
const handle = new HandleImpl<A, E>(signal)
|
|
3544
|
+
const nextEnv = envMutate(env, (map) => {
|
|
3545
|
+
map[currentAbortController.key] = handle._controller
|
|
3546
|
+
map[currentAbortSignal.key] = handle._controller.signal
|
|
3547
|
+
return map
|
|
3548
|
+
})
|
|
3549
|
+
yieldAdd(() => {
|
|
3550
|
+
self[runSymbol](nextEnv, (result) => {
|
|
3551
|
+
handle.emit(result)
|
|
3552
|
+
})
|
|
3553
|
+
})
|
|
3554
|
+
onResult(Either.right(handle))
|
|
3555
|
+
})
|
|
3556
|
+
|
|
3557
|
+
/**
|
|
3558
|
+
* Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
|
|
3559
|
+
* aborted.
|
|
3560
|
+
*
|
|
3561
|
+
* It will not be aborted when the parent `Micro` finishes.
|
|
3562
|
+
*
|
|
3563
|
+
* @since 3.4.0
|
|
3564
|
+
* @experimental
|
|
3565
|
+
* @category handle & forking
|
|
3566
|
+
*/
|
|
3567
|
+
export const forkDaemon = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never, R> =>
|
|
3568
|
+
make(function(env, onResult) {
|
|
3569
|
+
const controller = new AbortController()
|
|
3570
|
+
const handle = new HandleImpl<A, E>(controller.signal, controller)
|
|
3571
|
+
const nextEnv = envMutate(env, (map) => {
|
|
3572
|
+
map[currentAbortController.key] = controller
|
|
3573
|
+
map[currentAbortSignal.key] = controller.signal
|
|
3574
|
+
return map
|
|
3575
|
+
})
|
|
3576
|
+
yieldAdd(() => {
|
|
3577
|
+
self[runSymbol](nextEnv, (result) => {
|
|
3578
|
+
handle.emit(result)
|
|
3579
|
+
})
|
|
3580
|
+
})
|
|
3581
|
+
onResult(Either.right(handle))
|
|
3582
|
+
})
|
|
3583
|
+
|
|
3584
|
+
/**
|
|
3585
|
+
* Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
|
|
3586
|
+
* aborted.
|
|
3587
|
+
*
|
|
3588
|
+
* The lifetime of the handle will be attached to the provided `MicroScope`.
|
|
3589
|
+
*
|
|
3590
|
+
* @since 3.4.0
|
|
3591
|
+
* @experimental
|
|
3592
|
+
* @category handle & forking
|
|
3593
|
+
*/
|
|
3594
|
+
export const forkIn: {
|
|
3595
|
+
(scope: MicroScope): <A, E, R>(self: Micro<A, E, R>) => Micro<Handle<A, E>, never, R>
|
|
3596
|
+
<A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<Handle<A, E>, never, R>
|
|
3597
|
+
} = dual(
|
|
3598
|
+
2,
|
|
3599
|
+
<A, E, R>(self: Micro<A, E, R>, scope: MicroScope): Micro<Handle<A, E>, never, R> =>
|
|
3600
|
+
uninterruptibleMask((restore) =>
|
|
3601
|
+
flatMap(scope.fork, (scope) =>
|
|
3602
|
+
tap(
|
|
3603
|
+
restore(forkDaemon(onResult(self, (result) => scope.close(result)))),
|
|
3604
|
+
(fiber) => scope.addFinalizer((_) => asVoid(fiber.abort))
|
|
3605
|
+
))
|
|
3606
|
+
)
|
|
3607
|
+
)
|
|
3608
|
+
|
|
3609
|
+
/**
|
|
3610
|
+
* Run the `Micro` effect in a new `Handle` that can be awaited, joined, or
|
|
3611
|
+
* aborted.
|
|
3612
|
+
*
|
|
3613
|
+
* The lifetime of the handle will be attached to the current `MicroScope`.
|
|
3614
|
+
*
|
|
3615
|
+
* @since 3.4.0
|
|
3616
|
+
* @experimental
|
|
3617
|
+
* @category handle & forking
|
|
3618
|
+
*/
|
|
3619
|
+
export const forkScoped = <A, E, R>(self: Micro<A, E, R>): Micro<Handle<A, E>, never, R | MicroScope> =>
|
|
3620
|
+
flatMap(scope, (scope) => forkIn(self, scope))
|
|
3621
|
+
|
|
3622
|
+
// ----------------------------------------------------------------------------
|
|
3623
|
+
// execution
|
|
3624
|
+
// ----------------------------------------------------------------------------
|
|
3625
|
+
|
|
3626
|
+
/**
|
|
3627
|
+
* Execute the `Micro` effect and return a `Handle` that can be awaited, joined,
|
|
3628
|
+
* or aborted.
|
|
3629
|
+
*
|
|
3630
|
+
* You can listen for the result by adding an observer using the handle's
|
|
3631
|
+
* `addObserver` method.
|
|
3632
|
+
*
|
|
3633
|
+
* @since 3.4.0
|
|
3634
|
+
* @experimental
|
|
3635
|
+
* @category execution
|
|
3636
|
+
* @example
|
|
3637
|
+
* import * as Micro from "effect/Micro"
|
|
3638
|
+
*
|
|
3639
|
+
* const handle = Micro.succeed(42).pipe(
|
|
3640
|
+
* Micro.delay(1000),
|
|
3641
|
+
* Micro.runFork
|
|
3642
|
+
* )
|
|
3643
|
+
*
|
|
3644
|
+
* handle.addObserver((result) => {
|
|
3645
|
+
* console.log(result)
|
|
3646
|
+
* })
|
|
3647
|
+
*/
|
|
3648
|
+
export const runFork = <A, E>(
|
|
3649
|
+
effect: Micro<A, E>,
|
|
3650
|
+
options?: {
|
|
3651
|
+
readonly signal?: AbortSignal | undefined
|
|
3652
|
+
} | undefined
|
|
3653
|
+
): Handle<A, E> => {
|
|
3654
|
+
const controller = new AbortController()
|
|
3655
|
+
const refs = Object.create(null)
|
|
3656
|
+
refs[currentAbortController.key] = controller
|
|
3657
|
+
refs[currentAbortSignal.key] = controller.signal
|
|
3658
|
+
const env = envMake(refs)
|
|
3659
|
+
const handle = new HandleImpl<A, E>(controller.signal, controller)
|
|
3660
|
+
effect[runSymbol](envSet(env, currentAbortSignal, handle._controller.signal), (result) => {
|
|
3661
|
+
handle.emit(result)
|
|
3662
|
+
})
|
|
3663
|
+
if (options?.signal) {
|
|
3664
|
+
if (options.signal.aborted) {
|
|
3665
|
+
handle.unsafeAbort()
|
|
3666
|
+
} else {
|
|
3667
|
+
options.signal.addEventListener("abort", () => handle.unsafeAbort())
|
|
3668
|
+
}
|
|
3669
|
+
}
|
|
3670
|
+
return handle
|
|
3671
|
+
}
|
|
3672
|
+
|
|
3673
|
+
/**
|
|
3674
|
+
* Execute the `Micro` effect and return a `Promise` that resolves with the
|
|
3675
|
+
* `Result` of the computation.
|
|
3676
|
+
*
|
|
3677
|
+
* @since 3.4.0
|
|
3678
|
+
* @experimental
|
|
3679
|
+
* @category execution
|
|
3680
|
+
*/
|
|
3681
|
+
export const runPromiseResult = <A, E>(
|
|
3682
|
+
effect: Micro<A, E>,
|
|
3683
|
+
options?: {
|
|
3684
|
+
readonly signal?: AbortSignal | undefined
|
|
3685
|
+
} | undefined
|
|
3686
|
+
): Promise<Result<A, E>> =>
|
|
3687
|
+
new Promise((resolve, _reject) => {
|
|
3688
|
+
const handle = runFork(effect, options)
|
|
3689
|
+
handle.addObserver(resolve)
|
|
3690
|
+
})
|
|
3691
|
+
|
|
3692
|
+
/**
|
|
3693
|
+
* Execute the `Micro` effect and return a `Promise` that resolves with the
|
|
3694
|
+
* successful value of the computation.
|
|
3695
|
+
*
|
|
3696
|
+
* @since 3.4.0
|
|
3697
|
+
* @experimental
|
|
3698
|
+
* @category execution
|
|
3699
|
+
*/
|
|
3700
|
+
export const runPromise = <A, E>(
|
|
3701
|
+
effect: Micro<A, E>,
|
|
3702
|
+
options?: {
|
|
3703
|
+
readonly signal?: AbortSignal | undefined
|
|
3704
|
+
} | undefined
|
|
3705
|
+
): Promise<A> =>
|
|
3706
|
+
runPromiseResult(effect, options).then((result) => {
|
|
3707
|
+
if (result._tag === "Left") {
|
|
3708
|
+
throw result.left
|
|
3709
|
+
}
|
|
3710
|
+
return result.right
|
|
3711
|
+
})
|
|
3712
|
+
|
|
3713
|
+
/**
|
|
3714
|
+
* Attempt to execute the `Micro` effect synchronously and return the `Result`.
|
|
3715
|
+
*
|
|
3716
|
+
* If any asynchronous effects are encountered, the function will return a
|
|
3717
|
+
* FailureUnexpected containing the `Handle`.
|
|
3718
|
+
*
|
|
3719
|
+
* @since 3.4.0
|
|
3720
|
+
* @experimental
|
|
3721
|
+
* @category execution
|
|
3722
|
+
*/
|
|
3723
|
+
export const runSyncResult = <A, E>(effect: Micro<A, E>): Result<A, E> => {
|
|
3724
|
+
const handle = runFork(effect)
|
|
3725
|
+
while (yieldState.tasks.length > 0) {
|
|
3726
|
+
yieldRunTasks()
|
|
3727
|
+
}
|
|
3728
|
+
const result = handle.unsafePoll()
|
|
3729
|
+
if (result === null) {
|
|
3730
|
+
return ResultFailUnexpected(handle)
|
|
3731
|
+
}
|
|
3732
|
+
return result
|
|
3733
|
+
}
|
|
3734
|
+
|
|
3735
|
+
/**
|
|
3736
|
+
* Attempt to execute the `Micro` effect synchronously and return the success
|
|
3737
|
+
* value.
|
|
3738
|
+
*
|
|
3739
|
+
* @since 3.4.0
|
|
3740
|
+
* @experimental
|
|
3741
|
+
* @category execution
|
|
3742
|
+
*/
|
|
3743
|
+
export const runSync = <A, E>(effect: Micro<A, E>): A => {
|
|
3744
|
+
const result = runSyncResult(effect)
|
|
3745
|
+
if (result._tag === "Left") {
|
|
3746
|
+
throw result.left
|
|
3747
|
+
}
|
|
3748
|
+
return result.right
|
|
3749
|
+
}
|
|
3750
|
+
|
|
3751
|
+
// ----------------------------------------------------------------------------
|
|
3752
|
+
// Errors
|
|
3753
|
+
// ----------------------------------------------------------------------------
|
|
3754
|
+
|
|
3755
|
+
/**
|
|
3756
|
+
* @since 3.4.0
|
|
3757
|
+
* @experimental
|
|
3758
|
+
* @category errors
|
|
3759
|
+
*/
|
|
3760
|
+
export interface YieldableError extends Pipeable, Inspectable, Readonly<Error> {
|
|
3761
|
+
readonly [EffectTypeId]: Effect.VarianceStruct<never, this, never>
|
|
3762
|
+
readonly [StreamTypeId]: Stream.VarianceStruct<never, this, never>
|
|
3763
|
+
readonly [SinkTypeId]: Sink.VarianceStruct<never, unknown, never, this, never>
|
|
3764
|
+
readonly [ChannelTypeId]: Channel.VarianceStruct<never, unknown, this, unknown, never, unknown, never>
|
|
3765
|
+
readonly [TypeId]: Micro.Variance<never, this, never>
|
|
3766
|
+
readonly [runSymbol]: (env: Env<any>, onResult: (result: Result<never, this>) => void) => void
|
|
3767
|
+
[Symbol.iterator](): MicroIterator<Micro<never, this, never>>
|
|
3768
|
+
}
|
|
3769
|
+
|
|
3770
|
+
const YieldableError: new(message?: string) => YieldableError = (function() {
|
|
3771
|
+
class YieldableError extends globalThis.Error {
|
|
3772
|
+
[runSymbol](_env: any, onResult: any) {
|
|
3773
|
+
onResult(ResultFail(this))
|
|
3774
|
+
}
|
|
3775
|
+
toString() {
|
|
3776
|
+
return this.message ? `${this.name}: ${this.message}` : this.name
|
|
3777
|
+
}
|
|
3778
|
+
toJSON() {
|
|
3779
|
+
return { ...this }
|
|
3780
|
+
}
|
|
3781
|
+
[NodeInspectSymbol](): string {
|
|
3782
|
+
const stack = this.stack
|
|
3783
|
+
if (stack) {
|
|
3784
|
+
return `${this.toString()}\n${stack.split("\n").slice(1).join("\n")}`
|
|
3785
|
+
}
|
|
3786
|
+
return this.toString()
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
Object.assign(YieldableError.prototype, MicroProto, StructuralPrototype)
|
|
3790
|
+
return YieldableError as any
|
|
3791
|
+
})()
|
|
3792
|
+
|
|
3793
|
+
/**
|
|
3794
|
+
* @since 3.4.0
|
|
3795
|
+
* @experimental
|
|
3796
|
+
* @category errors
|
|
3797
|
+
*/
|
|
3798
|
+
export const Error: new<A extends Record<string, any> = {}>(
|
|
3799
|
+
args: Equals<A, {}> extends true ? void
|
|
3800
|
+
: { readonly [P in keyof A]: A[P] }
|
|
3801
|
+
) => YieldableError & Readonly<A> = (function() {
|
|
3802
|
+
return class extends YieldableError {
|
|
3803
|
+
constructor(args: any) {
|
|
3804
|
+
super()
|
|
3805
|
+
if (args) {
|
|
3806
|
+
Object.assign(this, args)
|
|
3807
|
+
}
|
|
3808
|
+
}
|
|
3809
|
+
} as any
|
|
3810
|
+
})()
|
|
3811
|
+
|
|
3812
|
+
/**
|
|
3813
|
+
* @since 3.4.0
|
|
3814
|
+
* @experimental
|
|
3815
|
+
* @category errors
|
|
3816
|
+
*/
|
|
3817
|
+
export const TaggedError = <Tag extends string>(tag: Tag): new<A extends Record<string, any> = {}>(
|
|
3818
|
+
args: Equals<A, {}> extends true ? void
|
|
3819
|
+
: { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }
|
|
3820
|
+
) => YieldableError & { readonly _tag: Tag } & Readonly<A> => {
|
|
3821
|
+
class Base extends Error<{}> {
|
|
3822
|
+
readonly _tag = tag
|
|
3823
|
+
}
|
|
3824
|
+
;(Base.prototype as any).name = tag
|
|
3825
|
+
return Base as any
|
|
3826
|
+
}
|