rc-js-util
Version:
A collection of TS and C++ utilities to help writing performant and correct applications, achieved through strict typing and (removable) invariant checking.
88 lines (75 loc) • 2.76 kB
text/typescript
import { TListener } from "./t-listener.js";
import { IBroadcastChannel } from "./i-broadcast-channel.js";
import { DirtyCheckedUniqueCollection } from "../collection/dirty-checked-unique-collection.js";
import type { ICleanupRegistry } from "../lifecycle/cleanup-registry.js";
/**
* @public
* Strong reference implementation of {@link IBroadcastChannel}.
*/
export class BroadcastChannel<TKey extends string, TArgs extends unknown[]>
implements IBroadcastChannel<TKey, TArgs>
{
public constructor
(
private key: TKey,
)
{
}
public addListener(listener: TListener<TKey, TArgs>): void;
public addListener(store: ICleanupRegistry, listener: TListener<TKey, TArgs>): void;
public addListener(maybeStore: ICleanupRegistry | TListener<TKey, TArgs>, listener?: TListener<TKey, TArgs>): void
{
if (listener == null)
{
// no store was supplied
listener = maybeStore as TListener<TKey, TArgs>;
}
else
{
// we have both args
(maybeStore as ICleanupRegistry).registerCleanup(() => this.removeListener(listener as TListener<TKey, TArgs>));
}
this.listeners.add(listener);
}
public addOneTimeListener(listener: TListener<TKey, TArgs>): void;
public addOneTimeListener(store: ICleanupRegistry, listener: TListener<TKey, TArgs>): void;
public addOneTimeListener(maybeStore: ICleanupRegistry | TListener<TKey, TArgs>, listener?: TListener<TKey, TArgs>): void
{
const hasStore = listener != null;
if (listener == null)
{
// no store was supplied
listener = maybeStore as TListener<TKey, TArgs>;
}
const temporaryListener = {
[]: (...args: TArgs) =>
{
this.removeListener(temporaryListener);
return listener[this.key](...args);
}
} as TListener<TKey, TArgs>;
this.addListener(temporaryListener);
if (hasStore)
{
(maybeStore as ICleanupRegistry).registerCleanup(() => this.removeListener(temporaryListener));
}
}
public removeListener(listener: TListener<TKey, TArgs>): void
{
this.listeners.delete(listener);
}
public emit(...args: TArgs): void
{
const listeners = this.listeners.getArray();
const key = this.key;
for (let i = 0, iEnd = listeners.length; i < iEnd; i++)
{
listeners[i][key](...args);
}
}
public getTargets(): readonly TListener<TKey, TArgs>[]
{
return this.listeners.getArray();
}
private readonly listeners = new DirtyCheckedUniqueCollection<TListener<TKey, TArgs>>();
}