Add get/set filters to forward state & remove cache

Forwarded states are no longer cached, because caching would have to
happen individually for every attribute and methods combination.
This commit is contained in:
Talia 2024-01-24 09:24:41 +01:00
parent 3f838821e4
commit 38b2127920

View file

@ -121,7 +121,6 @@ export class SimpleState extends EventTarget {
export class State extends SimpleState { export class State extends SimpleState {
#target #target
#shallow #shallow
#forwardCache
static isState(object) { return SimpleState.prototype.isPrototypeOf(object) } static isState(object) { return SimpleState.prototype.isPrototypeOf(object) }
@ -150,18 +149,8 @@ export class State extends SimpleState {
set value(value) { this.values.value = value } set value(value) { this.values.value = value }
get value() { return this.values.value } get value() { return this.values.value }
forward(property="value") { forward(property="value", methods) {
if (!this.#forwardCache) this.#forwardCache = new Map() return new ForwardState(this, property, methods)
const cached = this.#forwardCache.get(property)?.deref()
if (cached) {
return cached
} else {
const forwarded = new ForwardState(this, property)
const ref = new WeakRef(forwarded)
this.#forwardCache.set(property, ref)
forwardFinalizationRegistry.register(forwarded, [this.#forwardCache, property])
return forwarded
}
} }
set(prop, value) { set(prop, value) {
@ -175,26 +164,35 @@ export class State extends SimpleState {
} }
} }
const forwardFinalizationRegistry = new FinalizationRegistry(([cache, name]) => {
cache.remove(name)
})
export class ForwardState extends SimpleState { export class ForwardState extends SimpleState {
#backend #backend
#property #property
#methods
constructor(backend, property) { constructor(backend, property, methods = {}) {
super() super()
this.#methods = methods
this.#backend = backend this.#backend = backend
this.#property = property this.#property = property
const ref = new WeakRef(this) const ref = new WeakRef(this)
const abortController = new AbortController() const abortController = new AbortController()
abortRegistry.register(this, abortController)
backend.addEventListener("change", event => { backend.addEventListener("change", event => {
const state = ref.deref() const state = ref.deref()
if (state) { if (state) {
const relevantChanges = event.changes let relevantChanges = event.changes
.filter(({property: name}) => name === property) .filter(({property: name}) => name === property)
.map(({from, to}) => ({property: "value", from, to})) const get = methods.get
if (methods.get) {
relevantChanges = relevantChanges.map(
({from, to}) => ({property: "value", from: get(from), to: get(to)})
)
} else {
relevantChanges = relevantChanges.map(
({from, to}) => ({property: "value", from, to})
)
}
if (relevantChanges.length > 0) if (relevantChanges.length > 0)
state.dispatchEvent(new ChangeEvent(...relevantChanges)) state.dispatchEvent(new ChangeEvent(...relevantChanges))
} else { } else {
@ -203,8 +201,23 @@ export class ForwardState extends SimpleState {
}, {signal: abortController.signal}) }, {signal: abortController.signal})
} }
get value() { return this.#backend.values[this.#property]} get value() {
set value(value) { this.#backend.values[this.#property] = value } const methods = this.#methods
if (methods.get) {
return methods.get(this.#backend.values[this.#property])
} else {
return this.#backend.values[this.#property]
}
}
set value(value) {
const methods = this.#methods
if (methods.set) {
this.#backend.values[this.#property] = methods.set(value)
} else {
this.#backend.values[this.#property] = value
}
}
} }
class StorageChangeEvent extends Event { class StorageChangeEvent extends Event {