@byloth/core
Version:
An unopinionated collection of useful functions and classes that I use widely in all my projects. 🔧
220 lines (201 loc) • 5.43 kB
text/typescript
import Publisher from "../callbacks/publisher.js";
import type { Callback } from "../types.js";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import type MapView from "./map-view.js";
interface SetViewEventsMap<T>
{
"add": (value: T) => void;
"remove": (value: T) => void;
"clear": () => void;
}
/**
* A wrapper class around the native {@link Set} class that provides additional functionality
* for publishing events when entries are added, removed or the collection is cleared.
* There's also a complementary class that works with the native `Map` class.
* See also {@link MapView}.
*
* ---
*
* @example
* ```ts
* const set = new SetView<number>();
*
* set.onAdd((value: number) => console.log(`Added ${value}`));
* set.add(42); // "Added 42"
* ```
*
* ---
*
* @template T The type of the values in the set.
*/
export default class SetView<T> extends Set<T>
{
/**
* The internal {@link Publisher} instance used to publish events.
*/
protected readonly _publisher: Publisher<SetViewEventsMap<T>>;
/**
* Initializes a new instance of the {@link SetView} class.
*
* ---
*
* @example
* ```ts
* const set = new SetView<number>([2, 4, 8]);
* ```
*
* ---
*
* @param iterable An optional iterable of values to initialize the {@link Set} with.
*/
public constructor(iterable?: Iterable<T> | null)
{
super();
this._publisher = new Publisher();
if (iterable)
{
for (const value of iterable) { this.add(value); }
}
}
/**
* Appends a new element with a specified value to the end of the {@link Set}.
* If the value already exists, it will not be added again.
*
* ---
*
* @example
* ```ts
* const set = new SetView<number>();
* set.add(2)
* .add(4)
* .add(8);
*
* console.log(set); // SetView(4) { 2, 4, 8 }
* ```
*
* ---
*
* @param value The value to add.
*
* @returns The current instance of the {@link SetView} class.
*/
public override add(value: T): this
{
super.add(value);
this._publisher.publish("add", value);
return this;
}
/**
* Removes the specified value from the {@link Set}.
*
* ---
*
* @example
* ```ts
* const set = new SetView<number>([2, 4, 8]);
* set.delete(4); // true
* set.delete(16); // false
*
* console.log(set); // SetView(2) { 2, 8 }
* ```
*
* ---
*
* @param value The value to remove.
*
* @returns `true` if the entry existed and has been removed; otherwise `false` if the entry doesn't exist.
*/
public override delete(value: T): boolean
{
const result = super.delete(value);
if (result) { this._publisher.publish("remove", value); }
return result;
}
/**
* Removes all entries from the {@link Set}.
*
* ---
*
* @example
* ```ts
* const set = new SetView<number>([2, 4, 8]);
* set.clear();
*
* console.log(set); // SetView(0) { }
* ```
*/
public override clear(): void
{
const size = this.size;
super.clear();
if (size > 0) { this._publisher.publish("clear"); }
}
/**
* Subscribes to the `add` event of the set with a callback that will be executed when a value is added.
*
* ---
*
* @example
* ```ts
* set.onAdd((value) => console.log(`Added ${value}`));
*
* set.add(2); // "Added 2"
* set.add(42); // "Added 42"
* ```
*
* ---
*
* @param callback The callback that will be executed when a value is added to the set.
*
* @returns A function that can be used to unsubscribe from the event.
*/
public onAdd(callback: (value: T) => void): Callback
{
return this._publisher.subscribe("add", callback);
}
/**
* Subscribes to the `remove` event of the set with a callback that will be executed when a value is removed.
*
* ---
*
* @example
* ```ts
* set.onRemove((value) => console.log(`Removed ${value}`));
*
* set.delete(2); // "Removed 2"
* set.delete(42); // "Removed 42"
* ```
*
* ---
*
* @param callback The callback that will be executed when a value is removed from the set.
*
* @returns A function that can be used to unsubscribe from the event.
*/
public onRemove(callback: (value: T) => void): Callback
{
return this._publisher.subscribe("remove", callback);
}
/**
* Subscribes to the `clear` event of the set with a callback that will be executed when the set is cleared.
*
* ---
*
* @example
* ```ts
* set.onClear(() => console.log("The set has all been cleared."));
* set.clear(); // "The set has all been cleared."
* ```
*
* ---
*
* @param callback The callback that will be executed when the set is cleared.
*
* @returns A function that can be used to unsubscribe from the event.
*/
public onClear(callback: () => void): Callback
{
return this._publisher.subscribe("clear", callback);
}
public override readonly [Symbol.toStringTag]: string = "SetView";
}