@lf-lang/reactor-ts
Version:
A reactor-oriented programming framework in TypeScript
181 lines • 5.6 kB
JavaScript
"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