value-cell.ts 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. /** A mutable value reference. */
  7. interface ValueRef<T> { ref: T }
  8. namespace ValueRef {
  9. export function create<T>(ref: T): ValueRef<T> { return { ref }; }
  10. export function set<T>(ref: ValueRef<T>, value: T) { ref.ref = value; return ref; }
  11. }
  12. let _valueBoxId = 0;
  13. function getNextId() {
  14. return _valueBoxId++ % 0x7FFFFFFF;
  15. }
  16. /**
  17. * An immutable value box that also holds a version of the attribute.
  18. * Optionally includes automatically propadated "metadata".
  19. */
  20. type ValueBox<T, D = never> = {
  21. // Unique identifier in the range 0 to 0x7FFFFFFF
  22. readonly id: number,
  23. readonly version: number,
  24. readonly metadata: D,
  25. readonly value: T,
  26. }
  27. namespace ValueBox {
  28. export function create<T, D = never>(value: T, metadata?: D): ValueBox<T, D> {
  29. return { id: getNextId(), version: 0, value, metadata: metadata! };
  30. }
  31. /** The box.metadata is carried over from the old box */
  32. export function withValue<T, D>(box: ValueBox<T, D>, value: T): ValueBox<T, D> {
  33. return { id: box.id, version: box.version + 1, value, metadata: box.metadata };
  34. }
  35. }
  36. /** An immutable box stored inside a mutable cell. */
  37. type ValueCell<T, D = never> = ValueRef<ValueBox<T, D>>
  38. namespace ValueCell {
  39. export function create<T, D = never>(value: T, metadata?: D): ValueCell<T, D> {
  40. return ValueRef.create(ValueBox.create(value, metadata));
  41. }
  42. /** The box.metadata is carried over from the old box */
  43. export function update<T, D>(cell: ValueCell<T, D>, value: T): ValueCell<T, D> {
  44. return ValueRef.set(cell, ValueBox.withValue(cell.ref, value));
  45. }
  46. export function set<T, D>(cell: ValueCell<T, D>, box: ValueBox<T, D>): ValueCell<T, D> {
  47. return ValueRef.set(cell, box);
  48. }
  49. }
  50. export { ValueRef, ValueBox, ValueCell };