/** * @since 1.0.0 */ import * as Equal from "@effect/data/Equal" import * as Dual from "@effect/data/Function" import { type Inspectable, NodeInspectSymbol, toJSON, toString } from "@effect/data/Inspectable" import type { Pipeable } from "@effect/data/Pipeable" import { pipeArguments } from "@effect/data/Pipeable" const TypeId: unique symbol = Symbol.for("@effect/data/MutableRef") as TypeId /** * @since 1.0.0 * @category symbol */ export type TypeId = typeof TypeId /** * @since 1.0.0 * @category models */ export interface MutableRef extends Pipeable, Inspectable { readonly [TypeId]: TypeId /** @internal */ current: T } const MutableRefProto: Omit, "current"> = { [TypeId]: TypeId, toString(this: MutableRef): string { return toString(this.toJSON()) }, toJSON(this: MutableRef) { return { _id: "MutableRef", current: toJSON(this.current) } }, [NodeInspectSymbol]() { return this.toJSON() }, pipe() { return pipeArguments(this, arguments) } } /** * @since 1.0.0 * @category constructors */ export const make = (value: T): MutableRef => { const ref = Object.create(MutableRefProto) ref.current = value return ref } /** * @since 1.0.0 * @category general */ export const compareAndSet: { (oldValue: T, newValue: T): (self: MutableRef) => boolean (self: MutableRef, oldValue: T, newValue: T): boolean } = Dual.dual< (oldValue: T, newValue: T) => (self: MutableRef) => boolean, (self: MutableRef, oldValue: T, newValue: T) => boolean >(3, (self, oldValue, newValue) => { if (Equal.equals(oldValue, self.current)) { self.current = newValue return true } return false }) /** * @since 1.0.0 * @category numeric */ export const decrement = (self: MutableRef): MutableRef => update(self, (n) => n - 1) /** * @since 1.0.0 * @category numeric */ export const decrementAndGet = (self: MutableRef): number => updateAndGet(self, (n) => n - 1) /** * @since 1.0.0 * @category general */ export const get = (self: MutableRef): T => self.current /** * @since 1.0.0 * @category numeric */ export const getAndDecrement = (self: MutableRef): number => getAndUpdate(self, (n) => n - 1) /** * @since 1.0.0 * @category numeric */ export const getAndIncrement = (self: MutableRef): number => getAndUpdate(self, (n) => n + 1) /** * @since 1.0.0 * @category general */ export const getAndSet: { (value: T): (self: MutableRef) => T (self: MutableRef, value: T): T } = Dual.dual< (value: T) => (self: MutableRef) => T, (self: MutableRef, value: T) => T >(2, (self, value) => { const ret = self.current self.current = value return ret }) /** * @since 1.0.0 * @category general */ export const getAndUpdate: { (f: (value: T) => T): (self: MutableRef) => T (self: MutableRef, f: (value: T) => T): T } = Dual.dual< (f: (value: T) => T) => (self: MutableRef) => T, (self: MutableRef, f: (value: T) => T) => T >(2, (self, f) => getAndSet(self, f(get(self)))) /** * @since 1.0.0 * @category numeric */ export const increment = (self: MutableRef): MutableRef => update(self, (n) => n + 1) /** * @since 1.0.0 * @category numeric */ export const incrementAndGet = (self: MutableRef): number => updateAndGet(self, (n) => n + 1) /** * @since 1.0.0 * @category general */ export const set: { (value: T): (self: MutableRef) => MutableRef (self: MutableRef, value: T): MutableRef } = Dual.dual< (value: T) => (self: MutableRef) => MutableRef, (self: MutableRef, value: T) => MutableRef >(2, (self, value) => { self.current = value return self }) /** * @since 1.0.0 * @category general */ export const setAndGet: { (value: T): (self: MutableRef) => T (self: MutableRef, value: T): T } = Dual.dual< (value: T) => (self: MutableRef) => T, (self: MutableRef, value: T) => T >(2, (self, value) => { self.current = value return self.current }) /** * @since 1.0.0 * @category general */ export const update: { (f: (value: T) => T): (self: MutableRef) => MutableRef (self: MutableRef, f: (value: T) => T): MutableRef } = Dual.dual< (f: (value: T) => T) => (self: MutableRef) => MutableRef, (self: MutableRef, f: (value: T) => T) => MutableRef >(2, (self, f) => set(self, f(get(self)))) /** * @since 1.0.0 * @category general */ export const updateAndGet: { (f: (value: T) => T): (self: MutableRef) => T (self: MutableRef, f: (value: T) => T): T } = Dual.dual< (f: (value: T) => T) => (self: MutableRef) => T, (self: MutableRef, f: (value: T) => T) => T >(2, (self, f) => setAndGet(self, f(get(self)))) /** * @since 1.0.0 * @category boolean */ export const toggle = (self: MutableRef): MutableRef => update(self, (_) => !_)