From d4487929ff7c4f076af7833d425f3659952bd413 Mon Sep 17 00:00:00 2001 From: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com> Date: Sun, 19 Jan 2025 16:22:56 -0500 Subject: [PATCH] Progress? --- .../@ember/-internals/metal/lib/storage.ts | 90 +++++++++++++++---- 1 file changed, 73 insertions(+), 17 deletions(-) diff --git a/packages/@ember/-internals/metal/lib/storage.ts b/packages/@ember/-internals/metal/lib/storage.ts index d36db6f6995..5b9eede60f8 100644 --- a/packages/@ember/-internals/metal/lib/storage.ts +++ b/packages/@ember/-internals/metal/lib/storage.ts @@ -1,21 +1,77 @@ -import { trackedData } from '@glimmer/validator'; - -interface Storage { - /** - * This is not a real property. Don't use it. - * This is functioning as a brand-type for use with - * - createStorage - * - getValue - * - setValue - * - * from @glimmer/trcking/primitives/storage - */ - __storage: Value; +import type { UpdatableTag } from '@glimmer/interfaces'; + +import { consumeTag } from './tracking'; +import { createUpdatableTag, DIRTY_TAG } from './validators'; +import { assert } from '@ember/debug'; + +const SET = Symbol.for('TrackedStorage.set'); +const READ = Symbol.for('TrackedStorage.read'); + +function tripleEq(a: Value, b: Value): boolean { + return a === b; +} + +class Storage { + #tag: UpdatableTag; + #value: Value; + #lastValue: Value; + #isEqual: (a: Value, b: Value) => boolean; + + get #current() { + consumeTag(this.#tag); + return this.#value; + } + set #current(value) { + if (this.#isEqual(this.#value, this.#lastValue)) { + return; + } + + this.#value = this.#lastValue = value; + + DIRTY_TAG(this.#tag); + } + + constructor(initialValue: Value, isEqual?: (a: Value, b: Value) => boolean) { + this.#tag = createUpdatableTag(); + this.#value = this.#lastValue = initialValue; + this.#isEqual = isEqual ?? tripleEq; + } + + [READ]() { + return this.#current; + } + + [SET](value: Value) { + this.#current = value; + } } export function createStorage( - initialValue?: Value, + initialValue: Value, isEqual?: (oldValue: Value, newValue: Value) => boolean -): Storage {} -export function getValue(storage: Storage): Value {} -export function setValue(storage: Storage, value: Value): void {} +): Storage { + assert( + 'the second parameter to `createStorage` must be an equality function or undefined', + isEqual === undefined || typeof isEqual === 'function' + ); + + return new Storage(initialValue, isEqual); +} + +export function getValue(storage: Storage): Value { + assert( + 'getValue must be passed a tracked store created with `createStorage`.', + storage instanceof Storage + ); + + return storage[READ](); +} + +export function setValue(storage: Storage, value: Value): void { + assert( + 'setValue must be passed a tracked store created with `createStorage`.', + storage instanceof Storage + ); + + storage[SET](value); +}