import * as Context from "../Context.js" import type * as Effect from "../Effect.js" import type { LazyArg } from "../Function.js" import { dual, pipe } from "../Function.js" import type * as Scope from "../Scope.js" import type * as ScopedRef from "../ScopedRef.js" import * as core from "./core.js" import * as circular from "./effect/circular.js" import * as effectable from "./effectable.js" import * as fiberRuntime from "./fiberRuntime.js" import * as ref from "./ref.js" import * as synchronized from "./synchronizedRef.js" /** @internal */ const ScopedRefSymbolKey = "effect/ScopedRef" /** @internal */ export const ScopedRefTypeId: ScopedRef.ScopedRefTypeId = Symbol.for( ScopedRefSymbolKey ) as ScopedRef.ScopedRefTypeId /** @internal */ const scopedRefVariance = { /* c8 ignore next */ _A: (_: any) => _ } /** @internal */ const proto: ThisType> = { ...effectable.CommitPrototype, commit() { return get(this) }, [ScopedRefTypeId]: scopedRefVariance } /** @internal */ const close = (self: ScopedRef.ScopedRef): Effect.Effect => core.flatMap(ref.get(self.ref), (tuple) => tuple[0].close(core.exitVoid)) /** @internal */ export const fromAcquire = ( acquire: Effect.Effect ): Effect.Effect, E, R | Scope.Scope> => core.uninterruptible( fiberRuntime.scopeMake().pipe(core.flatMap((newScope) => acquire.pipe( core.mapInputContext(Context.add(fiberRuntime.scopeTag, newScope)), core.onError((cause) => newScope.close(core.exitFail(cause))), core.flatMap((value) => circular.makeSynchronized([newScope, value] as const).pipe( core.flatMap((ref) => { const scopedRef = Object.create(proto) scopedRef.ref = ref return pipe( fiberRuntime.addFinalizer(() => close(scopedRef)), core.as(scopedRef) ) }) ) ) ) )) ) /** @internal */ export const get = (self: ScopedRef.ScopedRef): Effect.Effect => core.map(ref.get(self.ref), (tuple) => tuple[1]) /** @internal */ export const make = (evaluate: LazyArg): Effect.Effect, never, Scope.Scope> => fromAcquire(core.sync(evaluate)) /** @internal */ export const set = dual< ( acquire: Effect.Effect ) => (self: ScopedRef.ScopedRef) => Effect.Effect>, ( self: ScopedRef.ScopedRef, acquire: Effect.Effect ) => Effect.Effect> >(2, ( self: ScopedRef.ScopedRef, acquire: Effect.Effect ) => core.flatten( synchronized.modifyEffect(self.ref, ([oldScope, value]) => core.uninterruptible( core.scopeClose(oldScope, core.exitVoid).pipe( core.zipRight(fiberRuntime.scopeMake()), core.flatMap((newScope) => core.exit(fiberRuntime.scopeExtend(acquire, newScope)).pipe( core.flatMap((exit) => core.exitMatch(exit, { onFailure: (cause) => core.scopeClose(newScope, core.exitVoid).pipe( core.as( [ core.failCause(cause) as Effect.Effect, [oldScope, value] as const ] as const ) ), onSuccess: (value) => core.succeed( [ core.void as Effect.Effect, [newScope, value] as const ] as const ) }) ) ) ) ) )) ))