namespace Leaf { export type LifeOwner = { events?: Leaf.EventEmitter life: Life } export class Life { public readonly owner: LifeOwner constructor(owner: any) { this.owner = owner this.connect(new Leaf.OwnerReferencer()) } private fns: Function[] = [] referencer: OwnerReferencer connect(referencer: OwnerReferencer) { if (this.referencer) this.referencer.events.stopListenBy(this.owner) this.referencer = referencer this.referencer.events.listenBy(this.owner, "release", () => { this.kill() }) return this } dead(fn) { this.fns.push(fn) return this } depends: LifeOwner[] = [] children: LifeOwner[] = [] uses: LifeOwner[] = [] containBy(owner: LifeOwner) { owner.life.contain(owner) return this } contain(item: LifeOwner) { if (!item) return this.children.push(item) return this } purge(item: LifeOwner) { if (!item) return this.children = this.children.filter(child => { if (child === item) { child.life.kill() return false } return true }) return this } use(obj: LifeOwner) { if (!obj) return this if (!obj.life) return if (!obj.life.referencer) return obj.life.referencer.refBy(this.owner) this.uses.push(obj) obj.life.events.listenBy(this.owner, "dead", () => { obj.life.events.stopListenBy(this) if (obj.events) { obj.events.stopListenBy(this) } }) return this } unuse(obj: LifeOwner) { if (!obj) return this.uses = this.uses.filter(item => { if (item === obj) { item.life.referencer.derefBy(this.owner) return false } return true }) return this } need(obj: LifeOwner) { this.depends.push(obj) obj.events.listenBy(this.owner, "dead", () => { this.kill() }) this.use(obj) return this } kill() { if (this.isDestroyed) return this.isDestroyed = true this.referencer.events.stopListenBy(this.owner) for (let obj of this.uses) { obj.life.referencer.derefBy(this.owner) obj.life.events.stopListenBy(this.owner) if (obj.events) obj.events.stopListenBy(this.owner) } for (let obj of this.children) { obj.life.kill() obj.life.events.stopListenBy(this.owner) if (obj.events) obj.events.stopListenBy(this.owner) } for (let obj of this.depends) { obj.life.events.stopListenBy(this.owner) if (obj.events) obj.events.stopListenBy(this.owner) } for (let fn of this.fns) { fn() } this.events.emit("dead") } isDestroyed = false events = new Leaf.EventEmitter<{ dead }>() private keeper: number = Math.random() keep() { this.referencer.refBy(this.keeper) return this } unkeep() { this.referencer.derefBy(this.keeper) return this } ttl(time?: number) { this.referencer.ttl(time) return this } } }