import { matchTag } from "@principia/prelude/Utils"; import { left, right } from "../../Either"; import { identity, pipe, tuple } from "../../Function"; import type { Option } from "../../Option"; import { none, some } from "../../Option"; import * as Mb from "../../Option"; import * as S from "../Semaphore"; import * as T from "../Task/_core"; import { fold } from "./fold"; import type { XRefM } from "./model"; import { concrete } from "./model"; /** * Atomically modifies the `RefM` with the specified function, which computes * a return value for the modification. This is a more powerful version of * `update`. */ export const modify_ = ( self: XRefM, f: (a: A) => T.Task ): T.Task => pipe( self, concrete, matchTag({ Atomic: (atomic) => pipe( atomic.ref.get, T.chain(f), T.chain(([b, a]) => pipe(atomic.ref.set(a), T.as(b))), S.withPermit(atomic.semaphore) ), Derived: (derived) => pipe( derived.value.ref.get, T.chain((a) => pipe( derived.getEither(a), T.chain(f), T.chain(([b, a]) => pipe( derived.setEither(a), T.chain((a) => derived.value.ref.set(a)), T.as(b) ) ) ) ), S.withPermit(derived.value.semaphore) ), DerivedAll: (derivedAll) => pipe( derivedAll.value.ref.get, T.chain((s) => pipe( derivedAll.getEither(s), T.chain(f), T.chain(([b, a]) => pipe( derivedAll.setEither(a)(s), T.chain((a) => derivedAll.value.ref.set(a)), T.as(b) ) ) ) ), S.withPermit(derivedAll.value.semaphore) ) }) ); /** * Atomically modifies the `RefM` with the specified function, which computes * a return value for the modification. This is a more powerful version of * `update`. */ export const modify = (f: (a: A) => T.Task) => ( self: XRefM ): T.Task => modify_(self, f); /** * Writes a new value to the `RefM`, returning the value immediately before * modification. */ export const getAndSet_ = (self: XRefM, a: A) => pipe( self, modify((v) => T.pure([v, a])) ); /** * Writes a new value to the `RefM`, returning the value immediately before * modification. */ export const getAndSet = (a: A) => (self: XRefM) => getAndSet_(self, a); /** * Atomically modifies the `RefM` with the specified function, returning the * value immediately before modification. */ export const getAndUpdate_ = ( self: XRefM, f: (a: A) => T.Task ) => pipe( self, modify((v) => pipe( f(v), T.map((r) => [v, r]) ) ) ); /** * Atomically modifies the `RefM` with the specified function, returning the * value immediately before modification. */ export const getAndUpdate = (f: (a: A) => T.Task) => ( self: XRefM ) => getAndUpdate_(self, f); /** * Atomically modifies the `RefM` with the specified function, returning the * value immediately before modification. */ export const getAndUpdateSome_ = ( self: XRefM, f: (a: A) => Option> ) => pipe( self, modify((v) => pipe( f(v), Mb.getOrElse(() => T.pure(v)), T.map((r) => [v, r]) ) ) ); /** * Atomically modifies the `RefM` with the specified function, returning the * value immediately before modification. */ export const getAndUpdateSome = (f: (a: A) => Option>) => ( self: XRefM ) => getAndUpdateSome_(self, f); /** * Atomically modifies the `RefM` with the specified function, which computes * a return value for the modification if the function is defined in the current value * otherwise it returns a default value. * This is a more powerful version of `updateSome`. */ export const modifySome_ = ( self: XRefM, def: B, f: (a: A) => Option> ) => pipe( self, modify((v) => pipe( f(v), Mb.getOrElse(() => T.pure(tuple(def, v))) ) ) ); /** * Atomically modifies the `RefM` with the specified function, which computes * a return value for the modification if the function is defined in the current value * otherwise it returns a default value. * This is a more powerful version of `updateSome`. */ export const modifySome = (def: B) => (f: (a: A) => Option>) => ( self: XRefM ) => modifySome_(self, def, f); /** * Atomically modifies the `RefM` with the specified function. */ export const update_ = ( self: XRefM, f: (a: A) => T.Task ): T.Task => pipe( self, modify((v) => pipe( f(v), T.map((r) => [undefined, r]) ) ) ); /** * Atomically modifies the `RefM` with the specified function. */ export const update = (f: (a: A) => T.Task) => ( self: XRefM ): T.Task => update_(self, f); /** * Atomically modifies the `RefM` with the specified function. */ export const updateAndGet_ = ( self: XRefM, f: (a: A) => T.Task ): T.Task => pipe( self, modify((v) => pipe( f(v), T.map((r) => [r, r]) ) ) ); /** * Atomically modifies the `RefM` with the specified function. */ export const updateAndGet = (f: (a: A) => T.Task) => ( self: XRefM ): T.Task => updateAndGet_(self, f); /** * Atomically modifies the `RefM` with the specified function. */ export const updateSome_ = ( self: XRefM, f: (a: A) => Option> ): T.Task => pipe( self, modify((v) => pipe( f(v), Mb.getOrElse(() => T.pure(v)), T.map((r) => [undefined, r]) ) ) ); /** * Atomically modifies the `RefM` with the specified function. */ export const updateSome = (f: (a: A) => Option>) => ( self: XRefM ): T.Task => updateSome_(self, f); /** * Atomically modifies the `RefM` with the specified function. */ export const updateSomeAndGet_ = ( self: XRefM, f: (a: A) => Option> ): T.Task => pipe( self, modify((v) => pipe( f(v), Mb.getOrElse(() => T.pure(v)), T.map((r) => [r, r]) ) ) ); /** * Atomically modifies the `RefM` with the specified function. */ export const updateSomeAndGet = (f: (a: A) => Option>) => ( self: XRefM ): T.Task => updateSomeAndGet_(self, f); /** * Maps and filters the `get` value of the `XRefM` with the specified * effectual partial function, returning a `XRefM` with a `get` value that * succeeds with the result of the partial function if it is defined or else * fails with `None`. */ export const collectM_ = ( self: XRefM, f: (b: B) => Option> ): XRefM, A, C> => self.foldM( identity, (_) => some(_), (_) => T.pure(_), (b) => pipe( f(b), Mb.map((a) => T.asSomeError(a)), Mb.getOrElse(() => T.fail(none())) ) ); /** * Maps and filters the `get` value of the `XRefM` with the specified * effectual partial function, returning a `XRefM` with a `get` value that * succeeds with the result of the partial function if it is defined or else * fails with `None`. */ export const collectM = (f: (b: B) => Option>) => ( self: XRefM ): XRefM, A, C> => collectM_(self, f); /** * Maps and filters the `get` value of the `XRefM` with the specified partial * function, returning a `XRefM` with a `get` value that succeeds with the * result of the partial function if it is defined or else fails with `None`. */ export const collect_ = ( self: XRefM, f: (b: B) => Option ): XRefM, A, C> => pipe( self, collectM((b) => pipe(f(b), Mb.map(T.pure))) ); /** * Maps and filters the `get` value of the `XRefM` with the specified partial * function, returning a `XRefM` with a `get` value that succeeds with the * result of the partial function if it is defined or else fails with `None`. */ export const collect = (f: (b: B) => Option) => ( self: XRefM ): XRefM, A, C> => collect_(self, f); /** * Returns a read only view of the `XRefM`. */ export const readOnly = (self: XRefM): XRefM => self; /** * Returns a read only view of the `XRefM`. */ export const writeOnly = (self: XRefM): XRefM => pipe( self, fold( identity, (): void => undefined, right, () => left(undefined) ) );