LifetimeManager.ts
142 lines
| 4.0 KiB
| video/mp2t
|
TypeScriptLexer
|
|
r129 | import { IDestroyable, MapOf } from "../interfaces"; | ||
| import { argumentNotNull, isDestroyable } from "../safe"; | ||||
|
|
r130 | import { ILifetimeManager, ILifetime } from "./interfaces"; | ||
| import { ActivationContext } from "./ActivationContext"; | ||||
|
|
r129 | |||
| function safeCall(item: () => void) { | ||||
| try { | ||||
| item(); | ||||
| } catch { | ||||
|
|
r131 | // silence! | ||
|
|
r129 | } | ||
| } | ||||
|
|
r131 | const emptyLifetime: ILifetime = { | ||
| has() { | ||||
| return false; | ||||
| }, | ||||
| enter() { | ||||
| }, | ||||
| get() { | ||||
| throw new Error("The specified item isn't registered with this lifetime manager"); | ||||
| }, | ||||
| store() { | ||||
| // does nothing | ||||
| } | ||||
| }; | ||||
|
|
r129 | export class LifetimeManager implements IDestroyable, ILifetimeManager { | ||
| private _cleanup: (() => void)[] = []; | ||||
| private _cache: MapOf<any> = {}; | ||||
| private _destroyed = false; | ||||
|
|
r132 | private _pending: MapOf<boolean> = {}; | ||
|
|
r131 | initialize(id: string): ILifetime { | ||
|
|
r130 | const self = this; | ||
| return { | ||||
| has() { | ||||
| return (id in self._cache); | ||||
| }, | ||||
| get() { | ||||
| const t = self._cache[id]; | ||||
| if (t === undefined) | ||||
| throw new Error(`The item with with the key ${id} isn't found`); | ||||
| return t; | ||||
| }, | ||||
|
|
r129 | |||
|
|
r130 | enter() { | ||
|
|
r132 | if (self._pending[id]) | ||
|
|
r130 | throw Error(`Cyclic reference detected: the item with the key ${id} is already activating.`); | ||
|
|
r132 | self._pending[id] = true; | ||
|
|
r130 | }, | ||
| store(item: any, cleanup?: (item: any) => void) { | ||||
| argumentNotNull(id, "id"); | ||||
| argumentNotNull(item, "item"); | ||||
| if (this.has()) | ||||
| throw new Error(`The item with with the key ${id} already registered with this lifetime manager`); | ||||
|
|
r132 | delete self._pending[id]; | ||
|
|
r130 | |||
| self._cache[id] = item; | ||||
| if (self._destroyed) | ||||
| throw new Error("Lifetime manager is destroyed"); | ||||
| if (cleanup) { | ||||
| self._cleanup.push(() => cleanup(item)); | ||||
| } else if (isDestroyable(item)) { | ||||
| self._cleanup.push(() => item.destroy()); | ||||
| } | ||||
| } | ||||
| }; | ||||
|
|
r129 | } | ||
| destroy() { | ||||
| if (!this._destroyed) { | ||||
| this._destroyed = true; | ||||
| this._cleanup.forEach(safeCall); | ||||
| this._cleanup.length = 0; | ||||
| } | ||||
| } | ||||
| static readonly empty: ILifetimeManager = { | ||||
|
|
r131 | initialize(): ILifetime { | ||
| return emptyLifetime; | ||||
|
|
r129 | }, | ||
|
|
r131 | destroy() { | ||
| throw new Error("Trying to destroy empty lifetime manager, this is a bug."); | ||||
| } | ||||
| }; | ||||
| static readonly hierarchyLifetime: ILifetimeManager = { | ||||
| initialize(id: string, context: ActivationContext<any>): ILifetime { | ||||
| return context.getContainer().getLifetimeManager().initialize(id, context); | ||||
| }, | ||||
| destroy() { | ||||
| throw new Error("Trying to destroy hierarchy lifetime manager, this is a bug."); | ||||
| } | ||||
| }; | ||||
|
|
r129 | |||
|
|
r131 | static readonly singletonLifetime: ILifetimeManager = { | ||
| initialize(id: string): ILifetime { | ||||
| return singletonLifetimeManager.initialize(id); | ||||
|
|
r129 | }, | ||
|
|
r131 | destroy() { | ||
| throw new Error("Trying to destroy singleton lifetime manager, this is a bug."); | ||||
| } | ||||
| }; | ||||
|
|
r129 | |||
|
|
r131 | static readonly contextLifetime: ILifetimeManager = { | ||
| initialize(id: string, context: ActivationContext<any>): ILifetime { | ||||
| return { | ||||
| enter() { | ||||
| if (context.visit(id)) | ||||
| throw new Error("Cyclic reference detected"); | ||||
| }, | ||||
| get() { | ||||
| return context.get(id); | ||||
| }, | ||||
| has() { | ||||
| return context.has(id); | ||||
| }, | ||||
| store(item: any) { | ||||
| context.store(id, item); | ||||
| } | ||||
| }; | ||||
|
|
r129 | }, | ||
| destroy() { | ||||
| throw new Error("Trying to destroy empty lifetime manager, this is a bug."); | ||||
| } | ||||
| }; | ||||
| } | ||||
|
|
r131 | |||
| const singletonLifetimeManager = new LifetimeManager(); | ||||
