Skip to content

Commit

Permalink
remove RunnerConstructor
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim Smart committed Mar 7, 2024
1 parent 3a4e1f9 commit e264434
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 128 deletions.
4 changes: 1 addition & 3 deletions .changeset/famous-mugs-attack.md
Original file line number Diff line number Diff line change
Expand Up @@ -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!")
);
Expand Down
18 changes: 3 additions & 15 deletions packages/effect/src/Layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1078,15 +1078,6 @@ export const buildWithMemoMap: {
// runner
// -----------------------------------------------------------------------------

/**
* @since 2.0.0
* @category runner
*/
export interface RunnerConstructor<Args extends ReadonlyArray<any>, R, E> {
(...args: Args): Runner<R, E>
readonly withMemoMap: (memoMap: MemoMap, ...args: Args) => Runner<R, E>
}

/**
* @since 2.0.0
* @category runner
Expand Down Expand Up @@ -1139,16 +1130,13 @@ export interface Runner<R, RE> 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: <Args extends ReadonlyArray<any>, R, RE>(
evaluate: (...args: Args) => Layer<R, RE, never>
) => RunnerConstructor<Args, R, RE> = internal.toRunner
export const toRunner: <R, RE>(layer: Layer<R, RE, never>, memoMap?: MemoMap | undefined) => Runner<R, RE> =
internal.toRunner
184 changes: 89 additions & 95 deletions packages/effect/src/internal/layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1245,108 +1245,102 @@ export const effect_provide = dual<
: provideSomeRuntime(self, source as Runtime.Runtime<ROut>)
)

export const toRunner = <Args extends ReadonlyArray<any>, R, RE>(
evaluate: (...args: Args) => Layer.Layer<R, RE, never>
): Layer.RunnerConstructor<Args, R, RE> => {
function withMemoMap(memoMap: Layer.MemoMap, ...args: Args): Layer.Runner<R, RE> {
const scope = runtime.unsafeRunSyncEffect(fiberRuntime.scopeMake())

let runtimeOrEffect: Effect.Effect<Runtime.Runtime<R>, RE> | Runtime.Runtime<R> = runtime.unsafeRunSyncEffect(
effect.memoize(
core.tap(
Scope.extend(
toRuntimeWithMemoMap(evaluate(...(args as unknown as Args)), memoMap),
scope
),
(rt) => {
runtimeOrEffect = rt
}
)
export const toRunner = <R, RE>(
layer: Layer.Layer<R, RE, never>,
memoMap?: Layer.MemoMap
): Layer.Runner<R, RE> => {
memoMap = memoMap ?? unsafeMakeMemoMap()
const scope = runtime.unsafeRunSyncEffect(fiberRuntime.scopeMake())

let runtimeOrEffect: Effect.Effect<Runtime.Runtime<R>, RE> | Runtime.Runtime<R> = runtime.unsafeRunSyncEffect(
effect.memoize(
core.tap(
Scope.extend(
toRuntimeWithMemoMap(layer, memoMap),
scope
),
(rt) => {
runtimeOrEffect = rt
}
)
)
)

function provide<A, E>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | RE> {
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<A, E>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | RE> {
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<void> {
runtimeOrEffect = core.die("Runner disposed")
return runtime.unsafeRunPromiseEffect(Scope.close(scope, core.exitUnit))
}
function dispose(): Promise<void> {
runtimeOrEffect = core.die("Runner disposed")
return runtime.unsafeRunPromiseEffect(Scope.close(scope, core.exitUnit))
}

function runPromise<E, A>(effect: Effect.Effect<A, E, R>): Promise<A> {
return core.isEffect(runtimeOrEffect)
? runtime.unsafeRunPromiseEffect(provide(effect))
: runtime.unsafeRunPromise(runtimeOrEffect)(effect)
}
function runPromise<E, A>(effect: Effect.Effect<A, E, R>): Promise<A> {
return core.isEffect(runtimeOrEffect)
? runtime.unsafeRunPromiseEffect(provide(effect))
: runtime.unsafeRunPromise(runtimeOrEffect)(effect)
}

return {
memoMap,
[Symbol.asyncDispose]() {
return dispose()
},
dispose,
runFork<E, A>(effect: Effect.Effect<A, E, R>): Fiber.RuntimeFiber<A, E | RE> {
return core.isEffect(runtimeOrEffect)
? runtime.unsafeForkEffect(provide(effect))
: runtime.unsafeFork(runtimeOrEffect)(effect)
},
runSync<A, E>(effect: Effect.Effect<A, E, R>): A {
return core.isEffect(runtimeOrEffect)
? runtime.unsafeRunSyncEffect(provide(effect))
: runtime.unsafeRunSync(runtimeOrEffect)(effect)
},
runSyncExit<A, E>(effect: Effect.Effect<A, E, R>): Exit.Exit<A, E | RE> {
return core.isEffect(runtimeOrEffect)
? runtime.unsafeRunSyncExitEffect(provide(effect))
: runtime.unsafeRunSyncExit(runtimeOrEffect)(effect)
},
runPromise,
runPromiseExit<E, A>(effect: Effect.Effect<A, E, R>): Promise<Exit.Exit<A, E | RE>> {
return core.isEffect(runtimeOrEffect)
? runtime.unsafeRunPromiseExitEffect(provide(effect))
: runtime.unsafeRunPromiseExit(runtimeOrEffect)(effect)
},
runPromiseFn<
F extends (...args: Array<any>) => Effect.Effect<any, any, R>
>(
fn: F
): (...args: Parameters<F>) => Promise<Effect.Effect.Success<ReturnType<F>>> {
return (...args) => runPromise(fn(...args))
},
runPromiseService<I extends R, S, A, E>(
tag: Context.Tag<I, S>,
fn: (service: S) => Effect.Effect<A, E, R>
): Promise<A> {
return runPromise(core.flatMap(tag, (_) => fn(_)))
},
runPromiseServiceFn<
I extends R,
S,
F extends (...args: Array<any>) => Effect.Effect<any, any, R>
>(
tag: Context.Tag<I, S>,
fn: (service: S) => F
): (...args: Parameters<F>) => Promise<Effect.Effect.Success<ReturnType<F>>> {
return (...args) => runPromise(core.flatMap(tag, (_) => fn(_).apply(_, args)))
}
return {
memoMap,
[Symbol.asyncDispose]() {
return dispose()
},
dispose,
runFork<E, A>(effect: Effect.Effect<A, E, R>): Fiber.RuntimeFiber<A, E | RE> {
return core.isEffect(runtimeOrEffect)
? runtime.unsafeForkEffect(provide(effect))
: runtime.unsafeFork(runtimeOrEffect)(effect)
},
runSync<A, E>(effect: Effect.Effect<A, E, R>): A {
return core.isEffect(runtimeOrEffect)
? runtime.unsafeRunSyncEffect(provide(effect))
: runtime.unsafeRunSync(runtimeOrEffect)(effect)
},
runSyncExit<A, E>(effect: Effect.Effect<A, E, R>): Exit.Exit<A, E | RE> {
return core.isEffect(runtimeOrEffect)
? runtime.unsafeRunSyncExitEffect(provide(effect))
: runtime.unsafeRunSyncExit(runtimeOrEffect)(effect)
},
runPromise,
runPromiseExit<E, A>(effect: Effect.Effect<A, E, R>): Promise<Exit.Exit<A, E | RE>> {
return core.isEffect(runtimeOrEffect)
? runtime.unsafeRunPromiseExitEffect(provide(effect))
: runtime.unsafeRunPromiseExit(runtimeOrEffect)(effect)
},
runPromiseFn<
F extends (...args: Array<any>) => Effect.Effect<any, any, R>
>(
fn: F
): (...args: Parameters<F>) => Promise<Effect.Effect.Success<ReturnType<F>>> {
return (...args) => runPromise(fn(...args))
},
runPromiseService<I extends R, S, A, E>(
tag: Context.Tag<I, S>,
fn: (service: S) => Effect.Effect<A, E, R>
): Promise<A> {
return runPromise(core.flatMap(tag, (_) => fn(_)))
},
runPromiseServiceFn<
I extends R,
S,
F extends (...args: Array<any>) => Effect.Effect<any, any, R>
>(
tag: Context.Tag<I, S>,
fn: (service: S) => F
): (...args: Parameters<F>) => Promise<Effect.Effect.Success<ReturnType<F>>> {
return (...args) => runPromise(core.flatMap(tag, (_) => fn(_).apply(_, args)))
}
}

return Object.assign(function build(...args: Args): Layer.Runner<R, RE> {
return withMemoMap(unsafeMakeMemoMap(), ...args)
}, {
withMemoMap
})
}
23 changes: 8 additions & 15 deletions packages/effect/test/Layer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -720,17 +719,15 @@ describe("Layer", () => {
test("provides context", async () => {
const tag = Context.GenericTag<string>("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")
})

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)
Expand All @@ -739,8 +736,7 @@ describe("Layer", () => {
test("runPromiseService", async () => {
const tag = Context.GenericTag<string>("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")
Expand All @@ -749,8 +745,7 @@ describe("Layer", () => {
test("runPromiseServiceFn", async () => {
const tag = Context.GenericTag<(_: string) => Effect.Effect<string>>("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()
Expand All @@ -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")
})()
Expand All @@ -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()
Expand Down

0 comments on commit e264434

Please sign in to comment.