Skip to content

Commit def4c80

Browse files
Kagamihara Nadeshikolhstrh
Kagamihara Nadeshiko
authored andcommitted
Implemented connectable port
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
1 parent 6d10efb commit def4c80

File tree

6 files changed

+51
-20
lines changed

6 files changed

+51
-20
lines changed

__tests__/InvalidMutations.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,23 @@ class R1 extends Reactor {
4040
function (this, __in1, __in2, __out1, __out2) {
4141
test("expect error on creating creating direct feed through", () => {
4242
expect(() => {
43-
this.connect(__in2, __out2);
43+
this.connect(__in2.asConnectable(), __out2.asConnectable());
4444
}).toThrowError("New connection introduces direct feed through.");
4545
});
4646
test("expect error when creating connection outside container", () => {
4747
expect(() => {
48-
this.connect(__out2, __in2);
48+
this.connect(__out2.asConnectable(), __in2.asConnectable());
4949
}).toThrowError("New connection is outside of container.");
5050
});
5151
const R2 = new R1(this.getReactor());
5252
test("expect error on mutation creating race condition on an output port", () => {
5353
expect(() => {
54-
this.connect(R2.out1, __out1);
54+
this.connect(R2.out1.asConnectable(), __out1.asConnectable());
5555
}).toThrowError("Destination port is already occupied.");
5656
});
5757
test("expect error on spawning and creating loop within a reactor", () => {
5858
expect(() => {
59-
this.connect(R2.out1, R2.in1);
59+
this.connect(R2.out1.asConnectable(), R2.in1.asConnectable());
6060
}).toThrowError("New connection introduces cycle.");
6161
});
6262
}

__tests__/SimpleMutation.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class R2 extends Reactor {
4646
function (this, __in, __out) {
4747
test("expect error to be thrown", () => {
4848
expect(() => {
49-
this.connect(__out, __in);
49+
this.connect(__out.asConnectable(), __in.asConnectable());
5050
}).toThrowError("New connection is outside of container.");
5151
});
5252
}

__tests__/disconnect.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ class R1 extends Reactor {
5454
const R2 = new R1(this.getReactor());
5555
test("expect that disconnecting an existing connection will not result in an error being thrown", () => {
5656
expect(() => {
57-
this.connect(R2.out2, R2.in2);
57+
this.connect(R2.out2.asConnectable(), R2.in2.asConnectable());
5858
this.disconnect(R2.out2, R2.in2);
59-
this.connect(R2.out2, R2.in2);
59+
this.connect(R2.out2.asConnectable(), R2.in2.asConnectable());
6060
this.disconnect(R2.out2);
61-
this.connect(R2.out2, R2.in2);
61+
this.connect(R2.out2.asConnectable(), R2.in2.asConnectable());
6262
}).not.toThrow();
6363
});
6464
}

__tests__/mutations.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ class Computer extends Reactor {
9292
continue;
9393
}
9494
const x = new AddOne(this.getReactor(), id);
95-
this.connect(src, x.input);
95+
this.connect(src.asConnectable(), x.input.asConnectable());
9696
}
9797
}
9898
});

src/core/port.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import type {
77
Absent,
88
MultiReadWrite,
99
ReadWrite,
10-
Variable
10+
Variable,
11+
Read
1112
} from "./internal";
1213
import {Trigger, Log} from "./internal";
1314

@@ -59,6 +60,13 @@ export abstract class Port<T> extends Trigger {
5960
}
6061
}
6162

63+
export class ConnectablePort<T> implements Read<T> {
64+
public get = (): Absent => undefined;
65+
public getPort = (): IOPort<T> => this.port;
66+
67+
constructor(public port: IOPort<T>) {}
68+
}
69+
6270
/**
6371
* Abstract class for a writable port. It is intended as a wrapper for a
6472
* regular port. In addition to a get method, it also has a set method and
@@ -103,6 +111,10 @@ export abstract class IOPort<T> extends Port<T> {
103111
}
104112
}
105113

114+
public asConnectable(): ConnectablePort<T> {
115+
return new ConnectablePort(this);
116+
}
117+
106118
/**
107119
* Only the holder of the key may obtain a writable port.
108120
* @param key

src/core/reactor.ts

+29-10
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ import {
4242
Startup,
4343
Shutdown,
4444
WritableMultiPort,
45-
Dummy
45+
Dummy,
46+
ConnectablePort
4647
} from "./internal";
4748
import {v4 as uuidv4} from "uuid";
4849
import {Bank} from "./bank";
@@ -440,16 +441,31 @@ export abstract class Reactor extends Component {
440441
* @param src
441442
* @param dst
442443
*/
444+
445+
public connect<R, S extends R>(
446+
src: ConnectablePort<S>,
447+
dst: ConnectablePort<R>
448+
): void;
449+
public connect<A extends T, R, T, S extends R>(
450+
src: CallerPort<A, R>,
451+
dst: CalleePort<T, S>
452+
): void;
443453
public connect<A extends T, R, T, S extends R>(
444-
src: CallerPort<A, R> | IOPort<S>,
445-
dst: CalleePort<T, S> | IOPort<R>
454+
...[src, dst]:
455+
| [ConnectablePort<S>, ConnectablePort<R>]
456+
| [CallerPort<A, R>, CalleePort<T, S>]
446457
): void {
447458
if (src instanceof CallerPort && dst instanceof CalleePort) {
448459
this.reactor._connectCall(src, dst);
449-
} else if (src instanceof IOPort && dst instanceof IOPort) {
450-
this.reactor._connect(src, dst);
460+
} else if (
461+
src instanceof ConnectablePort &&
462+
dst instanceof ConnectablePort
463+
) {
464+
this.reactor._connect(src.getPort(), dst.getPort());
451465
} else {
452-
// ERROR
466+
throw Error(
467+
"Logically unreachable code: src and dst type mismatch, Caller(ee) port cannot be connected to IOPort."
468+
);
453469
}
454470
}
455471

@@ -1805,10 +1821,13 @@ interface UtilityFunctions {
18051821
}
18061822

18071823
export interface MutationSandbox extends ReactionSandbox {
1808-
connect: <A extends T, R, T, S extends R>(
1809-
src: CallerPort<A, R> | IOPort<S>,
1810-
dst: CalleePort<T, S> | IOPort<R>
1811-
) => void;
1824+
connect: {
1825+
<R, S extends R>(src: ConnectablePort<S>, dst: ConnectablePort<R>): void;
1826+
<A extends T, R, T, S extends R>(
1827+
src: CallerPort<A, R>,
1828+
dst: CalleePort<T, S>
1829+
): void;
1830+
};
18121831

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

0 commit comments

Comments
 (0)