import type { AnyRequest, Request } from './Request' import type { HashMap } from '@principia/base/HashMap' import type { _A, _E } from '@principia/base/prelude' import type { URef } from '@principia/base/Ref' import * as E from '@principia/base/Either' import { pipe } from '@principia/base/function' import * as HM from '@principia/base/HashMap' import * as I from '@principia/base/IO' import * as M from '@principia/base/Maybe' import * as Ref from '@principia/base/Ref' import { tuple } from '@principia/base/tuple' export interface Cache { get(request: A): I.FIO, _A>>>> lookup( request: A ): I.UIO, _A>>>, URef, _A>>>>> put(request: A, result: URef, _A>>>): I.UIO } export class DefaultCache implements Cache { constructor(private state: URef>) {} get(request: Request): I.FIO>>> { return pipe( this.state.get, I.map(HM.get(request)), I.get, I.orElseFail(() => undefined) ) } lookup(request: Request): I.UIO>>, URef>>>> { return pipe( Ref.make(M.nothing>()), I.chain((ref) => Ref.modify_(this.state, (map) => pipe( HM.get_(map, request), M.match( () => tuple(E.left(ref), HM.set_(map, request, ref)), (ref) => tuple(E.right(ref), map) ) ) ) ) ) } put(request: Request, result: URef>>): I.UIO { return I.asUnit(Ref.update_(this.state, (m) => HM.set_(m, request, result))) } } export const empty: I.UIO = pipe( Ref.make(HM.makeDefault()), I.map((ref) => new DefaultCache(ref)) )