Skip to content

Commit

Permalink
move to methods
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-smart committed Mar 8, 2024
1 parent dcf7365 commit 6e87576
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 199 deletions.
5 changes: 2 additions & 3 deletions .changeset/famous-mugs-attack.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ class Notifications extends Effect.Tag("Notifications")<

async function main() {
const runtime = ManagedRuntime.make(Notifications.Live);
const runPromise = ManagedRuntime.runPromise(runtime);
await runPromise(Notifications.notify("Hello, world!"));
await ManagedRuntime.dispose(runtime);
await runtime.runPromise(Notifications.notify("Hello, world!"));
await runtime.dispose();
}

main();
Expand Down
175 changes: 71 additions & 104 deletions packages/effect/src/ManagedRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,76 @@ import type * as Runtime from "./Runtime.js"
* @since 2.0.0
* @category models
*/
export interface ManagedRuntime<in R, out E> extends Pipeable {
export interface ManagedRuntime<in R, out ER> extends Pipeable {
readonly memoMap: Layer.MemoMap
readonly runtime: Effect.Effect<Runtime.Runtime<R>, E>
readonly runtimeEffect: Effect.Effect<Runtime.Runtime<R>, ER>
readonly runtime: () => Promise<Runtime.Runtime<R>>

/**
* Executes the effect using the provided Scheduler or using the global
* Scheduler if not provided
*/
readonly runFork: <A, E>(
self: Effect.Effect<A, E, R>,
options?: Runtime.RunForkOptions
) => Fiber.RuntimeFiber<A, E | ER>

/**
* Executes the effect synchronously returning the exit.
*
* This method is effectful and should only be invoked at the edges of your
* program.
*/
readonly runSyncExit: <A, E>(effect: Effect.Effect<A, E, R>) => Exit.Exit<A, ER | E>

/**
* Executes the effect synchronously throwing in case of errors or async boundaries.
*
* This method is effectful and should only be invoked at the edges of your
* program.
*/
readonly runSync: <A, E>(effect: Effect.Effect<A, E, R>) => A

/**
* Executes the effect asynchronously, eventually passing the exit value to
* the specified callback.
*
* This method is effectful and should only be invoked at the edges of your
* program.
*/
readonly runCallback: <A, E>(
effect: Effect.Effect<A, E, R>,
options?: Runtime.RunCallbackOptions<A, E | ER> | undefined
) => Runtime.Cancel<A, E | ER>

/**
* Runs the `Effect`, returning a JavaScript `Promise` that will be resolved
* with the value of the effect once the effect has been executed, or will be
* rejected with the first error or exception throw by the effect.
*
* This method is effectful and should only be used at the edges of your
* program.
*/
readonly runPromise: <A, E>(effect: Effect.Effect<A, E, R>) => Promise<A>

/**
* Runs the `Effect`, returning a JavaScript `Promise` that will be resolved
* with the `Exit` state of the effect once the effect has been executed.
*
* This method is effectful and should only be used at the edges of your
* program.
*/
readonly runPromiseExit: <A, E>(effect: Effect.Effect<A, E, R>) => Promise<Exit.Exit<A, ER | E>>

/**
* Dispose of the resources associated with the runtime.
*/
readonly dispose: () => Promise<void>

/**
* Dispose of the resources associated with the runtime.
*/
readonly disposeEffect: Effect.Effect<void, never, never>
}

/**
Expand All @@ -36,9 +103,8 @@ export interface ManagedRuntime<in R, out E> extends Pipeable {
*
* async function main() {
* const runtime = ManagedRuntime.make(Notifications.Live)
* const runPromise = ManagedRuntime.runPromise(runtime)
* await runPromise(Notifications.notify("Hello, world!"))
* await ManagedRuntime.dispose(runtime)
* await runtime.runPromise(Notifications.notify("Hello, world!"))
* await runtime.dispose()
* }
*
* main()
Expand All @@ -47,102 +113,3 @@ export const make: <R, E>(
layer: Layer.Layer<R, E, never>,
memoMap?: Layer.MemoMap | undefined
) => ManagedRuntime<R, E> = internal.make

/**
* Executes the effect using the provided Scheduler or using the global
* Scheduler if not provided
*
* @since 2.0.0
* @category execution
*/
export const runFork: <R, ER>(
runtime: ManagedRuntime<R, ER>
) => <A, E>(self: Effect.Effect<A, E, R>, options?: Runtime.RunForkOptions) => Fiber.RuntimeFiber<A, E | ER> =
internal.runFork

/**
* Executes the effect synchronously returning the exit.
*
* This method is effectful and should only be invoked at the edges of your
* program.
*
* @since 2.0.0
* @category execution
*/
export const runSyncExit: <R, ER>(
self: ManagedRuntime<R, ER>
) => <A, E>(effect: Effect.Effect<A, E, R>) => Exit.Exit<A, ER | E> = internal.runSyncExit

/**
* Executes the effect synchronously throwing in case of errors or async boundaries.
*
* This method is effectful and should only be invoked at the edges of your
* program.
*
* @since 2.0.0
* @category execution
*/
export const runSync: <R, ER>(self: ManagedRuntime<R, ER>) => <A, E>(effect: Effect.Effect<A, E, R>) => A =
internal.runSync

/**
* Executes the effect asynchronously, eventually passing the exit value to
* the specified callback.
*
* This method is effectful and should only be invoked at the edges of your
* program.
*
* @since 2.0.0
* @category execution
*/
export const runCallback: <R, ER>(
runtime: ManagedRuntime<R, ER>
) => <A, E>(
effect: Effect.Effect<A, E, R>,
options?: Runtime.RunCallbackOptions<A, E | ER> | undefined
) => Runtime.Cancel<A, E | ER> = internal.runCallback

/**
* Runs the `Effect`, returning a JavaScript `Promise` that will be resolved
* with the value of the effect once the effect has been executed, or will be
* rejected with the first error or exception throw by the effect.
*
* This method is effectful and should only be used at the edges of your
* program.
*
* @since 2.0.0
* @category execution
*/
export const runPromise: <R, ER>(self: ManagedRuntime<R, ER>) => <A, E>(effect: Effect.Effect<A, E, R>) => Promise<A> =
internal.runPromise

/**
* Runs the `Effect`, returning a JavaScript `Promise` that will be resolved
* with the `Exit` state of the effect once the effect has been executed.
*
* This method is effectful and should only be used at the edges of your
* program.
*
* @since 2.0.0
* @category execution
*/
export const runPromiseExit: <R, ER>(
self: ManagedRuntime<R, ER>
) => <A, E>(effect: Effect.Effect<A, E, R>) => Promise<Exit.Exit<A, ER | E>> = internal.runPromiseExit

/**
* Dispose of the resources associated with the runtime.
*
* @since 2.0.0
* @category finalization
*/
export const dispose: <R, E>(self: ManagedRuntime<R, E>) => Promise<void> = internal.dispose

/**
* Dispose of the resources associated with the runtime.
*
* @since 2.0.0
* @category finalization
*/
export const disposeEffect: <R, E>(self: ManagedRuntime<R, E>) => Effect.Effect<void, never, never> =
internal.disposeEffect
130 changes: 52 additions & 78 deletions packages/effect/src/internal/managedRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function provide<R, ER, A, E>(
effect: Effect.Effect<A, E, R>
): Effect.Effect<A, E | ER> {
return core.flatMap(
managed.runtime,
managed.runtimeEffect,
(rt) =>
core.withFiberRuntime((fiber) => {
fiber.setFiberRefs(rt.fiberRefs)
Expand All @@ -33,16 +33,16 @@ function provide<R, ER, A, E>(
}

/** @internal */
export const make = <R, E>(
layer: Layer.Layer<R, E, never>,
export const make = <R, ER>(
layer: Layer.Layer<R, ER, never>,
memoMap?: Layer.MemoMap
): ManagedRuntime<R, E> => {
): ManagedRuntime<R, ER> => {
memoMap = memoMap ?? internalLayer.unsafeMakeMemoMap()
const scope = internalRuntime.unsafeRunSyncEffect(fiberRuntime.scopeMake())
const self: ManagedRuntimeImpl<R, E> = {
const self: ManagedRuntimeImpl<R, ER> = {
memoMap,
scope,
runtime: internalRuntime
runtimeEffect: internalRuntime
.unsafeRunSyncEffect(
effect.memoize(
core.tap(
Expand All @@ -59,79 +59,53 @@ export const make = <R, E>(
cachedRuntime: undefined,
pipe() {
return pipeArguments(this, arguments)
},
runtime() {
return self.cachedRuntime === undefined ?
internalRuntime.unsafeRunPromiseEffect(self.runtimeEffect) :
Promise.resolve(self.cachedRuntime)
},
dispose(): Promise<void> {
return internalRuntime.unsafeRunPromiseEffect(self.disposeEffect)
},
disposeEffect: core.suspend(() => {
;(self as any).runtime = core.die("ManagedRuntime disposed")
self.cachedRuntime = undefined
return Scope.close(self.scope, core.exitUnit)
}),
runFork<A, E>(effect: Effect.Effect<A, E, R>, options?: Runtime.RunForkOptions): Fiber.RuntimeFiber<A, E | ER> {
return self.cachedRuntime === undefined ?
internalRuntime.unsafeForkEffect(provide(self, effect), options) :
internalRuntime.unsafeFork(self.cachedRuntime)(effect, options)
},
runSyncExit<A, E>(effect: Effect.Effect<A, E, R>): Exit<A, E | ER> {
return self.cachedRuntime === undefined ?
internalRuntime.unsafeRunSyncExitEffect(provide(self, effect)) :
internalRuntime.unsafeRunSyncExit(self.cachedRuntime)(effect)
},
runSync<A, E>(effect: Effect.Effect<A, E, R>): A {
return self.cachedRuntime === undefined ?
internalRuntime.unsafeRunSyncEffect(provide(self, effect)) :
internalRuntime.unsafeRunSync(self.cachedRuntime)(effect)
},
runPromiseExit<A, E>(effect: Effect.Effect<A, E, R>): Promise<Exit<A, E | ER>> {
return self.cachedRuntime === undefined ?
internalRuntime.unsafeRunPromiseExitEffect(provide(self, effect)) :
internalRuntime.unsafeRunPromiseExit(self.cachedRuntime)(effect)
},
runCallback<A, E>(
effect: Effect.Effect<A, E, R>,
options?: Runtime.RunCallbackOptions<A, E | ER> | undefined
): Runtime.Cancel<A, E | ER> {
return self.cachedRuntime === undefined ?
internalRuntime.unsafeRunCallback(internalRuntime.defaultRuntime)(provide(self, effect), options) :
internalRuntime.unsafeRunCallback(self.cachedRuntime)(effect, options)
},
runPromise<A, E>(effect: Effect.Effect<A, E, R>): Promise<A> {
return self.cachedRuntime === undefined ?
internalRuntime.unsafeRunPromiseEffect(provide(self, effect)) :
internalRuntime.unsafeRunPromise(self.cachedRuntime)(effect)
}
}
return self
}

/** @internal */
export const dispose = <R, E>(self: ManagedRuntime<R, E>): Promise<void> =>
internalRuntime.unsafeRunPromiseEffect(disposeEffect(self))

/** @internal */
export const disposeEffect = <R, E>(self: ManagedRuntime<R, E>): Effect.Effect<void> =>
core.suspend(() => {
const impl = self as ManagedRuntimeImpl<R, E>
;(self as any).runtime = core.die("ManagedRuntime disposed")
impl.cachedRuntime = undefined
return Scope.close(impl.scope, core.exitUnit)
})

/** @internal */
export const runFork =
<R, ER>(self: ManagedRuntime<R, ER>) =>
<A, E>(effect: Effect.Effect<A, E, R>, options?: Runtime.RunForkOptions): Fiber.RuntimeFiber<A, E | ER> => {
const impl = self as ManagedRuntimeImpl<R, ER>
return impl.cachedRuntime === undefined ?
internalRuntime.unsafeForkEffect(provide(impl, effect), options) :
internalRuntime.unsafeFork(impl.cachedRuntime)(effect, options)
}

/** @internal */
export const runSyncExit =
<R, ER>(self: ManagedRuntime<R, ER>) => <A, E>(effect: Effect.Effect<A, E, R>): Exit<A, E | ER> => {
const impl = self as ManagedRuntimeImpl<R, ER>
return impl.cachedRuntime === undefined ?
internalRuntime.unsafeRunSyncExitEffect(provide(impl, effect)) :
internalRuntime.unsafeRunSyncExit(impl.cachedRuntime)(effect)
}

/** @internal */
export const runSync = <R, ER>(self: ManagedRuntime<R, ER>) => <A, E>(effect: Effect.Effect<A, E, R>): A => {
const impl = self as ManagedRuntimeImpl<R, ER>
return impl.cachedRuntime === undefined ?
internalRuntime.unsafeRunSyncEffect(provide(impl, effect)) :
internalRuntime.unsafeRunSync(impl.cachedRuntime)(effect)
}

/** @internal */
export const runPromiseExit =
<R, ER>(self: ManagedRuntime<R, ER>) => <A, E>(effect: Effect.Effect<A, E, R>): Promise<Exit<A, E | ER>> => {
const impl = self as ManagedRuntimeImpl<R, ER>
return impl.cachedRuntime === undefined ?
internalRuntime.unsafeRunPromiseExitEffect(provide(impl, effect)) :
internalRuntime.unsafeRunPromiseExit(impl.cachedRuntime)(effect)
}

/** @internal */
export const runCallback = <R, ER>(
runtime: ManagedRuntime<R, ER>
) =>
<A, E>(
effect: Effect.Effect<A, E, R>,
options?: Runtime.RunCallbackOptions<A, E | ER> | undefined
): Runtime.Cancel<A, E | ER> => {
const impl = runtime as ManagedRuntimeImpl<R, ER>
return impl.cachedRuntime === undefined ?
internalRuntime.unsafeRunCallback(internalRuntime.defaultRuntime)(provide(impl, effect), options) :
internalRuntime.unsafeRunCallback(impl.cachedRuntime)(effect, options)
}

/** @internal */
export const runPromise =
<R, ER>(self: ManagedRuntime<R, ER>) => <A, E>(effect: Effect.Effect<A, E, R>): Promise<A> => {
const impl = self as ManagedRuntimeImpl<R, ER>
return impl.cachedRuntime === undefined ?
internalRuntime.unsafeRunPromiseEffect(provide(impl, effect)) :
internalRuntime.unsafeRunPromise(impl.cachedRuntime)(effect)
}
Loading

0 comments on commit 6e87576

Please sign in to comment.