// ets_tracing: off import type { Clock } from "../Clock/index.js" import { currentTime } from "../Clock/index.js" import * as Tp from "../Collections/Immutable/Tuple/index.js" import { pipe } from "../Function/index.js" import type { Has } from "../Has/index.js" import * as O from "../Option/index.js" import * as Ref from "../RefM/index.js" import * as core from "./core.js" import * as die from "./die.js" import * as Do from "./do.js" import type { Effect, IO, RIO, UIO } from "./effect.js" import { environment } from "./environment.js" import * as P from "./excl-forEach-promise.js" import * as uninterruptibleMask from "./interruption.js" import * as map from "./map.js" import * as tap from "./tap.js" import * as to from "./to.js" /** * Returns an effect that, if evaluated, will return the cached result of * this effect. Cached results will expire after `timeToLive` duration. In * addition, returns an effect that can be used to invalidate the current * cached value before the `timeToLive` duration expires. * * @ets_data_first cachedInvalidate_ */ export function cachedInvalidate(ttl: number, __trace?: string) { return (fa: Effect) => cachedInvalidate_(fa, ttl) } /** * Returns an effect that, if evaluated, will return the cached result of * this effect. Cached results will expire after `timeToLive` duration. In * addition, returns an effect that can be used to invalidate the current * cached value before the `timeToLive` duration expires. */ export function cachedInvalidate_( fa: Effect, ttl: number, __trace?: string ): RIO, Tp.Tuple<[IO, UIO]>> { return pipe( Do.do, Do.bind("r", () => environment>()), Do.bind("cache", () => Ref.makeRefM]>>>(O.none) ), map.map( ({ cache, r }) => Tp.tuple<[IO, UIO]>( core.provideAll(r)(get(fa, ttl, cache)), invalidate(cache) ), __trace ) ) } function invalidate( cache: Ref.RefM]>>> ) { return cache.set(O.none) } function compute(fa: Effect, ttl: number, start: number) { return pipe( Do.do, Do.bind("p", () => P.make()), tap.tap(({ p }) => to.to(p)(fa)), map.map(({ p }) => O.some(Tp.tuple(start + ttl, p))) ) } function get( fa: Effect, ttl: number, cache: Ref.RefM]>>> ) { return uninterruptibleMask.uninterruptibleMask(({ restore }) => pipe( currentTime, core.chain((time) => pipe( cache, Ref.updateSomeAndGet((o) => pipe( o, O.fold( () => O.some(compute(fa, ttl, time)), ({ tuple: [end] }) => end - time <= 0 ? O.some(compute(fa, ttl, time)) : O.none ) ) ), core.chain((a) => a._tag === "None" ? die.die("bug") : restore(P.await(a.value.get(1))) ) ) ) ) ) }