Skip to content

Commit 8baef83

Browse files
committedFeb 14, 2025
add Promise based apis to Fiber{Handle,Set,Map} modules (#4401)
1 parent 6862444 commit 8baef83

File tree

7 files changed

+209
-0
lines changed

7 files changed

+209
-0
lines changed
 

‎.changeset/chatty-terms-occur.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"effect": minor
3+
---
4+
5+
add Promise based apis to Fiber{Handle,Set,Map} modules

‎packages/effect/src/FiberHandle.ts

+59
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,25 @@ export const makeRuntime = <R, E = unknown, A = unknown>(): Effect.Effect<
143143
(self) => runtime(self)<R>()
144144
)
145145

146+
/**
147+
* Create an Effect run function that is backed by a FiberHandle.
148+
*
149+
* @since 3.13.0
150+
* @categories constructors
151+
*/
152+
export const makeRuntimePromise = <R = never, A = unknown, E = unknown>(): Effect.Effect<
153+
<XE extends E, XA extends A>(
154+
effect: Effect.Effect<XA, XE, R>,
155+
options?: Runtime.RunForkOptions | undefined
156+
) => Promise<XA>,
157+
never,
158+
Scope.Scope | R
159+
> =>
160+
Effect.flatMap(
161+
make<A, E>(),
162+
(self) => runtimePromise(self)<R>()
163+
)
164+
146165
const internalFiberIdId = -1
147166
const internalFiberId = FiberId.make(internalFiberIdId, 0)
148167
const isInternalInterruption = Cause.reduceWithContext(undefined, {
@@ -436,6 +455,46 @@ export const runtime: <A, E>(
436455
}
437456
)
438457

458+
/**
459+
* Capture a Runtime and use it to fork Effect's, adding the forked fibers to the FiberHandle.
460+
*
461+
* The returned run function will return Promise's that will resolve when the
462+
* fiber completes.
463+
*
464+
* @since 3.13.0
465+
* @categories combinators
466+
*/
467+
export const runtimePromise = <A, E>(self: FiberHandle<A, E>): <R = never>() => Effect.Effect<
468+
<XE extends E, XA extends A>(
469+
effect: Effect.Effect<XA, XE, R>,
470+
options?:
471+
| Runtime.RunForkOptions & { readonly propagateInterruption?: boolean | undefined }
472+
| undefined
473+
) => Promise<XA>,
474+
never,
475+
R
476+
> =>
477+
<R>() =>
478+
Effect.map(
479+
runtime(self)<R>(),
480+
(runFork) =>
481+
<XE extends E, XA extends A>(
482+
effect: Effect.Effect<XA, XE, R>,
483+
options?:
484+
| Runtime.RunForkOptions & { readonly propagateInterruption?: boolean | undefined }
485+
| undefined
486+
): Promise<XA> =>
487+
new Promise((resolve, reject) =>
488+
runFork(effect, options).addObserver((exit) => {
489+
if (Exit.isSuccess(exit)) {
490+
resolve(exit.value)
491+
} else {
492+
reject(Cause.squash(exit.cause))
493+
}
494+
})
495+
)
496+
)
497+
439498
/**
440499
* If any of the Fiber's in the handle terminate with a failure,
441500
* the returned Effect will terminate with the first failure that occurred.

‎packages/effect/src/FiberMap.ts

+66
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,30 @@ export const makeRuntime = <R, K, E = unknown, A = unknown>(): Effect.Effect<
158158
(self) => runtime(self)<R>()
159159
)
160160

161+
/**
162+
* Create an Effect run function that is backed by a FiberMap.
163+
*
164+
* @since 3.13.0
165+
* @categories constructors
166+
*/
167+
export const makeRuntimePromise = <R, K, A = unknown, E = unknown>(): Effect.Effect<
168+
<XE extends E, XA extends A>(
169+
key: K,
170+
effect: Effect.Effect<XA, XE, R>,
171+
options?:
172+
| Runtime.RunForkOptions & {
173+
readonly onlyIfMissing?: boolean | undefined
174+
}
175+
| undefined
176+
) => Promise<XA>,
177+
never,
178+
Scope.Scope | R
179+
> =>
180+
Effect.flatMap(
181+
make<K, A, E>(),
182+
(self) => runtimePromise(self)<R>()
183+
)
184+
161185
const internalFiberIdId = -1
162186
const internalFiberId = FiberId.make(internalFiberIdId, 0)
163187
const isInternalInterruption = Cause.reduceWithContext(undefined, {
@@ -539,6 +563,48 @@ export const runtime: <K, A, E>(
539563
}
540564
)
541565

566+
/**
567+
* Capture a Runtime and use it to fork Effect's, adding the forked fibers to the FiberMap.
568+
*
569+
* @since 3.13.0
570+
* @categories combinators
571+
*/
572+
export const runtimePromise = <K, A, E>(self: FiberMap<K, A, E>): <R = never>() => Effect.Effect<
573+
<XE extends E, XA extends A>(
574+
key: K,
575+
effect: Effect.Effect<XA, XE, R>,
576+
options?:
577+
| Runtime.RunForkOptions & {
578+
readonly onlyIfMissing?: boolean | undefined
579+
readonly propagateInterruption?: boolean | undefined
580+
}
581+
| undefined
582+
) => Promise<XA>,
583+
never,
584+
R
585+
> =>
586+
<R>() =>
587+
Effect.map(
588+
runtime(self)<R>(),
589+
(runFork) =>
590+
<XE extends E, XA extends A>(
591+
key: K,
592+
effect: Effect.Effect<XA, XE, R>,
593+
options?:
594+
| Runtime.RunForkOptions & { readonly propagateInterruption?: boolean | undefined }
595+
| undefined
596+
): Promise<XA> =>
597+
new Promise((resolve, reject) =>
598+
runFork(key, effect, options).addObserver((exit) => {
599+
if (Exit.isSuccess(exit)) {
600+
resolve(exit.value)
601+
} else {
602+
reject(Cause.squash(exit.cause))
603+
}
604+
})
605+
)
606+
)
607+
542608
/**
543609
* @since 2.0.0
544610
* @categories combinators

‎packages/effect/src/FiberSet.ts

+58
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,25 @@ export const makeRuntime = <R = never, A = unknown, E = unknown>(): Effect.Effec
146146
(self) => runtime(self)<R>()
147147
)
148148

149+
/**
150+
* Create an Effect run function that is backed by a FiberSet.
151+
*
152+
* @since 3.13.0
153+
* @categories constructors
154+
*/
155+
export const makeRuntimePromise = <R = never, A = unknown, E = unknown>(): Effect.Effect<
156+
<XE extends E, XA extends A>(
157+
effect: Effect.Effect<XA, XE, R>,
158+
options?: Runtime.RunForkOptions | undefined
159+
) => Promise<XA>,
160+
never,
161+
Scope.Scope | R
162+
> =>
163+
Effect.flatMap(
164+
make<A, E>(),
165+
(self) => runtimePromise(self)<R>()
166+
)
167+
149168
const internalFiberIdId = -1
150169
const internalFiberId = FiberId.make(internalFiberIdId, 0)
151170
const isInternalInterruption = Cause.reduceWithContext(undefined, {
@@ -375,6 +394,45 @@ export const runtime: <A, E>(
375394
}
376395
)
377396

397+
/**
398+
* Capture a Runtime and use it to fork Effect's, adding the forked fibers to the FiberSet.
399+
*
400+
* The returned run function will return Promise's.
401+
*
402+
* @since 3.13.0
403+
* @categories combinators
404+
*/
405+
export const runtimePromise = <A, E>(self: FiberSet<A, E>): <R = never>() => Effect.Effect<
406+
<XE extends E, XA extends A>(
407+
effect: Effect.Effect<XA, XE, R>,
408+
options?:
409+
| Runtime.RunForkOptions & { readonly propagateInterruption?: boolean | undefined }
410+
| undefined
411+
) => Promise<XA>,
412+
never,
413+
R
414+
> =>
415+
<R>() =>
416+
Effect.map(
417+
runtime(self)<R>(),
418+
(runFork) =>
419+
<XE extends E, XA extends A>(
420+
effect: Effect.Effect<XA, XE, R>,
421+
options?:
422+
| Runtime.RunForkOptions & { readonly propagateInterruption?: boolean | undefined }
423+
| undefined
424+
): Promise<XA> =>
425+
new Promise((resolve, reject) =>
426+
runFork(effect, options).addObserver((exit) => {
427+
if (Exit.isSuccess(exit)) {
428+
resolve(exit.value)
429+
} else {
430+
reject(Cause.squash(exit.cause))
431+
}
432+
})
433+
)
434+
)
435+
378436
/**
379437
* @since 2.0.0
380438
* @categories combinators

‎packages/effect/test/FiberHandle.test.ts

+7
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,11 @@ describe("FiberHandle", () => {
111111
yield* TestClock.adjust(500)
112112
assert.isDefined(fiber.unsafePoll())
113113
}))
114+
115+
it.scoped("makeRuntimePromise", () =>
116+
Effect.gen(function*() {
117+
const run = yield* FiberHandle.makeRuntimePromise()
118+
const result = yield* Effect.promise(() => run(Effect.succeed("done")))
119+
strictEqual(result, "done")
120+
}))
114121
})

‎packages/effect/test/FiberMap.test.ts

+7
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,11 @@ describe("FiberMap", () => {
136136
yield* TestClock.adjust(500)
137137
assert.isDefined(fiber.unsafePoll())
138138
}))
139+
140+
it.scoped("makeRuntimePromise", () =>
141+
Effect.gen(function*() {
142+
const run = yield* FiberMap.makeRuntimePromise<never, string>()
143+
const result = yield* Effect.promise(() => run("a", Effect.succeed("done")))
144+
strictEqual(result, "done")
145+
}))
139146
})

‎packages/effect/test/FiberSet.test.ts

+7
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,11 @@ describe("FiberSet", () => {
108108
yield* TestClock.adjust(500)
109109
assert.isDefined(fiber.unsafePoll())
110110
}))
111+
112+
it.scoped("makeRuntimePromise", () =>
113+
Effect.gen(function*() {
114+
const run = yield* FiberSet.makeRuntimePromise()
115+
const result = yield* Effect.promise(() => run(Effect.succeed("done")))
116+
strictEqual(result, "done")
117+
}))
111118
})

0 commit comments

Comments
 (0)
Please sign in to comment.