UNPKG

veffect

Version:

powerful TypeScript validation library built on the robust foundation of Effect combining exceptional type safety, high performance, and developer experience. Taking inspiration from Effect's functional principles, VEffect delivers a balanced approach tha

145 lines (130 loc) 3.87 kB
import { equals } from "../../Equal.js" import type * as FiberId from "../../FiberId.js" import type * as FiberRefs from "../../FiberRefs.js" import type * as FiberRefsPatch from "../../FiberRefsPatch.js" import { dual } from "../../Function.js" import * as Arr from "../../ReadonlyArray.js" import * as _fiberRefs from "../fiberRefs.js" /** @internal */ export const OP_EMPTY = "Empty" as const /** @internal */ export type OP_EMPTY = typeof OP_EMPTY /** @internal */ export const OP_ADD = "Add" as const /** @internal */ export type OP_ADD = typeof OP_ADD /** @internal */ export const OP_REMOVE = "Remove" as const /** @internal */ export type OP_REMOVE = typeof OP_REMOVE /** @internal */ export const OP_UPDATE = "Update" as const /** @internal */ export type OP_UPDATE = typeof OP_UPDATE /** @internal */ export const OP_AND_THEN = "AndThen" as const /** @internal */ export type OP_AND_THEN = typeof OP_AND_THEN /** @internal */ export const empty: FiberRefsPatch.FiberRefsPatch = ({ _tag: OP_EMPTY }) as FiberRefsPatch.FiberRefsPatch /** @internal */ export const diff = ( oldValue: FiberRefs.FiberRefs, newValue: FiberRefs.FiberRefs ): FiberRefsPatch.FiberRefsPatch => { const missingLocals = new Map(oldValue.locals) let patch = empty for (const [fiberRef, pairs] of newValue.locals.entries()) { const newValue = Arr.headNonEmpty(pairs)[1] const old = missingLocals.get(fiberRef) if (old !== undefined) { const oldValue = Arr.headNonEmpty(old)[1] if (!equals(oldValue, newValue)) { patch = combine({ _tag: OP_UPDATE, fiberRef, patch: fiberRef.diff(oldValue, newValue) })(patch) } } else { patch = combine({ _tag: OP_ADD, fiberRef, value: newValue })(patch) } missingLocals.delete(fiberRef) } for (const [fiberRef] of missingLocals.entries()) { patch = combine({ _tag: OP_REMOVE, fiberRef })(patch) } return patch } /** @internal */ export const combine = dual< (that: FiberRefsPatch.FiberRefsPatch) => (self: FiberRefsPatch.FiberRefsPatch) => FiberRefsPatch.FiberRefsPatch, (self: FiberRefsPatch.FiberRefsPatch, that: FiberRefsPatch.FiberRefsPatch) => FiberRefsPatch.FiberRefsPatch >(2, (self, that) => ({ _tag: OP_AND_THEN, first: self, second: that })) /** @internal */ export const patch = dual< ( fiberId: FiberId.Runtime, oldValue: FiberRefs.FiberRefs ) => (self: FiberRefsPatch.FiberRefsPatch) => FiberRefs.FiberRefs, ( self: FiberRefsPatch.FiberRefsPatch, fiberId: FiberId.Runtime, oldValue: FiberRefs.FiberRefs ) => FiberRefs.FiberRefs >(3, (self, fiberId, oldValue) => { let fiberRefs: FiberRefs.FiberRefs = oldValue let patches: ReadonlyArray<FiberRefsPatch.FiberRefsPatch> = Arr.of(self) while (Arr.isNonEmptyReadonlyArray(patches)) { const head = Arr.headNonEmpty(patches) const tail = Arr.tailNonEmpty(patches) switch (head._tag) { case OP_EMPTY: { patches = tail break } case OP_ADD: { fiberRefs = _fiberRefs.updateAs(fiberRefs, { fiberId, fiberRef: head.fiberRef, value: head.value }) patches = tail break } case OP_REMOVE: { fiberRefs = _fiberRefs.delete_(fiberRefs, head.fiberRef) patches = tail break } case OP_UPDATE: { const value = _fiberRefs.getOrDefault(fiberRefs, head.fiberRef) fiberRefs = _fiberRefs.updateAs(fiberRefs, { fiberId, fiberRef: head.fiberRef, value: head.fiberRef.patch(head.patch)(value) }) patches = tail break } case OP_AND_THEN: { patches = Arr.prepend(head.first)(Arr.prepend(head.second)(tail)) break } } } return fiberRefs })