UNPKG

@effect-ts/system

Version:

Effect-TS is a zero dependency set of libraries to write highly productive, purely functional TypeScript at scale.

523 lines (453 loc) 13.7 kB
var _a; import { reduce as chunkReduce } from "../Collections/Immutable/Chunk/api/reduce.mjs"; import { insert } from "../Collections/Immutable/Map/index.mjs"; import * as Tp from "../Collections/Immutable/Tuple/index.mjs"; import { _E, _RIn, _ROut } from "../Effect/commons.mjs"; import { sequential } from "../Effect/ExecutionStrategy.mjs"; import { pipe } from "../Function/index.mjs"; import { chain as managedChain, chain_ as managedChain_, foldCauseM_ as managedFoldCauseM_, map as managedMap, map_ as managedMap_, provideAll_ as managedProvideAll_, provideSome_ as managedProvideSome_, zipWith_ as managedZipWith_, zipWithPar_ as managedZipWithPar_ } from "../Managed/core.mjs"; import { bind as managedBind, do as managedDo } from "../Managed/do.mjs"; import { forEach_ as managedForEach_, forEachPar_ as managedForEachPar_ } from "../Managed/forEach.mjs"; import { fromEffect as managedFromEffect } from "../Managed/fromEffect.mjs"; import { managedApply } from "../Managed/managed.mjs"; import { environment as managedEnvironment } from "../Managed/methods/environment.mjs"; import * as add from "../Managed/ReleaseMap/add.mjs"; import * as Finalizer from "../Managed/ReleaseMap/finalizer.mjs"; import * as makeReleaseMap from "../Managed/ReleaseMap/makeReleaseMap.mjs"; import * as releaseAll from "../Managed/ReleaseMap/releaseAll.mjs"; import { succeed as succeed_1 } from "../Managed/succeed.mjs"; import { use_ } from "../Managed/use.mjs"; import { await as promiseAwait } from "../Promise/await.mjs"; import { halt } from "../Promise/halt.mjs"; import { make } from "../Promise/make.mjs"; import { succeed } from "../Promise/succeed.mjs"; import * as R from "../Ref/index.mjs"; import * as RM from "../RefM/index.mjs"; import { AtomicReference } from "../Support/AtomicReference/index.mjs"; import * as T from "./deps-effect.mjs"; /** * Creates a layer from an effect */ export function fromRawEffect(resource) { return new LayerManaged(managedFromEffect(resource)); } /** * Creates a layer from a function */ export function fromRawFunction(f) { return fromRawEffect(T.access(f)); } /** * Creates a layer from an effectful function */ export function fromRawFunctionM(f) { return fromRawEffect(T.accessM(f)); } /** * Creates a layer from a managed environment */ export function fromRawManaged(resource) { return new LayerManaged(resource); } /** * Constructs a layer that passes along the specified environment as an * output. */ export function identity() { return fromRawManaged(managedEnvironment()); } /** * Merge two Layers in parallel without providing any data to each other * * @param self - first Layer to combine * @param that - second Layer to combine */ export function and_(self, that) { return new LayerZipWithPar(self, that, (l, r) => ({ ...l, ...r })); } /** * Merge two Layers in parallel without providing any data to each other * * @param that - second Layer to combine * @param self - first Layer to combine */ export function and(that) { return self => new LayerZipWithPar(self, that, (l, r) => ({ ...l, ...r })); } /** * Feeds the error or output services of this layer into the input of either * the specified `failure` or `success` layers, resulting in a new layer with * the inputs of this layer, and the error or outputs of the specified layer. */ export function fold(self) { return failure => success => new LayerFold(self, failure, success); } /** * Use `from` to partially provide environment into `to` */ export function using(from) { return to => compose_(from["+++"](identity()), to); } /** * Use `from` to partially provide environment into `to` and merge both */ export function usingAnd(from) { return to => compose_(from["+++"](identity()), to["+++"](identity())); } /** * Compose layers */ export function compose_(from, to) { return fold(from)(fromRawFunctionM(_ => T.halt(_.get(1))))(to); } /** * Compose layers */ export function compose(to) { return from => compose_(from, to); } export const hashSym = /*#__PURE__*/Symbol(); export class Layer { constructor() { this[_a] = new AtomicReference(Symbol()); } /** * Set the hash key for memoization */ setKey(hash) { this[hashSym].set(hash); return this; } [(_a = hashSym, "_I")]() { return this; } /** * Use that Layer to provide data to this */ ["<=<"](that) { return that[">=>"](this); } /** * Use this Layer to provide data to that */ [">=>"](that) { return compose_(this, that); } /** * Use that Layer to partially provide data to this */ ["<<<"](that) { return that[">>>"](this); } [">>>"](that) { return this["+++"](identity())[">=>"](that); } /** * Create a Layer with the data from both Layers, while providing the data from this to that */ [">+>"](that) { return this[">>>"](that["+++"](identity())); } /** * Create a Layer with the data from both Layers, while providing the data from that to this */ ["<+<"](that) { return that[">+>"](this); } /** * Combine both layers in parallel */ ["+++"](from) { return and_(from, this); } /** * Use the layer to provide partial environment to an effect */ use(effect) { return provideSomeLayer(this)(effect); } /** * Use the layer to provide the full environment to an effect */ useAll(effect) { return provideLayer(this)(effect); } /** * Use the layer to provide the full environment to an effect */ get useForever() { return provideLayer(this)(T.never); } } /** * Provides a layer to the given effect */ export function provideSomeLayer(layer) { return self => provideLayer_(self, layer["+++"](identity())); } /** * Provides a layer to the given effect */ export function provideSomeLayer_(self, layer) { return provideLayer_(self, layer["+++"](identity())); } /** * Provides a layer to the given effect */ export function provideLayer_(self, layer) { return use_(build(layer), p => T.provideAll_(self, p)); } /** * Provides a layer to the given effect */ export function provideLayer(layer) { return self => provideLayer_(self, layer); } export class LayerFold extends Layer { constructor(self, failure, success) { super(); this.self = self; this.failure = failure; this.success = success; this._tag = "LayerFold"; } } export class LayerMap extends Layer { constructor(self, f) { super(); this.self = self; this.f = f; this._tag = "LayerMap"; } } export class LayerChain extends Layer { constructor(self, f) { super(); this.self = self; this.f = f; this._tag = "LayerChain"; } } export class LayerFresh extends Layer { constructor(self) { super(); this.self = self; this._tag = "LayerFresh"; } } export class LayerManaged extends Layer { constructor(self) { super(); this.self = self; this._tag = "LayerManaged"; } } export class LayerSuspend extends Layer { constructor(self) { super(); this.self = self; this._tag = "LayerSuspend"; } } export class LayerZipWithPar extends Layer { constructor(self, that, f) { super(); this.self = self; this.that = that; this.f = f; this._tag = "LayerZipWithPar"; } } export class LayerAllPar extends Layer { constructor(layers) { super(); this.layers = layers; this._tag = "LayerAllPar"; } } export class LayerAllSeq extends Layer { constructor(layers) { super(); this.layers = layers; this._tag = "LayerAllSeq"; } } export class LayerZipWithSeq extends Layer { constructor(self, that, f) { super(); this.self = self; this.that = that; this.f = f; this._tag = "LayerZipWithSeq"; } } export function scope(_) { const I = _._I(); switch (I._tag) { case "LayerFresh": { return succeed_1(() => build(I.self)); } case "LayerManaged": { return succeed_1(() => I.self); } case "LayerSuspend": { return succeed_1(memo => memo.getOrElseMemoize(I.self())); } case "LayerMap": { return succeed_1(memo => managedMap_(memo.getOrElseMemoize(I.self), I.f)); } case "LayerChain": { return succeed_1(memo => managedChain_(memo.getOrElseMemoize(I.self), a => memo.getOrElseMemoize(I.f(a)))); } case "LayerZipWithPar": { return succeed_1(memo => managedZipWithPar_(memo.getOrElseMemoize(I.self), memo.getOrElseMemoize(I.that), I.f)); } case "LayerZipWithSeq": { return succeed_1(memo => managedZipWith_(memo.getOrElseMemoize(I.self), memo.getOrElseMemoize(I.that), I.f)); } case "LayerAllPar": { return succeed_1(memo => { return managedMap(chunkReduce({}, (b, a) => ({ ...b, ...a })))(managedForEachPar_(I.layers, memo.getOrElseMemoize)); }); } case "LayerAllSeq": { return succeed_1(memo => { return managedMap(chunkReduce({}, (b, a) => ({ ...b, ...a })))(managedForEach_(I.layers, memo.getOrElseMemoize)); }); } case "LayerFold": { return succeed_1(memo => managedFoldCauseM_(memo.getOrElseMemoize(I.self), e => managedChain(r => managedProvideSome_(memo.getOrElseMemoize(I.failure), () => Tp.tuple(r, e)))(managedFromEffect(T.environment())), r => managedProvideAll_(memo.getOrElseMemoize(I.success), r))); } } } /** * Builds a layer into a managed value. */ export function build(_) { return managedMap(({ value }) => value)(managedBind("value", ({ memoMap, run }) => run(memoMap))(managedBind("run", () => scope(_))(managedBind("memoMap", () => managedFromEffect(makeMemoMap()))(managedDo)))); } /** * Creates a MemoMap */ export function makeMemoMap() { return T.chain_(RM.makeRefM(new Map()), r => T.succeedWith(() => new MemoMap(r))); } /** * A `MemoMap` memoizes dependencies. */ export class MemoMap { constructor(ref) { this.ref = ref; /** * Checks the memo map to see if a dependency exists. If it is, immediately * returns it. Otherwise, obtains the dependency, stores it in the memo map, * and adds a finalizer to the outer `Managed`. */ this.getOrElseMemoize = layer => { return managedApply(T.flatten(RM.modify(m => { const inMap = m.get(layer[hashSym].get); if (inMap) { const { tuple: [acquire, release] } = inMap; const cached = T.accessM(({ tuple: [_, rm] }) => T.map_(T.onExit_(acquire, ex => { switch (ex._tag) { case "Success": { return add.add(release)(rm); } case "Failure": { return T.unit; } } }), x => Tp.tuple(release, x))); return T.succeed(Tp.tuple(cached, m)); } else { return T.map_(T.let_(T.let_(T.bind_(T.bind_(T.bind_(T.do, "observers", () => R.makeRef(0)), "promise", () => make()), "finalizerRef", () => R.makeRef(Finalizer.noopFinalizer)), "resource", ({ finalizerRef, observers, promise }) => T.uninterruptibleMask(({ restore }) => T.map_(T.bind_(T.bind_(T.let_(T.let_(T.bind_(T.do, "env", () => T.environment()), "a", ({ env: { tuple: [a] } }) => a), "outerReleaseMap", ({ env: { tuple: [_, outerReleaseMap] } }) => outerReleaseMap), "innerReleaseMap", () => makeReleaseMap.makeReleaseMap), "tp", ({ a, innerReleaseMap, outerReleaseMap }) => restore(T.chain_(T.result(T.provideAll_(managedChain(_ => _(this))(scope(layer)).effect, Tp.tuple(a, innerReleaseMap))), e => { switch (e._tag) { case "Failure": { return T.chain_(T.chain_(halt(e.cause)(promise), () => releaseAll.releaseAll(e, sequential)(innerReleaseMap)), () => T.halt(e.cause)); } case "Success": { return T.map_(T.tap_(T.bind_(T.tap_(T.tap_(T.do, () => finalizerRef.set(e => T.whenM_(releaseAll.releaseAll(e, sequential)(innerReleaseMap), R.modify_(observers, n => Tp.tuple(n === 1, n - 1))))), () => R.update_(observers, n => n + 1)), "outerFinalizer", () => add.add(e => T.chain_(finalizerRef.get, f => f(e)))(outerReleaseMap)), () => succeed(e.value.get(1))(promise)), ({ outerFinalizer }) => Tp.tuple(outerFinalizer, e.value.get(1))); } } }))), ({ tp }) => tp))), "memoized", ({ finalizerRef, observers, promise }) => Tp.tuple(T.onExit_(promiseAwait(promise), e => { switch (e._tag) { case "Failure": { return T.unit; } case "Success": { return R.update_(observers, n => n + 1); } } }), e => T.chain_(finalizerRef.get, f => f(e)))), ({ memoized, resource }) => Tp.tuple(resource, insert(layer[hashSym].get, memoized)(m))); } })(this.ref))); }; } } /** * Empty layer, useful for init cases */ export const Empty = /*#__PURE__*/new LayerSuspend(() => identity()); //# sourceMappingURL=definitions.mjs.map