/** * @since 2.0.0 */ import * as Context from "./Context.ts" import * as Effect from "./Effect.ts" import * as Exit from "./Exit.ts" import { identity } from "./Function.ts" import { PipeInspectableProto } from "./internal/core.ts" import type { Pipeable } from "./Pipeable.ts" import { hasProperty } from "./Predicate.ts" import type * as Schedule from "./Schedule.ts" import type * as Scope from "./Scope.ts" import * as ScopedRef from "./ScopedRef.ts" const TypeId = "~effect/Resource" as const /** * A `Resource` is a value loaded into memory that can be refreshed manually or * automatically according to a schedule. * * @since 2.0.0 * @category models */ export interface Resource extends Pipeable { readonly [TypeId]: typeof TypeId readonly scopedRef: ScopedRef.ScopedRef> readonly acquire: Effect.Effect } /** * @since 2.0.0 * @category guards */ export const isResource: (u: unknown) => u is Resource = ( u: unknown ): u is Resource => hasProperty(u, TypeId) const Proto = { ...PipeInspectableProto, [TypeId]: TypeId, toJSON() { return { _id: "Resource" } } } const makeUnsafe = ( scopedRef: ScopedRef.ScopedRef>, acquire: Effect.Effect ): Resource => { const self = Object.create(Proto) self.scopedRef = scopedRef self.acquire = acquire return self } /** * Creates a `Resource` that must be refreshed manually. * * @since 2.0.0 * @category constructors */ export const manual = ( acquire: Effect.Effect ): Effect.Effect, never, Scope.Scope | R> => Effect.contextWith((context: Context.Context) => { const providedAcquire = Effect.updateContext( acquire, (input: Context.Context) => Context.merge(context, input) ) return Effect.map( ScopedRef.fromAcquire(Effect.exit(providedAcquire)), (scopedRef) => makeUnsafe(scopedRef, providedAcquire) ) }) /** * Creates a `Resource` that refreshes automatically according to the supplied * schedule. * * @since 2.0.0 * @category constructors */ export const auto = ( acquire: Effect.Effect, policy: Schedule.Schedule ): Effect.Effect, never, R | R2 | Scope.Scope> => Effect.tap( manual(acquire), (self) => Effect.forkScoped(Effect.repeat(refresh(self), policy)) ) /** * Retrieves the current value stored in this resource. * * @since 2.0.0 * @category getters */ export const get = (self: Resource): Effect.Effect => Effect.flatMap(ScopedRef.get(self.scopedRef), identity) /** * Refreshes this resource. * * @since 2.0.0 * @category utils */ export const refresh = (self: Resource): Effect.Effect => ScopedRef.set(self.scopedRef, Effect.map(self.acquire, Exit.succeed))