effect 2.1.2 → 2.2.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/src/FiberMap.ts CHANGED
@@ -7,11 +7,13 @@ import type { NoSuchElementException } from "./Cause.js"
7
7
  import * as Fiber from "./Fiber.js"
8
8
  import * as FiberId from "./FiberId.js"
9
9
  import { dual } from "./Function.js"
10
+ import type { FiberMap } from "./index.js"
10
11
  import * as Inspectable from "./Inspectable.js"
11
12
  import * as MutableHashMap from "./MutableHashMap.js"
12
13
  import * as Option from "./Option.js"
13
14
  import { type Pipeable, pipeArguments } from "./Pipeable.js"
14
15
  import * as Predicate from "./Predicate.js"
16
+ import * as Runtime from "./Runtime.js"
15
17
 
16
18
  /**
17
19
  * @since 2.0.0
@@ -98,6 +100,26 @@ const unsafeMake = <K, E = unknown, A = unknown>(): FiberMap<K, E, A> => {
98
100
  export const make = <K, E = unknown, A = unknown>(): Effect.Effect<Scope.Scope, never, FiberMap<K, E, A>> =>
99
101
  Effect.acquireRelease(Effect.sync(() => unsafeMake<K, E, A>()), clear)
100
102
 
103
+ /**
104
+ * Create an Effect run function that is backed by a FiberMap.
105
+ *
106
+ * @since 2.0.0
107
+ * @categories constructors
108
+ */
109
+ export const makeRuntime = <R, K, E = unknown, A = unknown>(): Effect.Effect<
110
+ Scope.Scope | R,
111
+ never,
112
+ <XE extends E, XA extends A>(
113
+ key: K,
114
+ effect: Effect.Effect<R, XE, XA>,
115
+ options?: Runtime.RunForkOptions | undefined
116
+ ) => Fiber.RuntimeFiber<XE, XA>
117
+ > =>
118
+ Effect.flatMap(
119
+ make<K, E, A>(),
120
+ (self) => runtime(self)<R>()
121
+ )
122
+
101
123
  /**
102
124
  * Add a fiber to the FiberMap. When the fiber completes, it will be removed from the FiberMap.
103
125
  * If the key already exists in the FiberMap, the previous fiber will be interrupted.
@@ -263,30 +285,89 @@ export const clear = <K, E, A>(self: FiberMap<K, E, A>): Effect.Effect<never, ne
263
285
  * @categories combinators
264
286
  */
265
287
  export const run: {
266
- <K, E, A, R, XE extends E, XA extends A>(
267
- key: K,
268
- effect: Effect.Effect<R, XE, XA>
269
- ): (self: FiberMap<K, E, A>) => Effect.Effect<R, never, Fiber.RuntimeFiber<XE, XA>>
270
- <K, E, A, R, XE extends E, XA extends A>(
288
+ <K, E, A>(
271
289
  self: FiberMap<K, E, A>,
272
- key: K,
273
- effect: Effect.Effect<R, XE, XA>
274
- ): Effect.Effect<R, never, Fiber.RuntimeFiber<XE, XA>>
275
- } = dual<
276
- <K, E, A, R, XE extends E, XA extends A>(
277
- key: K,
290
+ key: K
291
+ ): <R, XE extends E, XA extends A>(
278
292
  effect: Effect.Effect<R, XE, XA>
279
- ) => (self: FiberMap<K, E, A>) => Effect.Effect<R, never, Fiber.RuntimeFiber<XE, XA>>,
293
+ ) => Effect.Effect<R, never, Fiber.RuntimeFiber<XE, XA>>
280
294
  <K, E, A, R, XE extends E, XA extends A>(
281
295
  self: FiberMap<K, E, A>,
282
296
  key: K,
283
297
  effect: Effect.Effect<R, XE, XA>
284
- ) => Effect.Effect<R, never, Fiber.RuntimeFiber<XE, XA>>
285
- >(3, (self, key, effect) =>
286
- Effect.tap(
298
+ ): Effect.Effect<R, never, Fiber.RuntimeFiber<XE, XA>>
299
+ } = function() {
300
+ if (arguments.length === 2) {
301
+ const self = arguments[0] as FiberMap<any>
302
+ const key = arguments[1]
303
+ return (effect: Effect.Effect<any, any, any>) =>
304
+ Effect.tap(
305
+ Effect.forkDaemon(effect),
306
+ (fiber) => set(self, key, fiber)
307
+ )
308
+ }
309
+ const self = arguments[0] as FiberMap<any>
310
+ const key = arguments[1]
311
+ const effect = arguments[2] as Effect.Effect<any, any, any>
312
+ return Effect.tap(
287
313
  Effect.forkDaemon(effect),
288
314
  (fiber) => set(self, key, fiber)
289
- ))
315
+ ) as any
316
+ }
317
+
318
+ /**
319
+ * Capture a Runtime and use it to fork Effect's, adding the forked fibers to the FiberMap.
320
+ *
321
+ * @example
322
+ * import { Context, Effect, FiberMap } from "effect"
323
+ *
324
+ * interface Users {
325
+ * readonly _: unique symbol
326
+ * }
327
+ * const Users = Context.Tag<Users, {
328
+ * getAll: Effect.Effect<never, never, Array<unknown>>
329
+ * }>()
330
+ *
331
+ * Effect.gen(function*(_) {
332
+ * const map = yield* _(FiberMap.make<string>())
333
+ * const run = yield* _(FiberMap.runtime(map)<Users>())
334
+ *
335
+ * // run some effects and add the fibers to the map
336
+ * run("effect-a", Effect.andThen(Users, _ => _.getAll))
337
+ * run("effect-b", Effect.andThen(Users, _ => _.getAll))
338
+ * }).pipe(
339
+ * Effect.scoped // The fibers will be interrupted when the scope is closed
340
+ * )
341
+ *
342
+ * @since 2.0.0
343
+ * @categories combinators
344
+ */
345
+ export const runtime: <K, E, A>(
346
+ self: FiberMap<K, E, A>
347
+ ) => <R>() => Effect.Effect<
348
+ R,
349
+ never,
350
+ <XE extends E, XA extends A>(
351
+ key: K,
352
+ effect: Effect.Effect<R, XE, XA>,
353
+ options?: Runtime.RunForkOptions | undefined
354
+ ) => Fiber.RuntimeFiber<XE, XA>
355
+ > = <K, E, A>(self: FiberMap<K, E, A>) => <R>() =>
356
+ Effect.map(
357
+ Effect.runtime<R>(),
358
+ (runtime) => {
359
+ const runFork = Runtime.runFork(runtime)
360
+ return <XE extends E, XA extends A>(
361
+ key: K,
362
+ effect: Effect.Effect<R, XE, XA>,
363
+ options?: Runtime.RunForkOptions | undefined
364
+ ) => {
365
+ const fiber = runFork(effect, options)
366
+ unsafeSet(self, key, fiber)
367
+ return fiber
368
+ }
369
+ }
370
+ )
290
371
 
291
372
  /**
292
373
  * @since 2.0.0
package/src/FiberSet.ts CHANGED
@@ -8,6 +8,7 @@ import { dual } from "./Function.js"
8
8
  import * as Inspectable from "./Inspectable.js"
9
9
  import { type Pipeable, pipeArguments } from "./Pipeable.js"
10
10
  import * as Predicate from "./Predicate.js"
11
+ import * as Runtime from "./Runtime.js"
11
12
 
12
13
  /**
13
14
  * @since 2.0.0
@@ -94,6 +95,25 @@ const unsafeMake = <E = unknown, A = unknown>(): FiberSet<E, A> => {
94
95
  export const make = <E = unknown, A = unknown>(): Effect.Effect<Scope.Scope, never, FiberSet<E, A>> =>
95
96
  Effect.acquireRelease(Effect.sync(() => unsafeMake<E, A>()), clear)
96
97
 
98
+ /**
99
+ * Create an Effect run function that is backed by a FiberSet.
100
+ *
101
+ * @since 2.0.0
102
+ * @categories constructors
103
+ */
104
+ export const makeRuntime = <R, E = unknown, A = unknown>(): Effect.Effect<
105
+ Scope.Scope | R,
106
+ never,
107
+ <XE extends E, XA extends A>(
108
+ effect: Effect.Effect<R, XE, XA>,
109
+ options?: Runtime.RunForkOptions | undefined
110
+ ) => Fiber.RuntimeFiber<XE, XA>
111
+ > =>
112
+ Effect.flatMap(
113
+ make<E, A>(),
114
+ (self) => runtime(self)<R>()
115
+ )
116
+
97
117
  /**
98
118
  * Add a fiber to the FiberSet. When the fiber completes, it will be removed.
99
119
  *
@@ -165,26 +185,79 @@ export const clear = <E, A>(self: FiberSet<E, A>): Effect.Effect<never, never, v
165
185
  * @categories combinators
166
186
  */
167
187
  export const run: {
168
- <E, A, R, XE extends E, XA extends A>(
188
+ <E, A>(self: FiberSet<E, A>): <R, XE extends E, XA extends A>(
169
189
  effect: Effect.Effect<R, XE, XA>
170
- ): (self: FiberSet<E, A>) => Effect.Effect<R, never, Fiber.RuntimeFiber<XE, XA>>
190
+ ) => Effect.Effect<R, never, Fiber.RuntimeFiber<XE, XA>>
171
191
  <E, A, R, XE extends E, XA extends A>(
172
192
  self: FiberSet<E, A>,
173
193
  effect: Effect.Effect<R, XE, XA>
174
194
  ): Effect.Effect<R, never, Fiber.RuntimeFiber<XE, XA>>
175
- } = dual<
176
- <E, A, R, XE extends E, XA extends A>(
177
- effect: Effect.Effect<R, XE, XA>
178
- ) => (self: FiberSet<E, A>) => Effect.Effect<R, never, Fiber.RuntimeFiber<XE, XA>>,
179
- <E, A, R, XE extends E, XA extends A>(
180
- self: FiberSet<E, A>,
181
- effect: Effect.Effect<R, XE, XA>
182
- ) => Effect.Effect<R, never, Fiber.RuntimeFiber<XE, XA>>
183
- >(2, (self, effect) =>
184
- Effect.tap(
195
+ } = function() {
196
+ const self = arguments[0] as FiberSet<any>
197
+ if (arguments.length === 1) {
198
+ return (effect: Effect.Effect<any, any, any>) =>
199
+ Effect.tap(
200
+ Effect.forkDaemon(effect),
201
+ (fiber) => add(self, fiber)
202
+ )
203
+ }
204
+ const effect = arguments[1] as Effect.Effect<any, any, any>
205
+ return Effect.tap(
185
206
  Effect.forkDaemon(effect),
186
207
  (fiber) => add(self, fiber)
187
- ))
208
+ ) as any
209
+ }
210
+
211
+ /**
212
+ * Capture a Runtime and use it to fork Effect's, adding the forked fibers to the FiberSet.
213
+ *
214
+ * @example
215
+ * import { Context, Effect, FiberSet } from "effect"
216
+ *
217
+ * interface Users {
218
+ * readonly _: unique symbol
219
+ * }
220
+ * const Users = Context.Tag<Users, {
221
+ * getAll: Effect.Effect<never, never, Array<unknown>>
222
+ * }>()
223
+ *
224
+ * Effect.gen(function*(_) {
225
+ * const set = yield* _(FiberSet.make())
226
+ * const run = yield* _(FiberSet.runtime(set)<Users>())
227
+ *
228
+ * // run some effects and add the fibers to the set
229
+ * run(Effect.andThen(Users, _ => _.getAll))
230
+ * }).pipe(
231
+ * Effect.scoped // The fibers will be interrupted when the scope is closed
232
+ * )
233
+ *
234
+ * @since 2.0.0
235
+ * @categories combinators
236
+ */
237
+ export const runtime: <E, A>(
238
+ self: FiberSet<E, A>
239
+ ) => <R>() => Effect.Effect<
240
+ R,
241
+ never,
242
+ <XE extends E, XA extends A>(
243
+ effect: Effect.Effect<R, XE, XA>,
244
+ options?: Runtime.RunForkOptions | undefined
245
+ ) => Fiber.RuntimeFiber<XE, XA>
246
+ > = <E, A>(self: FiberSet<E, A>) => <R>() =>
247
+ Effect.map(
248
+ Effect.runtime<R>(),
249
+ (runtime) => {
250
+ const runFork = Runtime.runFork(runtime)
251
+ return <XE extends E, XA extends A>(
252
+ effect: Effect.Effect<R, XE, XA>,
253
+ options?: Runtime.RunForkOptions | undefined
254
+ ) => {
255
+ const fiber = runFork(effect, options)
256
+ unsafeAdd(self, fiber)
257
+ return fiber
258
+ }
259
+ }
260
+ )
188
261
 
189
262
  /**
190
263
  * @since 2.0.0
@@ -38,12 +38,13 @@ export type OP_COMPOSITE = typeof OP_COMPOSITE
38
38
  /** @internal */
39
39
  class None implements FiberId.None {
40
40
  readonly [FiberIdTypeId]: FiberId.FiberIdTypeId = FiberIdTypeId
41
- readonly _tag = OP_NONE;
41
+ readonly _tag = OP_NONE
42
+ readonly _hash: number
43
+ constructor() {
44
+ this._hash = Hash.string(`${FiberIdSymbolKey}-${this._tag}`)
45
+ }
42
46
  [Hash.symbol](): number {
43
- return pipe(
44
- Hash.hash(FiberIdSymbolKey),
45
- Hash.combine(Hash.hash(this._tag))
46
- )
47
+ return this._hash
47
48
  }
48
49
  [Equal.symbol](that: unknown): boolean {
49
50
  return isFiberId(that) && that._tag === OP_NONE
@@ -66,17 +67,15 @@ class None implements FiberId.None {
66
67
  class Runtime implements FiberId.Runtime {
67
68
  readonly [FiberIdTypeId]: FiberId.FiberIdTypeId = FiberIdTypeId
68
69
  readonly _tag = OP_RUNTIME
70
+ readonly _hash: number
69
71
  constructor(
70
72
  readonly id: number,
71
73
  readonly startTimeMillis: number
72
- ) {}
74
+ ) {
75
+ this._hash = Hash.string(`${FiberIdSymbolKey}-${this._tag}-${this.id}-${this.startTimeMillis}`)
76
+ }
73
77
  [Hash.symbol](): number {
74
- return pipe(
75
- Hash.hash(FiberIdSymbolKey),
76
- Hash.combine(Hash.hash(this._tag)),
77
- Hash.combine(Hash.hash(this.id)),
78
- Hash.combine(Hash.hash(this.startTimeMillis))
79
- )
78
+ return this._hash
80
79
  }
81
80
  [Equal.symbol](that: unknown): boolean {
82
81
  return isFiberId(that) &&
@@ -104,18 +103,20 @@ class Runtime implements FiberId.Runtime {
104
103
  class Composite implements FiberId.Composite {
105
104
  readonly [FiberIdTypeId]: FiberId.FiberIdTypeId = FiberIdTypeId
106
105
  readonly _tag = OP_COMPOSITE
106
+ readonly _hash: number
107
107
  constructor(
108
108
  readonly left: FiberId.FiberId,
109
109
  readonly right: FiberId.FiberId
110
- ) {}
111
- [Hash.symbol](): number {
112
- return pipe(
113
- Hash.hash(FiberIdSymbolKey),
114
- Hash.combine(Hash.hash(this._tag)),
110
+ ) {
111
+ this._hash = pipe(
112
+ Hash.string(`${FiberIdSymbolKey}-${this._tag}`),
115
113
  Hash.combine(Hash.hash(this.left)),
116
114
  Hash.combine(Hash.hash(this.right))
117
115
  )
118
116
  }
117
+ [Hash.symbol](): number {
118
+ return this._hash
119
+ }
119
120
  [Equal.symbol](that: unknown): boolean {
120
121
  return isFiberId(that) &&
121
122
  that._tag === OP_COMPOSITE &&
@@ -116,18 +116,21 @@ class ScheduleDriverImpl<Env, In, Out> implements Schedule.ScheduleDriver<Env, I
116
116
  core.flatMap((now) =>
117
117
  pipe(
118
118
  core.suspend(() => this.schedule.step(now, input, state)),
119
- core.flatMap(([state, out, decision]) =>
120
- ScheduleDecision.isDone(decision) ?
121
- pipe(
122
- ref.set(this.ref, [Option.some(out), state] as const),
123
- core.zipRight(core.fail(Option.none()))
124
- ) :
125
- pipe(
126
- ref.set(this.ref, [Option.some(out), state] as const),
127
- core.zipRight(effect.sleep(Duration.millis(Intervals.start(decision.intervals) - now))),
128
- core.as(out)
129
- )
130
- )
119
+ core.flatMap(([state, out, decision]) => {
120
+ const setState = ref.set(this.ref, [Option.some(out), state] as const)
121
+ if (ScheduleDecision.isDone(decision)) {
122
+ return core.zipRight(setState, core.fail(Option.none()))
123
+ }
124
+ const millis = Intervals.start(decision.intervals) - now
125
+ if (millis <= 0) {
126
+ return core.as(setState, out)
127
+ }
128
+ return pipe(
129
+ setState,
130
+ core.zipRight(effect.sleep(Duration.millis(millis))),
131
+ core.as(out)
132
+ )
133
+ })
131
134
  )
132
135
  )
133
136
  )
@@ -1 +1 @@
1
- export const moduleVersion = "2.1.2"
1
+ export const moduleVersion = "2.2.0"