2025-01-07 02:58:12 +11:00
|
|
|
// deno-lint-ignore-file no-explicit-any
|
|
|
|
import { jit } from "./jit.ts";
|
|
|
|
|
|
|
|
export class Emitter<F extends (...args: any) => void> {
|
|
|
|
#ls: { f: F; once: boolean }[] = [];
|
|
|
|
#argc = 0;
|
|
|
|
|
|
|
|
get argc() {
|
|
|
|
return this.#argc;
|
|
|
|
}
|
|
|
|
|
|
|
|
get size() {
|
|
|
|
return this.#ls.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
this.emit = this.#emit_fast;
|
|
|
|
}
|
|
|
|
|
|
|
|
on(f: F, once: boolean) {
|
|
|
|
this.#ls.push({ f, once });
|
|
|
|
this.#argc = Math.max(this.#argc, f.length);
|
|
|
|
|
|
|
|
if (once) this.emit = this.#emit_slow;
|
|
|
|
else this.#emit_fast = this.#compile();
|
|
|
|
if (this.emit !== this.#emit_slow) this.emit = this.#emit_fast;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
off(f: F) {
|
|
|
|
const ls = this.#ls;
|
|
|
|
let once = false;
|
|
|
|
|
|
|
|
for (let i = ls.length; i-- !== 0; ) {
|
|
|
|
if (ls[i].f === f) {
|
|
|
|
(once = ls[i].once), ls.splice(i, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.#argc = ls.length ? Math.max(...ls.map(({ f }) => f.length)) : 0;
|
|
|
|
if (!once) this.#emit_fast = this.#compile();
|
|
|
|
if (this.emit !== this.#emit_slow) this.emit = this.#emit_fast;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// deno-lint-ignore no-unused-vars
|
|
|
|
emit(...args: Parameters<F>) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
listeners() {
|
|
|
|
return this.#ls.map(({ f }) => f);
|
|
|
|
}
|
|
|
|
|
|
|
|
#emit_fast = this.#compile();
|
|
|
|
#emit_slow(...args: Parameters<F>) {
|
|
|
|
const ls = this.#ls;
|
|
|
|
(this.#ls = ls.filter(({ once }) => !once)), (this.emit = this.#emit_fast);
|
|
|
|
|
|
|
|
for (let i = 0, n = ls.length; i < n; i++)
|
|
|
|
Reflect.apply(ls[i].f, undefined, args);
|
|
|
|
|
|
|
|
return ls.length !== 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#compile(): typeof this.emit {
|
|
|
|
const ls = this.#ls.filter(({ once }) => !once);
|
|
|
|
const ps = [...Array(this.#argc).keys()].map((i) => jit.raw`a${i}`);
|
|
|
|
|
|
|
|
return jit.compiled`function emit(${jit.fragment(", ", ...ps)}) {
|
|
|
|
${jit.map(" ", ls, ({ f }) => {
|
|
|
|
return jit`${f}(${jit.fragment(", ", ...ps.slice(0, f.length))});`;
|
|
|
|
})}
|
|
|
|
return ${jit.literal(ls.length !== 0)};
|
|
|
|
}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export type EventMap = Record<string | symbol, (...args: any) => void>;
|
|
|
|
|
|
|
|
export class TypedEmitter<T extends EventMap> {
|
|
|
|
readonly #events: { [K in keyof T]?: Emitter<T[K]> } = Object.create(null);
|
|
|
|
|
|
|
|
on<K extends keyof T>(name: K, f: T[K]) {
|
|
|
|
return (this.#events[name] ??= new Emitter()).on(f, false), this;
|
|
|
|
}
|
|
|
|
|
|
|
|
once<K extends keyof T>(name: K, f: T[K]) {
|
|
|
|
return (this.#events[name] ??= new Emitter()).on(f, true), this;
|
|
|
|
}
|
|
|
|
|
|
|
|
off<K extends keyof T>(name: K, f: T[K]) {
|
|
|
|
const events = this.#events;
|
|
|
|
if (events[name]?.off(f).size === 0) delete events[name];
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit<K extends keyof T>(name: K, ...args: Parameters<T[K]>) {
|
|
|
|
const event = this.#events[name];
|
|
|
|
if (event) return event.emit.apply(event, args);
|
|
|
|
else return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
listeners<K extends keyof T>(name: K) {
|
|
|
|
return this.#events[name]?.listeners() ?? [];
|
|
|
|
}
|
|
|
|
|
|
|
|
static {
|
|
|
|
this.prototype.emit = function emit(
|
|
|
|
this: TypedEmitter<EventMap>,
|
|
|
|
name: string,
|
|
|
|
a: any,
|
|
|
|
b: any,
|
|
|
|
c: any,
|
|
|
|
d: any,
|
2025-01-07 03:13:13 +11:00
|
|
|
e: any,
|
2025-01-07 02:58:12 +11:00
|
|
|
) {
|
|
|
|
const event = this.#events[name];
|
|
|
|
if (!event) return false;
|
|
|
|
|
|
|
|
const { argc } = event;
|
|
|
|
if (argc < 6) {
|
|
|
|
return event.emit(a, b, c, d, e);
|
|
|
|
} else {
|
|
|
|
const args = Array(argc);
|
|
|
|
for (let i = 0; i < argc; i++) args[i] = arguments[i + 1];
|
|
|
|
return event.emit.apply(undefined, args);
|
|
|
|
}
|
|
|
|
} as any;
|
|
|
|
}
|
|
|
|
}
|