Skip to content

Commit

Permalink
Implemented connectable port
Browse files Browse the repository at this point in the history
1. Implemented ConnectablePort that can be used as `Variable`
2. Refactored ConnectablePort with function overloading at the same time to facilitate better type check (but due to TS limitation there's no type narrowing, see microsoft/TypeScript#22609)
3. Made tests conform to the new connection API
  • Loading branch information
Kagamihara Nadeshiko committed Dec 13, 2023
1 parent c2f74ce commit d113496
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 20 deletions.
8 changes: 4 additions & 4 deletions __tests__/InvalidMutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,23 @@ class R1 extends Reactor {
function (this, __in1, __in2, __out1, __out2) {
test("expect error on creating creating direct feed through", () => {
expect(() => {
this.connect(__in2, __out2);
this.connect(__in2.asConnectable(), __out2.asConnectable());
}).toThrowError("New connection introduces direct feed through.");
});
test("expect error when creating connection outside container", () => {
expect(() => {
this.connect(__out2, __in2);
this.connect(__out2.asConnectable(), __in2.asConnectable());
}).toThrowError("New connection is outside of container.");
});
const R2 = new R1(this.getReactor());
test("expect error on mutation creating race condition on an output port", () => {
expect(() => {
this.connect(R2.out1, __out1);
this.connect(R2.out1.asConnectable(), __out1.asConnectable());
}).toThrowError("Destination port is already occupied.");
});
test("expect error on spawning and creating loop within a reactor", () => {
expect(() => {
this.connect(R2.out1, R2.in1);
this.connect(R2.out1.asConnectable(), R2.in1.asConnectable());
}).toThrowError("New connection introduces cycle.");
});
}
Expand Down
2 changes: 1 addition & 1 deletion __tests__/SimpleMutation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class R2 extends Reactor {
function (this, __in, __out) {
test("expect error to be thrown", () => {
expect(() => {
this.connect(__out, __in);
this.connect(__out.asConnectable(), __in.asConnectable());
}).toThrowError("New connection is outside of container.");
});
}
Expand Down
6 changes: 3 additions & 3 deletions __tests__/disconnect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ class R1 extends Reactor {
const R2 = new R1(this.getReactor());
test("expect that disconnecting an existing connection will not result in an error being thrown", () => {
expect(() => {
this.connect(R2.out2, R2.in2);
this.connect(R2.out2.asConnectable(), R2.in2.asConnectable());
this.disconnect(R2.out2, R2.in2);
this.connect(R2.out2, R2.in2);
this.connect(R2.out2.asConnectable(), R2.in2.asConnectable());
this.disconnect(R2.out2);
this.connect(R2.out2, R2.in2);
this.connect(R2.out2.asConnectable(), R2.in2.asConnectable());
}).not.toThrow();
});
}
Expand Down
2 changes: 1 addition & 1 deletion __tests__/mutations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class Computer extends Reactor {
continue;
}
const x = new AddOne(this.getReactor(), id);
this.connect(src, x.input);
this.connect(src.asConnectable(), x.input.asConnectable());
}
}
});
Expand Down
14 changes: 13 additions & 1 deletion src/core/port.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import type {
Absent,
MultiReadWrite,
ReadWrite,
Variable
Variable,
Read
} from "./internal";
import {Trigger, Log} from "./internal";

Expand Down Expand Up @@ -59,6 +60,13 @@ export abstract class Port<T> extends Trigger {
}
}

export class ConnectablePort<T> implements Read<T> {
public get = (): Absent => undefined;
public getPort = (): IOPort<T> => this.port;

constructor(public port: IOPort<T>) {}
}

/**
* 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
Expand Down Expand Up @@ -103,6 +111,10 @@ export abstract class IOPort<T> extends Port<T> {
}
}

public asConnectable(): ConnectablePort<T> {
return new ConnectablePort(this);
}

/**
* Only the holder of the key may obtain a writable port.
* @param key
Expand Down
39 changes: 29 additions & 10 deletions src/core/reactor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ import {
Startup,
Shutdown,
WritableMultiPort,
Dummy
Dummy,
ConnectablePort
} from "./internal";
import {v4 as uuidv4} from "uuid";
import {Bank} from "./bank";
Expand Down Expand Up @@ -440,16 +441,31 @@ export abstract class Reactor extends Component {
* @param src
* @param dst
*/

public connect<R, S extends R>(
src: ConnectablePort<S>,
dst: ConnectablePort<R>
): void;
public connect<A extends T, R, T, S extends R>(
src: CallerPort<A, R>,
dst: CalleePort<T, S>
): void;
public connect<A extends T, R, T, S extends R>(
src: CallerPort<A, R> | IOPort<S>,
dst: CalleePort<T, S> | IOPort<R>
...[src, dst]:
| [ConnectablePort<S>, ConnectablePort<R>]
| [CallerPort<A, R>, CalleePort<T, S>]
): void {
if (src instanceof CallerPort && dst instanceof CalleePort) {
this.reactor._connectCall(src, dst);
} else if (src instanceof IOPort && dst instanceof IOPort) {
this.reactor._connect(src, dst);
} else if (
src instanceof ConnectablePort &&
dst instanceof ConnectablePort
) {
this.reactor._connect(src.getPort(), dst.getPort());
} else {
// ERROR
throw Error(
"Logically unreachable code: src and dst type mismatch, Caller(ee) port cannot be connected to IOPort."
);
}
}

Expand Down Expand Up @@ -1804,10 +1820,13 @@ interface UtilityFunctions {
}

export interface MutationSandbox extends ReactionSandbox {
connect: <A extends T, R, T, S extends R>(
src: CallerPort<A, R> | IOPort<S>,
dst: CalleePort<T, S> | IOPort<R>
) => void;
connect: {
<R, S extends R>(src: ConnectablePort<S>, dst: ConnectablePort<R>): void;
<A extends T, R, T, S extends R>(
src: CallerPort<A, R>,
dst: CalleePort<T, S>
): void;
};

disconnect: <R, S extends R>(src: IOPort<S>, dst?: IOPort<R>) => void;

Expand Down

0 comments on commit d113496

Please sign in to comment.