"use strict";
var _a, _b;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DropGenerator = exports.DropPromise = exports.Drop = void 0;
const dropId = Symbol('id');
class Drop {
    constructor() {
        this.dropId = Drop.idCtr++;
        this.dropRef = { [dropId]: this.dropId };
        const weak = this.weak();
        Drop.weak[this.dropId] = weak;
        Drop.registry.register(this.dropRef, this.dropId, this.dropRef);
        return new Proxy(this, {
            set(target, prop, value) {
                if (prop === 'dropRef' || prop == 'dropId')
                    return false;
                target[prop] = value;
                weak[prop] = value;
                return true;
            },
        });
    }
    register() { }
    weak() {
        const weak = Object.assign(Object.create(Object.getPrototypeOf(this)), this);
        if (this.dropRef)
            weak.ref = new WeakRef(this.dropRef);
        return weak;
    }
    drop() {
        if (!this.dropRef || !this.dropId)
            return;
        this.onDrop();
        this.leak();
    }
    leak() {
        if (!this.dropRef || !this.dropId)
            return this;
        Drop.registry.unregister(this.dropRef);
        delete Drop.weak[this.dropId];
        delete this.dropRef;
        delete this.dropId;
        return this;
    }
}
exports.Drop = Drop;
Drop.weak = {};
Drop.registry = new FinalizationRegistry((id) => {
    const weak = Drop.weak[id];
    if (weak)
        weak.drop();
});
Drop.idCtr = 0;
class DropPromise {
    constructor(promise, dropFnOrRef) {
        this.promise = promise;
        this[_a] = 'DropPromise';
        if (dropFnOrRef && dropId in dropFnOrRef) {
            this.dropId = dropFnOrRef[dropId];
            this.dropRef = dropFnOrRef;
            return;
        }
        this.dropId = DropPromise.idCtr++;
        this.dropRef = { [dropId]: this.dropId };
        if (dropFnOrRef)
            DropPromise.dropFns[this.dropId] = dropFnOrRef;
        DropPromise.registry.register(this.dropRef, this.dropId, this.dropRef);
    }
    static of(promise, dropFn) {
        return new DropPromise(promise, dropFn);
    }
    static ref(promise, dropRef) {
        return new DropPromise(promise, dropRef);
    }
    then(onfulfilled, onrejected) {
        return DropPromise.ref(this.promise.then(onfulfilled, onrejected), this.dropRef);
    }
    catch(onrejected) {
        return DropPromise.ref(this.promise.catch(onrejected), this.dropRef);
    }
    finally(onfinally) {
        return DropPromise.ref(this.promise.finally(onfinally), this.dropRef);
    }
}
exports.DropPromise = DropPromise;
_a = Symbol.toStringTag;
DropPromise.dropFns = {};
DropPromise.registry = new FinalizationRegistry((id) => {
    const drop = DropPromise.dropFns[id];
    if (drop) {
        drop();
        delete DropPromise.dropFns[id];
    }
});
DropPromise.idCtr = 0;
class DropGenerator {
    constructor(generator, dropFn) {
        this.generator = generator;
        this[_b] = () => this;
        this.dropId = DropGenerator.idCtr++;
        this.dropRef = { [dropId]: this.dropId };
        if (dropFn)
            DropGenerator.dropFns[this.dropId] = dropFn;
        DropGenerator.registry.register(this.dropRef, this.dropId, this.dropRef);
    }
    static of(generator, dropFn) {
        return new DropGenerator(generator, dropFn);
    }
    next(...args) {
        return DropPromise.ref(this.generator.next(...args), this.dropRef);
    }
    return(value) {
        return DropPromise.ref(this.generator.return(value), this.dropRef);
    }
    throw(e) {
        return DropPromise.ref(this.generator.throw(e), this.dropRef);
    }
}
exports.DropGenerator = DropGenerator;
_b = Symbol.asyncIterator;
DropGenerator.dropFns = {};
DropGenerator.registry = new FinalizationRegistry((id) => {
    const drop = DropGenerator.dropFns[id];
    if (drop) {
        drop();
        delete DropGenerator.dropFns[id];
    }
});
DropGenerator.idCtr = 0;
//# sourceMappingURL=Drop.js.map