UNPKG

@lf-lang/reactor-ts

Version:

A reactor-oriented programming framework in TypeScript

181 lines 5.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.InPort = exports.OutPort = exports.IOPort = exports.WritableMultiPort = exports.WritablePort = exports.ConnectablePort = exports.Port = void 0; const internal_1 = require("./internal"); class Port extends internal_1.Trigger { receivers = new Set(); runtime; constructor(container) { super(container); this._linkToRuntimeObject(); } /** The tag associated with this port's value, or undefined is there is none. */ tag; /** The current value associated with this port. */ value; _receiveRuntimeObject(runtime) { if (this.runtime == null) { this.runtime = runtime; } else { throw new Error("Can only establish link to runtime once. Name: " + this._getFullyQualifiedName()); } } /** * Returns true if the connected port's value has been set; false otherwise */ isPresent() { internal_1.Log.debug(this, () => "In isPresent()..."); internal_1.Log.debug(this, () => `value: ${this.value?.toString()}`); internal_1.Log.debug(this, () => `tag: ${this.tag}`); internal_1.Log.debug(this, () => `time: ${this.runtime.util.getCurrentLogicalTime()}`); if (this.value !== undefined && this.tag !== undefined && this.tag.isSimultaneousWith(this.runtime.util.getCurrentTag())) { return true; } else { return false; } } } exports.Port = Port; class ConnectablePort { port; get = () => undefined; getPort = () => this.port; constructor(port) { this.port = port; } } exports.ConnectablePort = ConnectablePort; /** * Abstract class for a writable port. It is intended as a wrapper for a * regular port. In addition to a get method, it also has a set method and * a method for retrieving the port that it wraps. * We have this abstract class so that we can do `instanceof` checks. */ class WritablePort { } exports.WritablePort = WritablePort; class WritableMultiPort { } exports.WritableMultiPort = WritableMultiPort; class IOPort extends Port { /** * Return the value set to this port. Return `Absent` if the connected * output did not have its value set at the current logical time. */ get() { if (this.isPresent()) { return this.value; } else { return undefined; } } asConnectable() { return new ConnectablePort(this); } /** * Only the holder of the key may obtain a writable port. * @param key */ asWritable(key) { if (this._key === key) { return this.writer; } throw Error("Referenced port is out of scope: " + this._getFullyQualifiedName()); // FIXME: adjust messages for other methods as well // FIXME: we could potentially do this for reads/triggers as well just for scope rule enforcement } /** * * @param container Reference to the container of this port * (or the container thereof). */ getManager(key) { if (this._key === key) { return this.manager; } throw Error("Unable to grant access to manager."); } /** * Inner class instance to gain access to Write<T> interface. */ writer = new (class extends WritablePort { port; constructor(port) { super(); this.port = port; } set(value) { this.port.value = value; this.port.tag = this.port.runtime.util.getCurrentTag(); // Set values in downstream receivers. this.port.receivers.forEach((p) => { p.set(value); }); // Stage triggered reactions for execution. this.port.reactions.forEach((r) => { this.port.runtime.stage(r); }); } get() { return this.port.get(); } getPort() { return this.port; } toString() { return this.port.toString(); } })(this); /** * Inner class instance to let the container configure this port. */ manager = new (class { port; constructor(port) { this.port = port; } getContainer() { return this.port._getContainer(); } /** * Add the given port to the list of receivers. If the connection was * established at runtime and the upstream port already has a value, * immediately propagate the value to the newly connected receiver. * @param port A newly connected downstream port. */ addReceiver(port) { this.port.receivers.add(port); if (this.port.runtime.isRunning()) { const val = this.port.get(); if (val !== undefined) { port.set(val); } } } delReceiver(port) { this.port.receivers.delete(port); } addReaction(reaction) { this.port.reactions.add(reaction); } delReaction(reaction) { this.port.reactions.delete(reaction); } })(this); toString() { return this._getFullyQualifiedName(); } } exports.IOPort = IOPort; class OutPort extends IOPort { } exports.OutPort = OutPort; class InPort extends IOPort { } exports.InPort = InPort; //# sourceMappingURL=port.js.map