UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

126 lines (104 loc) 2.9 kB
import Signal from "../../../core/events/signal/Signal.js"; /** * Value container, allows reference counting through {@link #onReleased} signal * Intended for usage with reference-managing systems * @example * const ref: Reference<Texture> = texture_system.get(some_id); * // do work with texture * ref.release(); // we're done with the resource, texture_system will be notified * // now ref.getValue() === null, reference is no longer valid * @example * const ref: Reference<Texture> = Reference.from(texture); * ref.onReleased.add((this_ref:Reference<Texture>, texture:Texture) => { * // cleanup memory when the reference is released * texture.dispose(); * }); * // pass the reference to some other system for use * @template T */ export class Reference { /** * * @type {Signal<this,T>} * @private */ #onReleased = new Signal(); /** * Actual value being held * @type {T} * @private */ #value = null; /** * Whether a value is bound or not. Will be true if value is != null * @type {boolean} * @private */ #is_bound = false; get bound() { return this.#is_bound; } /** * * @returns {Signal<this,T>} */ get onReleased() { return this.#onReleased; } /** * Produces a new instance of a bound reference with a given value. * Same as calling {@link bind} on a new instance. * * @template X * @param {X} x * @return {Reference<X>} * @see bind */ static from(x){ const r = new Reference(); r.bind(x); return r; } /** * * @param {T} value */ bind(value) { if (value === this.#value) { return; } if (this.#is_bound) { throw new Error(`Reference is already bound, must release before binding to a new value`); } this.#value = value; this.#is_bound = true; } /** * * @returns {T} */ getValue() { return this.#value; } /** * Release value being referenced. After this the held value is set to null * This method is idempotent, calling it multiple times is safe */ release() { if (!this.#is_bound) { // not bound return; } const v = this.#value; // prevent further usage of the reference this.#value = null; this.#is_bound = false; this.#onReleased.send2(this, v); } } /** * Special NULL reference that can be used to indicate lack of reference * @readonly * @type {Readonly<Reference>} */ Reference.NULL = Object.freeze(new Reference());