import { Eq, EqMap, EqSet } from "../collections"; import { equals } from "../equals"; export class Subscriptions { private readonly onAdded: Subscriptions.OnAdded; private readonly onRemoved: Subscriptions.OnRemoved; private readonly eq: Eq; private readonly currentSubs: EqMap; constructor( onAdded: Subscriptions.OnAdded, onRemoved: Subscriptions.OnRemoved, eq: Eq = equals, ) { this.onAdded = onAdded; this.onRemoved = onRemoved; this.eq = eq; this.currentSubs = new EqMap(this.eq); } public update(s: ReadonlyArray) { const currentSubs = this.currentSubs; const nextSubs = new EqSet(this.eq, s); // Removed const removed = currentSubs.entries().filter(([currentSub, _currentSubState]) => !nextSubs.has(currentSub)); for (const [currentSub, currentSubState] of removed) { currentSubs.delete(currentSub); this.onRemoved(currentSub, currentSubState, currentSubs.size); } // Added const added = nextSubs.values().filter((nextSub) => !currentSubs.has(nextSub)); for (const nextSub of added) { const nextSubState = this.onAdded(nextSub, currentSubs.size); this.currentSubs.set(nextSub, nextSubState); } } public forEach(callback: (sub: Sub, subState: SubState) => void) { for (const [sub, subState] of this.currentSubs.entries()) { callback(sub, subState); } } } export namespace Subscriptions { export type OnAdded = (sub: Value, currentSubscriptionsCount: number) => State; export type OnRemoved = (sub: Value, state: State, remainingSubscriptionsCount: number) => void; }