import { FanOut } from 'thingies/lib/fanout';
/**
 * Merges multiple fanouts into a single fanout. The merged fanout emits the
 * same data as the source fanouts.
 */
export class MergeFanOut extends FanOut {
    fanouts;
    unsubs = [];
    constructor(fanouts) {
        super();
        this.fanouts = fanouts;
    }
    listen(listener) {
        if (!this.listeners.size)
            this.unsubs = this.fanouts.map((fanout) => fanout.listen((data) => this.emit(data)));
        const unsub = super.listen(listener);
        return () => {
            unsub();
            if (!this.listeners.size) {
                for (const unsub of this.unsubs)
                    unsub();
                this.unsubs = [];
            }
        };
    }
}
/**
 * Buffers data from a fanout and emits the buffered data once per microtask.
 */
export class MicrotaskBufferFanOut extends FanOut {
    source;
    buffer = [];
    unsub = undefined;
    constructor(source) {
        super();
        this.source = source;
    }
    listen(listener) {
        if (!this.unsub) {
            this.unsub = this.source.listen((data) => {
                const buffer = this.buffer;
                if (!buffer.length) {
                    queueMicrotask(() => {
                        this.emit(buffer);
                        this.buffer = [];
                    });
                }
                buffer.push(data);
            });
        }
        const unsub = super.listen(listener);
        return () => {
            unsub();
            if (!this.listeners.size)
                this.clear();
        };
    }
    clear() {
        this.listeners.clear();
        this.buffer = [];
        this.unsub?.();
        this.unsub = undefined;
    }
}
/**
 * Maps the data from a fanout using a mapper function.
 */
export class MapFanOut extends FanOut {
    source;
    mapper;
    constructor(source, mapper) {
        super();
        this.source = source;
        this.mapper = mapper;
    }
    unsub = undefined;
    listen(listener) {
        if (!this.unsub)
            this.unsub = this.source.listen((data) => this.emit(this.mapper(data)));
        const unsub = super.listen(listener);
        return () => {
            unsub();
            if (!this.listeners.size)
                this.clear();
        };
    }
    clear() {
        this.listeners.clear();
        this.unsub?.();
        this.unsub = undefined;
    }
}
/**
 * Emits only when the source fanout emits a new value. The first value is
 * emitted immediately.
 */
export class OnNewFanOut extends FanOut {
    source;
    last;
    unsub = undefined;
    constructor(source, last = undefined) {
        super();
        this.source = source;
        this.last = last;
    }
    listen(listener) {
        if (!this.unsub) {
            this.unsub = this.source.listen((data) => {
                if (this.last !== data)
                    this.emit((this.last = data));
            });
        }
        const unsub = super.listen(listener);
        return () => {
            unsub();
            if (!this.listeners.size)
                this.clear();
        };
    }
    clear() {
        this.listeners.clear();
        this.last = undefined;
        this.unsub?.();
        this.unsub = undefined;
    }
}
//# sourceMappingURL=fanout.js.map