import { once } from './functional' ; export interface IDisposable { dispose ( ) : void ; } export function isDisposable < E extends object > ( thing ) { return typeof ( < IDisposable > < any > thing ) . dispose === 'function' && ( < IDisposable > < any > thing ) . dispose . length === 0 ; } export function dispose < T extends IDisposable > ( disposable ) ; export function dispose < T extends IDisposable > ( ... disposables ) ; export function dispose < T extends IDisposable > ( disposables ) ; export function dispose < T extends IDisposable > ( first , ... rest ) { if ( Array . isArray ( first ) ) { first . forEach ( d => d && d . dispose ( ) ) ; return [ ] ; } else if ( rest . length === 0 ) { if ( first ) { first . dispose ( ) ; return first ; } return undefined ; } else { dispose ( first ) ; dispose ( rest ) ; return [ ] ; } } export function combinedDisposable ( disposables ) { return { dispose : ( ) => dispose ( disposables ) } ; } export function toDisposable ( fn ) { return { dispose ( ) { fn ( ) ; } } ; } export abstract class Disposable implements IDisposable { static None = Object . freeze < IDisposable > ( { dispose ( ) { } } ) ; protected _toDispose : IDisposable [ ] = [ ] ; protected get toDispose ( ) : IDisposable [ ] { return this . _toDispose ; } private _lifecycle_disposable_isDisposed = false ; public dispose ( ) { this . _lifecycle_disposable_isDisposed = true ; this . _toDispose = dispose ( this . _toDispose ) ; } protected _register < T extends IDisposable > ( t ) { if ( this . _lifecycle_disposable_isDisposed ) { console . warn ( 'Registering disposable on object that has already been disposed.' ) ; t . dispose ( ) ; } else { this . _toDispose . push ( t ) ; } return t ; } } export interface IReference < T > extends IDisposable { readonly object : T ; } export abstract class ReferenceCollection < T > { private references : { [ key ] : { readonly object : T ; counter : number ; } ; } = Object . create ( null ) ; constructor ( ) { } acquire ( key ) { let reference = this . references [ key ] ; if ( ! reference ) { reference = this . references [ key ] = { counter : 0 , object : this . createReferencedObject ( key ) } ; } const { object } = reference ; const dispose = once ( ( ) => { if ( -- reference . counter === 0 ) { this . destroyReferencedObject ( key , reference . object ) ; delete this . references [ key ] ; } } ) ; reference . counter ++ ; return { object , dispose } ; } protected abstract createReferencedObject ( key ) ; protected abstract destroyReferencedObject ( key , object ) ; } export class ImmortalReference < T > implements IReference < T > { constructor ( public object ) { } dispose ( ) { } }