Skip to content

Commit 4d54bd1

Browse files
author
Kagamihara Nadeshiko
committed
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 e165c8c commit 4d54bd1

File tree

6 files changed

+51
-20
lines changed

6 files changed

+51
-20
lines changed

__tests__/InvalidMutations.ts

Lines changed: 4 additions & 4 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ class R1 extends Reactor {
5555
const R2 = new R1(this.getReactor());
5656
test("expect that disconnecting an existing connection will not result in an error being thrown", () => {
5757
expect(() => {
58-
this.connect(R2.out2, R2.in2);
58+
this.connect(R2.out2.asConnectable(), R2.in2.asConnectable());
5959
this.disconnect(R2.out2, R2.in2);
60-
this.connect(R2.out2, R2.in2);
60+
this.connect(R2.out2.asConnectable(), R2.in2.asConnectable());
6161
this.disconnect(R2.out2);
62-
this.connect(R2.out2, R2.in2);
62+
this.connect(R2.out2.asConnectable(), R2.in2.asConnectable());
6363
}).not.toThrow();
6464
});
6565
}

__tests__/mutations.test.ts

Lines changed: 1 addition & 1 deletion
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

Lines changed: 13 additions & 1 deletion
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

Lines changed: 29 additions & 10 deletions
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";
@@ -473,16 +474,31 @@ export abstract class Reactor extends Component {
473474
* @param src
474475
* @param dst
475476
*/
477+
478+
public connect<R, S extends R>(
479+
src: ConnectablePort<S>,
480+
dst: ConnectablePort<R>
481+
): void;
482+
public connect<A extends T, R, T, S extends R>(
483+
src: CallerPort<A, R>,
484+
dst: CalleePort<T, S>
485+
): void;
476486
public connect<A extends T, R, T, S extends R>(
477-
src: CallerPort<A, R> | IOPort<S>,
478-
dst: CalleePort<T, S> | IOPort<R>
487+
...[src, dst]:
488+
| [ConnectablePort<S>, ConnectablePort<R>]
489+
| [CallerPort<A, R>, CalleePort<T, S>]
479490
): void {
480491
if (src instanceof CallerPort && dst instanceof CalleePort) {
481492
this.reactor._connectCall(src, dst);
482-
} else if (src instanceof IOPort && dst instanceof IOPort) {
483-
this.reactor._connect(src, dst);
493+
} else if (
494+
src instanceof ConnectablePort &&
495+
dst instanceof ConnectablePort
496+
) {
497+
this.reactor._connect(src.getPort(), dst.getPort());
484498
} else {
485-
// ERROR
499+
throw Error(
500+
"Logically unreachable code: src and dst type mismatch, Caller(ee) port cannot be connected to IOPort."
501+
);
486502
}
487503
}
488504

@@ -1840,10 +1856,13 @@ interface UtilityFunctions {
18401856
}
18411857

18421858
export interface MutationSandbox extends ReactionSandbox {
1843-
connect: <A extends T, R, T, S extends R>(
1844-
src: CallerPort<A, R> | IOPort<S>,
1845-
dst: CalleePort<T, S> | IOPort<R>
1846-
) => void;
1859+
connect: {
1860+
<R, S extends R>(src: ConnectablePort<S>, dst: ConnectablePort<R>): void;
1861+
<A extends T, R, T, S extends R>(
1862+
src: CallerPort<A, R>,
1863+
dst: CalleePort<T, S>
1864+
): void;
1865+
};
18471866

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

0 commit comments

Comments
 (0)