import { ILifetimeSlot } from "../typings/interfaces"; import { isDestroyable } from "./traits"; const _destroy = (item: unknown) => () => isDestroyable(item) && item.destroy(); enum State { New, Initialized, Destroyed } export class LifetimeSlot implements ILifetimeSlot { private _value: NonNullable | undefined = undefined; private _state = State.New; cleanup: () => void; readonly remove: () => void; constructor(remove: () => void) { this.remove = this._finalizer(remove); this.cleanup = this._finalizer(() => { }); } has(): boolean { this._assertNotDisposed(); return this._value !== undefined; } get(): NonNullable { this._assertNotDisposed(); if (this._value === undefined) throw new Error("The slot doesn't have a value"); return this._value; } initialize(): boolean { return this._state === State.New ? (this._state = State.Initialized, true) : false; } store(item: NonNullable, cleanup: ((item: NonNullable) => void) | undefined = _destroy): void { this._assertNotDisposed(); this._value = item; if (cleanup) this.cleanup = this._finalizer(() => cleanup(item)); } private _finalizer(cb: () => void) { return () => this._state !== State.Destroyed ? (this._state = State.Destroyed, cb()) : void (0); } private _assertNotDisposed() { if (this._state === State.Destroyed) throw new Error("The slot is disposed"); } }