@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
102 lines (83 loc) • 2.22 kB
JavaScript
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
* @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;
}
/**
*
* @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());