/** * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal */ /** A mutable value reference. */ interface ValueRef { ref: T } namespace ValueRef { export function create(ref: T): ValueRef { return { ref }; } export function set(ref: ValueRef, value: T) { ref.ref = value; return ref; } } let _valueBoxId = 0; function getNextId() { return _valueBoxId++ % 0x7FFFFFFF; } /** * An immutable value box that also holds a version of the attribute. * Optionally includes automatically propadated "metadata". */ type ValueBox = { // Unique identifier in the range 0 to 0x7FFFFFFF readonly id: number, readonly version: number, readonly metadata: D, readonly value: T, } namespace ValueBox { export function create(value: T, metadata?: D): ValueBox { return { id: getNextId(), version: 0, value, metadata: metadata! }; } /** The box.metadata is carried over from the old box */ export function withValue(box: ValueBox, value: T): ValueBox { return { id: box.id, version: box.version + 1, value, metadata: box.metadata }; } } /** An immutable box stored inside a mutable cell. */ type ValueCell = ValueRef> namespace ValueCell { export function create(value: T, metadata?: D): ValueCell { return ValueRef.create(ValueBox.create(value, metadata)); } /** The box.metadata is carried over from the old box */ export function update(cell: ValueCell, value: T): ValueCell { return ValueRef.set(cell, ValueBox.withValue(cell.ref, value)); } export function set(cell: ValueCell, box: ValueBox): ValueCell { return ValueRef.set(cell, box); } } export { ValueRef, ValueBox, ValueCell };