diff --git a/.changeset/brown-deers-fry.md b/.changeset/brown-deers-fry.md new file mode 100644 index 0000000..3acb7f3 --- /dev/null +++ b/.changeset/brown-deers-fry.md @@ -0,0 +1,5 @@ +--- +"@effect-rx/rx": minor +--- + +add Rx.context api for building layers diff --git a/docs/rx/Rx.ts.md b/docs/rx/Rx.ts.md index 44fb8e9..eb2b08d 100644 --- a/docs/rx/Rx.ts.md +++ b/docs/rx/Rx.ts.md @@ -24,6 +24,7 @@ Added in v1.0.0 - [withFallback](#withfallback) - [withLabel](#withlabel) - [constructors](#constructors) + - [context](#context) - [family](#family) - [fn](#fn) - [fnSync](#fnsync) @@ -31,7 +32,7 @@ Added in v1.0.0 - [pull](#pull) - [readable](#readable) - [writable](#writable) -- [context](#context) +- [context](#context-1) - [Context (interface)](#context-interface) - [WriteContext (interface)](#writecontext-interface) - [models](#models) @@ -204,6 +205,16 @@ Added in v1.0.0 # constructors +## context + +**Signature** + +```ts +export declare const context: () => (layer: Layer.Layer) => RxRuntime +``` + +Added in v1.0.0 + ## family **Signature** @@ -268,8 +279,6 @@ export declare const make: { create: Rx.Read>, options?: { readonly initialValue?: A | undefined } | undefined ): Rx> - (layer: Layer.Layer): RxRuntime - (create: Rx.Read>): RxRuntime (create: Rx.Read): Rx (initialValue: A): Writable } @@ -590,8 +599,6 @@ export interface RxRuntime extends Rx> - (layer: Layer.Layer): RxRuntime - (create: Rx.Read>): RxRuntime } readonly fn: { diff --git a/packages/rx/src/Rx.ts b/packages/rx/src/Rx.ts index d21661d..80d2323 100644 --- a/packages/rx/src/Rx.ts +++ b/packages/rx/src/Rx.ts @@ -262,9 +262,9 @@ const RxProto = { } return makeEffect( get, - makeStreamPullEffect(get, arg, options, runtimeResult.value[0]), + makeStreamPullEffect(get, arg, options, runtimeResult.value), Result.initial(true), - runtimeResult.value[0] + runtimeResult.value ) }) return makeStreamPull(pullRx as any, options) @@ -339,8 +339,6 @@ export const make: { (create: Rx.Read>, options?: { readonly initialValue?: A }): Rx> - (layer: Layer.Layer): RxRuntime - (create: Rx.Read>): RxRuntime (create: Rx.Read): Rx (initialValue: A): Writable } = (arg: any, options?: { readonly initialValue?: unknown }) => { @@ -358,23 +356,17 @@ export const make: { const makeRead: { (effect: Effect.Effect, options?: { readonly initialValue?: A - }): (get: Context, runtime?: RuntimeTuple) => Result.Result + }): (get: Context, runtime?: Runtime.Runtime) => Result.Result (create: Rx.Read>, options?: { readonly initialValue?: A - }): (get: Context, runtime?: RuntimeTuple) => Result.Result + }): (get: Context, runtime?: Runtime.Runtime) => Result.Result (stream: Stream.Stream, options?: { readonly initialValue?: A - }): (get: Context, runtime?: RuntimeTuple) => Result.Result + }): (get: Context, runtime?: Runtime.Runtime) => Result.Result (create: Rx.Read>, options?: { readonly initialValue?: A - }): (get: Context, runtime?: RuntimeTuple) => Result.Result - ( - layer: Layer.Layer - ): (get: Context, runtime?: RuntimeTuple) => Result.Result - ( - create: Rx.Read> - ): (get: Context, runtime?: RuntimeTuple) => Result.Result - (create: Rx.Read): (get: Context, runtime?: RuntimeTuple) => A + }): (get: Context, runtime?: Runtime.Runtime) => Result.Result + (create: Rx.Read): (get: Context, runtime?: Runtime.Runtime) => A (initialValue: A): Writable } = ( arg: @@ -382,39 +374,31 @@ const makeRead: { | Rx.Read> | Stream.Stream | Rx.Read> - | Layer.Layer - | Rx.Read> | Rx.Read | A, options?: { readonly initialValue?: unknown } ) => { if (typeof arg === "function") { const create = arg as Rx.Read - return function(get: Context, providedRuntime?: RuntimeTuple) { + return function(get: Context, providedRuntime?: Runtime.Runtime) { const value = create(get) if (typeof value === "object" && value !== null) { if (Effect.EffectTypeId in value) { - return effect(get, value, options, providedRuntime ? providedRuntime[0] : undefined) + return effect(get, value, options, providedRuntime) } else if (Stream.StreamTypeId in value) { - return stream(get, value, options, providedRuntime ? providedRuntime[0] : undefined) - } else if (Layer.LayerTypeId in value) { - return runtime(get, value, providedRuntime) + return stream(get, value, options, providedRuntime) } } return value } } else if (typeof arg === "object" && arg !== null) { if (Effect.EffectTypeId in arg) { - return function(get: Context, providedRuntime?: RuntimeTuple) { - return effect(get, arg, options, providedRuntime ? providedRuntime[0] : undefined) + return function(get: Context, providedRuntime?: Runtime.Runtime) { + return effect(get, arg, options, providedRuntime) } } else if (Stream.StreamTypeId in arg) { - return function(get: Context, providedRuntime?: RuntimeTuple) { - return stream(get, arg, options, providedRuntime ? providedRuntime[0] : undefined) - } - } else if (Layer.LayerTypeId in arg) { - return function(get: Context, providedRuntime?: RuntimeTuple) { - return runtime(get, arg, providedRuntime) + return function(get: Context, providedRuntime?: Runtime.Runtime) { + return stream(get, arg, options, providedRuntime) } } } @@ -473,16 +457,14 @@ function makeEffect( } // ----------------------------------------------------------------------------- -// constructors - layer +// context // ----------------------------------------------------------------------------- -type RuntimeTuple = readonly [Runtime.Runtime, Layer.MemoMap] - /** * @since 1.0.0 * @category models */ -export interface RxRuntime extends Rx>> { +export interface RxRuntime extends Rx>> { readonly rx: { (effect: Effect.Effect, options?: { readonly initialValue?: A @@ -496,8 +478,6 @@ export interface RxRuntime extends Rx>> (create: Rx.Read>, options?: { readonly initialValue?: A }): Rx> - (layer: Layer.Layer): RxRuntime - (create: Rx.Read>): RxRuntime } readonly fn: { @@ -515,30 +495,25 @@ export interface RxRuntime extends Rx>> }) => Writable, void> } -const runtime = ( - get: Context, - layer: Layer.Layer, - runtime?: RuntimeTuple -): Result.Result> => { - if (runtime) { - const buildEffect = pipe( - Effect.flatMap(Effect.scope, (scope) => { - return Layer.buildWithMemoMap(layer, runtime[1], scope) - }), - Effect.flatMap((context) => Effect.provide(Effect.runtime(), context)), - Effect.map((rt) => [rt, runtime[1]] as const) - ) - - return effect(get, buildEffect, undefined, runtime[0]) - } - - const buildEffect = Effect.flatMap(Layer.makeMemoMap, (memoMap) => - pipe( - Effect.flatMap(Effect.scope, (scope) => Layer.buildWithMemoMap(layer, memoMap, scope)), - Effect.flatMap((context) => Effect.provide(Effect.runtime(), context)), - Effect.map((rt) => [rt, memoMap] as const) - )) - return effect(get, buildEffect) +/** + * @since 1.0.0 + * @category constructors + */ +export const context: () => (layer: Layer.Layer) => RxRuntime = () => { + const memoMapRx = make(Layer.makeMemoMap) + return (layer: Layer.Layer): RxRuntime => + readable(function(get) { + const memoMapResult = get(memoMapRx) + if (memoMapResult._tag !== "Success") { + return Result.initial(true) + } + const memoMap = memoMapResult.value + const build = Effect.flatMap( + Effect.flatMap(Effect.scope, (scope) => Layer.buildWithMemoMap(layer, memoMap, scope)), + (context) => Effect.provide(Effect.runtime(), context) + ) + return effect(get, build) + }) as any } // ----------------------------------------------------------------------------- @@ -662,16 +637,16 @@ function makeResultFn( ? Result.success(options.initialValue) : Result.initial() - function read(get: Context, runtime?: RuntimeTuple): Result.Result { + function read(get: Context, runtime?: Runtime.Runtime): Result.Result { const [counter, arg] = get(argRx) if (counter === 0) { return initialValue } const value = f(arg, get) if (Effect.EffectTypeId in value) { - return makeEffect(get, value, initialValue, runtime ? runtime[0] : undefined) + return makeEffect(get, value, initialValue, runtime) } - return makeStream(get, value, initialValue, runtime ? runtime[0] : undefined) + return makeStream(get, value, initialValue, runtime) } function write(ctx: WriteContext>, arg: Arg) { ctx.set(argRx, [ctx.get(argRx)[0] + 1, arg]) diff --git a/packages/rx/test/Rx.test.ts b/packages/rx/test/Rx.test.ts index c708a13..2601ada 100644 --- a/packages/rx/test/Rx.test.ts +++ b/packages/rx/test/Rx.test.ts @@ -751,6 +751,8 @@ const CounterLive = Layer.effect( }) }) }) +).pipe( + Layer.provide(BuildCounterLive) ) interface Multiplier { @@ -765,9 +767,13 @@ const MultiplierLive = Layer.effect( times: (n) => Effect.map(counter.get, (_) => _ * n) }) }) +).pipe( + Layer.provideMerge(CounterLive) ) -const buildCounterRuntime = Rx.make(BuildCounterLive) -const counterRuntime = buildCounterRuntime.rx(CounterLive) -const multiplierRuntime = counterRuntime.rx(MultiplierLive.pipe(Layer.provide(CounterLive))) -const fiberRefRuntime = counterRuntime.rx(Layer.setRequestCaching(true)) +const rxContext = Rx.context() + +const buildCounterRuntime = rxContext(BuildCounterLive) +const counterRuntime = rxContext(CounterLive) +const multiplierRuntime = rxContext(MultiplierLive) +const fiberRefRuntime = rxContext(Layer.setRequestCaching(true))