diff --git a/.changeset/famous-mugs-attack.md b/.changeset/famous-mugs-attack.md index a84dd7e1b9..58a3165e6c 100644 --- a/.changeset/famous-mugs-attack.md +++ b/.changeset/famous-mugs-attack.md @@ -20,10 +20,8 @@ class Notifications extends Context.Tag("Notifications")< }); } -const NotificationsRunner = Layer.toRunner(() => Notifications.Live); - async function main() { - const runner = NotificationsRunner(); + const runner = Layer.toRunner(Notifications.Live); await runner.runPromiseService(Notifications, (_) => _.notify("Hello world!") ); diff --git a/packages/effect/src/Layer.ts b/packages/effect/src/Layer.ts index 400ea1fb06..5c96359fb1 100644 --- a/packages/effect/src/Layer.ts +++ b/packages/effect/src/Layer.ts @@ -1078,15 +1078,6 @@ export const buildWithMemoMap: { // runner // ----------------------------------------------------------------------------- -/** - * @since 2.0.0 - * @category runner - */ -export interface RunnerConstructor, R, E> { - (...args: Args): Runner - readonly withMemoMap: (memoMap: MemoMap, ...args: Args) => Runner -} - /** * @since 2.0.0 * @category runner @@ -1139,16 +1130,13 @@ export interface Runner extends AsyncDisposable { * }) * } * - * const NotificationsRunner = Layer.toRunner(() => Notifications.Live) - * * async function main() { - * const runner = NotificationsRunner() + * const runner = Layer.toRunner(Notifications.Live) * await runner.runPromiseService(Notifications, (_) => _.notify("Hello, world!")) * await runner.dispose() * } * * main() */ -export const toRunner: , R, RE>( - evaluate: (...args: Args) => Layer -) => RunnerConstructor = internal.toRunner +export const toRunner: (layer: Layer, memoMap?: MemoMap | undefined) => Runner = + internal.toRunner diff --git a/packages/effect/src/internal/layer.ts b/packages/effect/src/internal/layer.ts index 46487eb7fa..f65b68e199 100644 --- a/packages/effect/src/internal/layer.ts +++ b/packages/effect/src/internal/layer.ts @@ -1245,108 +1245,102 @@ export const effect_provide = dual< : provideSomeRuntime(self, source as Runtime.Runtime) ) -export const toRunner = , R, RE>( - evaluate: (...args: Args) => Layer.Layer -): Layer.RunnerConstructor => { - function withMemoMap(memoMap: Layer.MemoMap, ...args: Args): Layer.Runner { - const scope = runtime.unsafeRunSyncEffect(fiberRuntime.scopeMake()) - - let runtimeOrEffect: Effect.Effect, RE> | Runtime.Runtime = runtime.unsafeRunSyncEffect( - effect.memoize( - core.tap( - Scope.extend( - toRuntimeWithMemoMap(evaluate(...(args as unknown as Args)), memoMap), - scope - ), - (rt) => { - runtimeOrEffect = rt - } - ) +export const toRunner = ( + layer: Layer.Layer, + memoMap?: Layer.MemoMap +): Layer.Runner => { + memoMap = memoMap ?? unsafeMakeMemoMap() + const scope = runtime.unsafeRunSyncEffect(fiberRuntime.scopeMake()) + + let runtimeOrEffect: Effect.Effect, RE> | Runtime.Runtime = runtime.unsafeRunSyncEffect( + effect.memoize( + core.tap( + Scope.extend( + toRuntimeWithMemoMap(layer, memoMap), + scope + ), + (rt) => { + runtimeOrEffect = rt + } ) ) + ) - function provide(effect: Effect.Effect): Effect.Effect { - if (!core.isEffect(runtimeOrEffect)) { - return provideSomeRuntime(effect, runtimeOrEffect) - } - return core.flatMap( - runtimeOrEffect, - (rt) => - core.withFiberRuntime((fiber) => { - fiber.setFiberRefs(rt.fiberRefs) - fiber._runtimeFlags = rt.runtimeFlags - return core.provideContext(effect, rt.context) - }) - ) + function provide(effect: Effect.Effect): Effect.Effect { + if (!core.isEffect(runtimeOrEffect)) { + return provideSomeRuntime(effect, runtimeOrEffect) } + return core.flatMap( + runtimeOrEffect, + (rt) => + core.withFiberRuntime((fiber) => { + fiber.setFiberRefs(rt.fiberRefs) + fiber._runtimeFlags = rt.runtimeFlags + return core.provideContext(effect, rt.context) + }) + ) + } - function dispose(): Promise { - runtimeOrEffect = core.die("Runner disposed") - return runtime.unsafeRunPromiseEffect(Scope.close(scope, core.exitUnit)) - } + function dispose(): Promise { + runtimeOrEffect = core.die("Runner disposed") + return runtime.unsafeRunPromiseEffect(Scope.close(scope, core.exitUnit)) + } - function runPromise(effect: Effect.Effect): Promise { - return core.isEffect(runtimeOrEffect) - ? runtime.unsafeRunPromiseEffect(provide(effect)) - : runtime.unsafeRunPromise(runtimeOrEffect)(effect) - } + function runPromise(effect: Effect.Effect): Promise { + return core.isEffect(runtimeOrEffect) + ? runtime.unsafeRunPromiseEffect(provide(effect)) + : runtime.unsafeRunPromise(runtimeOrEffect)(effect) + } - return { - memoMap, - [Symbol.asyncDispose]() { - return dispose() - }, - dispose, - runFork(effect: Effect.Effect): Fiber.RuntimeFiber { - return core.isEffect(runtimeOrEffect) - ? runtime.unsafeForkEffect(provide(effect)) - : runtime.unsafeFork(runtimeOrEffect)(effect) - }, - runSync(effect: Effect.Effect): A { - return core.isEffect(runtimeOrEffect) - ? runtime.unsafeRunSyncEffect(provide(effect)) - : runtime.unsafeRunSync(runtimeOrEffect)(effect) - }, - runSyncExit(effect: Effect.Effect): Exit.Exit { - return core.isEffect(runtimeOrEffect) - ? runtime.unsafeRunSyncExitEffect(provide(effect)) - : runtime.unsafeRunSyncExit(runtimeOrEffect)(effect) - }, - runPromise, - runPromiseExit(effect: Effect.Effect): Promise> { - return core.isEffect(runtimeOrEffect) - ? runtime.unsafeRunPromiseExitEffect(provide(effect)) - : runtime.unsafeRunPromiseExit(runtimeOrEffect)(effect) - }, - runPromiseFn< - F extends (...args: Array) => Effect.Effect - >( - fn: F - ): (...args: Parameters) => Promise>> { - return (...args) => runPromise(fn(...args)) - }, - runPromiseService( - tag: Context.Tag, - fn: (service: S) => Effect.Effect - ): Promise { - return runPromise(core.flatMap(tag, (_) => fn(_))) - }, - runPromiseServiceFn< - I extends R, - S, - F extends (...args: Array) => Effect.Effect - >( - tag: Context.Tag, - fn: (service: S) => F - ): (...args: Parameters) => Promise>> { - return (...args) => runPromise(core.flatMap(tag, (_) => fn(_).apply(_, args))) - } + return { + memoMap, + [Symbol.asyncDispose]() { + return dispose() + }, + dispose, + runFork(effect: Effect.Effect): Fiber.RuntimeFiber { + return core.isEffect(runtimeOrEffect) + ? runtime.unsafeForkEffect(provide(effect)) + : runtime.unsafeFork(runtimeOrEffect)(effect) + }, + runSync(effect: Effect.Effect): A { + return core.isEffect(runtimeOrEffect) + ? runtime.unsafeRunSyncEffect(provide(effect)) + : runtime.unsafeRunSync(runtimeOrEffect)(effect) + }, + runSyncExit(effect: Effect.Effect): Exit.Exit { + return core.isEffect(runtimeOrEffect) + ? runtime.unsafeRunSyncExitEffect(provide(effect)) + : runtime.unsafeRunSyncExit(runtimeOrEffect)(effect) + }, + runPromise, + runPromiseExit(effect: Effect.Effect): Promise> { + return core.isEffect(runtimeOrEffect) + ? runtime.unsafeRunPromiseExitEffect(provide(effect)) + : runtime.unsafeRunPromiseExit(runtimeOrEffect)(effect) + }, + runPromiseFn< + F extends (...args: Array) => Effect.Effect + >( + fn: F + ): (...args: Parameters) => Promise>> { + return (...args) => runPromise(fn(...args)) + }, + runPromiseService( + tag: Context.Tag, + fn: (service: S) => Effect.Effect + ): Promise { + return runPromise(core.flatMap(tag, (_) => fn(_))) + }, + runPromiseServiceFn< + I extends R, + S, + F extends (...args: Array) => Effect.Effect + >( + tag: Context.Tag, + fn: (service: S) => F + ): (...args: Parameters) => Promise>> { + return (...args) => runPromise(core.flatMap(tag, (_) => fn(_).apply(_, args))) } } - - return Object.assign(function build(...args: Args): Layer.Runner { - return withMemoMap(unsafeMakeMemoMap(), ...args) - }, { - withMemoMap - }) } diff --git a/packages/effect/test/Layer.test.ts b/packages/effect/test/Layer.test.ts index 57eefd723a..d1bc021c89 100644 --- a/packages/effect/test/Layer.test.ts +++ b/packages/effect/test/Layer.test.ts @@ -709,8 +709,7 @@ describe("Layer", () => { const layer = Layer.effectDiscard(Effect.sync(() => { count++ })) - const Count = Layer.toRunner(() => layer) - const instance = Count() + const instance = Layer.toRunner(layer) await instance.runPromise(Effect.unit) await instance.runPromise(Effect.unit) await instance.dispose() @@ -720,8 +719,7 @@ describe("Layer", () => { test("provides context", async () => { const tag = Context.GenericTag("string") const layer = Layer.succeed(tag, "test") - const Test = Layer.toRunner(() => layer) - const instance = Test() + const instance = Layer.toRunner(layer) const result = await instance.runPromise(tag) await instance.dispose() assert.strictEqual(result, "test") @@ -729,8 +727,7 @@ describe("Layer", () => { test("provides fiberRefs", async () => { const layer = Layer.setRequestCaching(true) - const Test = Layer.toRunner(() => layer) - const instance = Test() + const instance = Layer.toRunner(layer) const result = await instance.runPromise(FiberRef.get(FiberRef.currentRequestCacheEnabled)) await instance.dispose() assert.strictEqual(result, true) @@ -739,8 +736,7 @@ describe("Layer", () => { test("runPromiseService", async () => { const tag = Context.GenericTag("string") const layer = Layer.succeed(tag, "test") - const Test = Layer.toRunner(() => layer) - const instance = Test() + const instance = Layer.toRunner(layer) const result = await instance.runPromiseService(tag, (_) => Effect.succeed(_)) await instance.dispose() assert.strictEqual(result, "test") @@ -749,8 +745,7 @@ describe("Layer", () => { test("runPromiseServiceFn", async () => { const tag = Context.GenericTag<(_: string) => Effect.Effect>("stringFn") const layer = Layer.succeed(tag, Effect.succeed) - const Test = Layer.toRunner(() => layer) - const instance = Test() + const instance = Layer.toRunner(layer) const fn = instance.runPromiseServiceFn(tag, (_) => _) const result = await fn("test") await instance.dispose() @@ -767,9 +762,8 @@ describe("Layer", () => { return "test" }) ) - const Test = Layer.toRunner(() => layer) await (async function() { - await using instance = Test() + await using instance = Layer.toRunner(layer) const result = await instance.runPromise(tag) assert.strictEqual(result, "test") })() @@ -781,9 +775,8 @@ describe("Layer", () => { const layer = Layer.effectDiscard(Effect.sync(() => { count++ })) - const Count = Layer.toRunner(() => layer) - const instanceA = Count() - const instanceB = Count.withMemoMap(instanceA.memoMap) + const instanceA = Layer.toRunner(layer) + const instanceB = Layer.toRunner(layer, instanceA.memoMap) await instanceA.runPromise(Effect.unit) await instanceB.runPromise(Effect.unit) await instanceA.dispose()