Better field typing
This commit is contained in:
parent
a374cbfdf9
commit
97aaa5ef5d
|
@ -17,7 +17,7 @@
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
import { bootModule, Skeleton, Record, Discard, Capture, Observe, Facet, DataflowObservableObject } from '..';
|
import { bootModule, Skeleton, Record, Discard, Capture, Observe, Facet } from '..';
|
||||||
const __ = Discard._instance;
|
const __ = Discard._instance;
|
||||||
const _$ = Capture(__);
|
const _$ = Capture(__);
|
||||||
|
|
||||||
|
@ -28,67 +28,66 @@ const N = 100000;
|
||||||
|
|
||||||
console.time('box-and-client-' + N.toString());
|
console.time('box-and-client-' + N.toString());
|
||||||
|
|
||||||
function boot(thisFacet: Facet) {
|
function boot(thisFacet: Facet<{}>) {
|
||||||
thisFacet.spawn('box', function (this: DataflowObservableObject & {
|
thisFacet.spawn<{ value: number }>('box', function (thisFacet) {
|
||||||
value: number;
|
thisFacet.declareField(this, 'value', 0);
|
||||||
}, thisFacet: Facet) {
|
thisFacet.addEndpoint(function () {
|
||||||
thisFacet.declareField(this, 'value', 0);
|
// console.log('recomputing published BoxState', this.value);
|
||||||
thisFacet.addEndpoint(() => {
|
return { assertion: BoxState(this.value), analysis: null };
|
||||||
// console.log('recomputing published BoxState', this.value);
|
});
|
||||||
return { assertion: BoxState(this.value), analysis: null };
|
thisFacet.addDataflow(function () {
|
||||||
});
|
// console.log('dataflow saw new value', this.value);
|
||||||
thisFacet.addDataflow(() => {
|
if (this.value === N) {
|
||||||
// console.log('dataflow saw new value', this.value);
|
thisFacet.stop(function () {
|
||||||
if (this.value === N) {
|
console.log('terminated box root facet');
|
||||||
thisFacet.stop(() => {
|
});
|
||||||
console.log('terminated box root facet');
|
}
|
||||||
|
});
|
||||||
|
thisFacet.addEndpoint(function () {
|
||||||
|
let analysis = Skeleton.analyzeAssertion(SetBox(_$));
|
||||||
|
analysis.callback = thisFacet.wrap(function (thisFacet, evt, [v]) {
|
||||||
|
if (evt === Skeleton.EventType.MESSAGE) {
|
||||||
|
if (typeof v !== 'number') return;
|
||||||
|
thisFacet.scheduleScript(function () {
|
||||||
|
this.value = v;
|
||||||
|
// console.log('box updated value', v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { assertion: Observe(SetBox(_$)), analysis };
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
thisFacet.addEndpoint(() => {
|
|
||||||
let analysis = Skeleton.analyzeAssertion(SetBox(_$));
|
|
||||||
analysis.callback = thisFacet.wrap((thisFacet, evt, [v]) => {
|
|
||||||
if (evt === Skeleton.EventType.MESSAGE) {
|
|
||||||
if (typeof v !== 'number') return;
|
|
||||||
thisFacet.scheduleScript(() => {
|
|
||||||
this.value = v;
|
|
||||||
// console.log('box updated value', v);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return { assertion: Observe(SetBox(_$)), analysis };
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
thisFacet.spawn('client', function (thisFacet: Facet) {
|
thisFacet.spawn('client', function (thisFacet: Facet<{}>) {
|
||||||
thisFacet.addEndpoint(() => {
|
thisFacet.addEndpoint(function () {
|
||||||
let analysis = Skeleton.analyzeAssertion(BoxState(_$));
|
let analysis = Skeleton.analyzeAssertion(BoxState(_$));
|
||||||
analysis.callback = thisFacet.wrap((thisFacet, evt, [v]) => {
|
analysis.callback = thisFacet.wrap(function (thisFacet, evt, [v]) {
|
||||||
if (evt === Skeleton.EventType.ADDED) {
|
if (evt === Skeleton.EventType.ADDED) {
|
||||||
if (typeof v !== 'number') return;
|
if (typeof v !== 'number') return;
|
||||||
thisFacet.scheduleScript(() => {
|
thisFacet.scheduleScript(function () {
|
||||||
// console.log('client sending SetBox', v + 1);
|
// console.log('client sending SetBox', v + 1);
|
||||||
thisFacet.send(SetBox(v + 1));
|
thisFacet.send(SetBox(v + 1));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return { assertion: Observe(BoxState(_$)), analysis };
|
return { assertion: Observe(BoxState(_$)), analysis };
|
||||||
|
});
|
||||||
|
thisFacet.addEndpoint(function () {
|
||||||
|
let analysis = Skeleton.analyzeAssertion(BoxState(__));
|
||||||
|
analysis.callback = thisFacet.wrap(function (thisFacet, evt, _vs) {
|
||||||
|
if (evt === Skeleton.EventType.REMOVED) {
|
||||||
|
thisFacet.scheduleScript(function () {
|
||||||
|
console.log('box gone');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { assertion: Observe(BoxState(__)), analysis };
|
||||||
|
});
|
||||||
});
|
});
|
||||||
thisFacet.addEndpoint(() => {
|
|
||||||
let analysis = Skeleton.analyzeAssertion(BoxState(__));
|
|
||||||
analysis.callback = thisFacet.wrap((thisFacet, evt, _vs) => {
|
|
||||||
if (evt === Skeleton.EventType.REMOVED) {
|
|
||||||
thisFacet.scheduleScript(() => {
|
|
||||||
console.log('box gone');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return { assertion: Observe(BoxState(__)), analysis };
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
thisFacet.actor.dataspace.ground().addStopHandler(() =>
|
thisFacet.actor.dataspace.ground().addStopHandler(function () {
|
||||||
console.timeEnd('box-and-client-' + N.toString()));
|
console.timeEnd('box-and-client-' + N.toString());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bootModule(boot);
|
bootModule(boot);
|
||||||
|
|
|
@ -40,17 +40,18 @@ export type FacetId = ActorId;
|
||||||
export type EndpointId = ActorId;
|
export type EndpointId = ActorId;
|
||||||
|
|
||||||
export type Task<T> = () => T;
|
export type Task<T> = () => T;
|
||||||
export type Script<T> = (f: Facet) => T;
|
export type Script<T, Fields> = (this: Fields & DataflowObservableObject, f: Facet<Fields>) => T;
|
||||||
|
|
||||||
export type MaybeValue = Value | undefined;
|
export type MaybeValue = Value | undefined;
|
||||||
export type EndpointSpec = { assertion: MaybeValue, analysis: Skeleton.Analysis | null };
|
export type EndpointSpec = { assertion: MaybeValue, analysis: Skeleton.Analysis | null };
|
||||||
|
|
||||||
export type ObserverCallback = (facet: Facet, bindings: Array<Value>) => void;
|
export type ObserverCallback<Fields> =
|
||||||
|
(this: Fields, facet: Facet<Fields>, bindings: Array<Value>) => void;
|
||||||
|
|
||||||
export type ObserverCallbacks = {
|
export type ObserverCallbacks<Fields> = {
|
||||||
add?: ObserverCallback;
|
add?: ObserverCallback<Fields>;
|
||||||
del?: ObserverCallback;
|
del?: ObserverCallback<Fields>;
|
||||||
msg?: ObserverCallback;
|
msg?: ObserverCallback<Fields>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DataflowObservableObjectId = Symbol.for('DataflowObservableObjectId');
|
export const DataflowObservableObjectId = Symbol.for('DataflowObservableObjectId');
|
||||||
|
@ -63,12 +64,12 @@ export function _canonicalizeDataflowObservable(i: DataflowObservable): string {
|
||||||
return i[0][DataflowObservableObjectId]() + ',' + i[1];
|
return i[0][DataflowObservableObjectId]() + ',' + i[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DataflowDependent = Endpoint;
|
export type DataflowDependent = Endpoint<any>;
|
||||||
export function _canonicalizeDataflowDependent(i: DataflowDependent): string {
|
export function _canonicalizeDataflowDependent(i: DataflowDependent): string {
|
||||||
return '' + i.id;
|
return '' + i.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ActivationScript = Script<void>;
|
export type ActivationScript = Script<void, {}>;
|
||||||
|
|
||||||
export abstract class Dataspace {
|
export abstract class Dataspace {
|
||||||
nextId: ActorId = 0;
|
nextId: ActorId = 0;
|
||||||
|
@ -81,7 +82,7 @@ export abstract class Dataspace {
|
||||||
actors: IdentityMap<number, Actor> = new IdentityMap();
|
actors: IdentityMap<number, Actor> = new IdentityMap();
|
||||||
activations: IdentitySet<ActivationScript> = new IdentitySet();
|
activations: IdentitySet<ActivationScript> = new IdentitySet();
|
||||||
|
|
||||||
constructor(bootProc: Script<void>) {
|
constructor(bootProc: Script<void, {}>) {
|
||||||
this.pendingTurns = [new Turn(null, [new Spawn(null, bootProc, new Set())])];
|
this.pendingTurns = [new Turn(null, [new Spawn(null, bootProc, new Set())])];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +130,12 @@ export abstract class Dataspace {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addActor(name: any, bootProc: Script<void>, initialAssertions: Set, parentActor: Actor | null) {
|
addActor<SpawnFields>(
|
||||||
|
name: any,
|
||||||
|
bootProc: Script<void, SpawnFields>,
|
||||||
|
initialAssertions: Set,
|
||||||
|
parentActor: Actor | null)
|
||||||
|
{
|
||||||
let ac = new Actor(this, name, initialAssertions, parentActor?.id);
|
let ac = new Actor(this, name, initialAssertions, parentActor?.id);
|
||||||
// debug('Spawn', ac && ac.toString());
|
// debug('Spawn', ac && ac.toString());
|
||||||
this.applyPatch(ac, ac.adhocAssertions);
|
this.applyPatch(ac, ac.adhocAssertions);
|
||||||
|
@ -181,7 +187,7 @@ export abstract class Dataspace {
|
||||||
this.index.removeHandler(handler, handler.callback!);
|
this.index.removeHandler(handler, handler.callback!);
|
||||||
}
|
}
|
||||||
|
|
||||||
endpointHook(_facet: Facet, _endpoint: Endpoint) {
|
endpointHook<Fields>(_facet: Facet<Fields>, _endpoint: Endpoint<Fields>) {
|
||||||
// Subclasses may override
|
// Subclasses may override
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,7 +196,7 @@ export class Actor {
|
||||||
readonly id: ActorId;
|
readonly id: ActorId;
|
||||||
readonly dataspace: Dataspace;
|
readonly dataspace: Dataspace;
|
||||||
readonly name: any;
|
readonly name: any;
|
||||||
rootFacet: Facet | null = null;
|
rootFacet: Facet<any> | null = null;
|
||||||
isRunnable: boolean = false;
|
isRunnable: boolean = false;
|
||||||
readonly pendingTasks: Array<Array<Task<void>>>;
|
readonly pendingTasks: Array<Array<Task<void>>>;
|
||||||
pendingActions: Array<Action>;
|
pendingActions: Array<Action>;
|
||||||
|
@ -253,11 +259,15 @@ export class Actor {
|
||||||
this.pendingTasks[priority].push(task);
|
this.pendingTasks[priority].push(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
addFacet(parentFacet: Facet | null, bootProc: Script<void>, checkInScript: boolean = false) {
|
addFacet<ParentFields, ChildFields extends ParentFields>(
|
||||||
|
parentFacet: Facet<ParentFields> | null,
|
||||||
|
bootProc: Script<void, ChildFields>,
|
||||||
|
checkInScript: boolean = false)
|
||||||
|
{
|
||||||
if (checkInScript && parentFacet && !parentFacet.inScript) {
|
if (checkInScript && parentFacet && !parentFacet.inScript) {
|
||||||
throw new Error("Cannot add facet outside script; are you missing a `react { ... }`?");
|
throw new Error("Cannot add facet outside script; are you missing a `react { ... }`?");
|
||||||
}
|
}
|
||||||
let f = new Facet(this, parentFacet);
|
let f = new Facet<ChildFields>(this, parentFacet);
|
||||||
f.invokeScript(f => f.withNonScriptContext(() => bootProc.call(f.fields, f)));
|
f.invokeScript(f => f.withNonScriptContext(() => bootProc.call(f.fields, f)));
|
||||||
this.scheduleTask(() => {
|
this.scheduleTask(() => {
|
||||||
if ((parentFacet && !parentFacet.isLive) || f.isInert()) {
|
if ((parentFacet && !parentFacet.isLive) || f.isInert()) {
|
||||||
|
@ -351,12 +361,12 @@ class Message extends Action {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Spawn extends Action {
|
class Spawn<Fields> extends Action {
|
||||||
readonly name: any;
|
readonly name: any;
|
||||||
readonly bootProc: Script<void>;
|
readonly bootProc: Script<void, Fields>;
|
||||||
readonly initialAssertions: Set;
|
readonly initialAssertions: Set;
|
||||||
|
|
||||||
constructor(name: any, bootProc: Script<void>, initialAssertions: Set = new Set()) {
|
constructor(name: any, bootProc: Script<void, Fields>, initialAssertions: Set = new Set()) {
|
||||||
super();
|
super();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.bootProc = bootProc;
|
this.bootProc = bootProc;
|
||||||
|
@ -406,7 +416,7 @@ class Activation extends Action {
|
||||||
perform(ds: Dataspace, ac: Actor | null): void {
|
perform(ds: Dataspace, ac: Actor | null): void {
|
||||||
if (ds.activations.has(this.script)) return;
|
if (ds.activations.has(this.script)) return;
|
||||||
ds.activations.add(this.script);
|
ds.activations.add(this.script);
|
||||||
ds.addActor(this.name, rootFacet => rootFacet.addStartScript(this.script), new Set(), ac);
|
ds.addActor<{}>(this.name, rootFacet => rootFacet.addStartScript(this.script), new Set(), ac);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,18 +434,18 @@ export class Turn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Facet {
|
export class Facet<Fields> {
|
||||||
readonly id: FacetId;
|
readonly id: FacetId;
|
||||||
isLive = true;
|
isLive = true;
|
||||||
readonly actor: Actor;
|
readonly actor: Actor;
|
||||||
readonly parent: Facet | null;
|
readonly parent: Facet<any> | null;
|
||||||
readonly endpoints = new IdentityMap<EndpointId, Endpoint>();
|
readonly endpoints = new IdentityMap<EndpointId, Endpoint<Fields>>();
|
||||||
readonly stopScripts: Array<Script<void>> = [];
|
readonly stopScripts: Array<Script<void, Fields>> = [];
|
||||||
readonly children = new IdentitySet<Facet>();
|
readonly children = new IdentitySet<Facet<any>>();
|
||||||
readonly fields: any;
|
readonly fields: Fields & DataflowObservableObject;
|
||||||
inScript = true;
|
inScript = true;
|
||||||
|
|
||||||
constructor(actor: Actor, parent: Facet | null) {
|
constructor(actor: Actor, parent: Facet<any> | null) {
|
||||||
this.id = actor.dataspace.nextId++;
|
this.id = actor.dataspace.nextId++;
|
||||||
this.actor = actor;
|
this.actor = actor;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
@ -513,11 +523,11 @@ export class Facet {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This alias exists because of the naive expansion done by the parser.
|
// This alias exists because of the naive expansion done by the parser.
|
||||||
_stop(continuation?: Script<void>) {
|
_stop(continuation?: Script<void, Fields>) {
|
||||||
this.stop(continuation);
|
this.stop(continuation);
|
||||||
}
|
}
|
||||||
|
|
||||||
stop(continuation?: Script<void>) {
|
stop(continuation?: Script<void, Fields>) {
|
||||||
this.parent!.invokeScript(() => {
|
this.parent!.invokeScript(() => {
|
||||||
this.actor.scheduleTask(() => {
|
this.actor.scheduleTask(() => {
|
||||||
this._terminate();
|
this._terminate();
|
||||||
|
@ -529,35 +539,35 @@ export class Facet {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addStartScript(s: Script<void>) {
|
addStartScript(s: Script<void, Fields>) {
|
||||||
this.ensureFacetSetup('`on start`');
|
this.ensureFacetSetup('`on start`');
|
||||||
this.scheduleScript(s);
|
this.scheduleScript(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
addStopScript(s: Script<void>) {
|
addStopScript(s: Script<void, Fields>) {
|
||||||
this.ensureFacetSetup('`on stop`');
|
this.ensureFacetSetup('`on stop`');
|
||||||
this.stopScripts.push(s);
|
this.stopScripts.push(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
addEndpoint(updateFun: Script<EndpointSpec>, isDynamic: boolean = true): Endpoint {
|
addEndpoint(updateFun: Script<EndpointSpec, Fields>, isDynamic: boolean = true): Endpoint<Fields> {
|
||||||
const ep = new Endpoint(this, isDynamic, updateFun);
|
const ep = new Endpoint(this, isDynamic, updateFun);
|
||||||
this.actor.dataspace.endpointHook(this, ep);
|
this.actor.dataspace.endpointHook(this, ep);
|
||||||
return ep;
|
return ep;
|
||||||
}
|
}
|
||||||
|
|
||||||
_addRawObserverEndpoint(specScript: Script<MaybeValue>, callbacks: ObserverCallbacks): Endpoint
|
_addRawObserverEndpoint(specScript: Script<MaybeValue, Fields>, callbacks: ObserverCallbacks<Fields>): Endpoint<Fields>
|
||||||
{
|
{
|
||||||
return this.addEndpoint(() => {
|
return this.addEndpoint(() => {
|
||||||
const spec = specScript(this);
|
const spec = specScript.call(this.fields, this);
|
||||||
if (spec === void 0) {
|
if (spec === void 0) {
|
||||||
return { assertion: void 0, analysis: null };
|
return { assertion: void 0, analysis: null };
|
||||||
} else {
|
} else {
|
||||||
const analysis = Skeleton.analyzeAssertion(spec);
|
const analysis = Skeleton.analyzeAssertion(spec);
|
||||||
analysis.callback = this.wrap((facet, evt, vs) => {
|
analysis.callback = this.wrap((facet, evt, vs) => {
|
||||||
switch (evt) {
|
switch (evt) {
|
||||||
case Skeleton.EventType.ADDED: callbacks.add?.(facet, vs); break;
|
case Skeleton.EventType.ADDED: callbacks.add?.call(facet.fields, facet, vs); break;
|
||||||
case Skeleton.EventType.REMOVED: callbacks.del?.(facet, vs); break;
|
case Skeleton.EventType.REMOVED: callbacks.del?.call(facet.fields, facet, vs); break;
|
||||||
case Skeleton.EventType.MESSAGE: callbacks.msg?.(facet, vs); break;
|
case Skeleton.EventType.MESSAGE: callbacks.msg?.call(facet.fields, facet, vs); break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return { assertion: Observe(spec), analysis };
|
return { assertion: Observe(spec), analysis };
|
||||||
|
@ -565,9 +575,9 @@ export class Facet {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addObserverEndpoint(specThunk: (facet: Facet) => MaybeValue, callbacks: ObserverCallbacks): Endpoint {
|
addObserverEndpoint(specThunk: (facet: Facet<Fields>) => MaybeValue, callbacks: ObserverCallbacks<Fields>): Endpoint<Fields> {
|
||||||
const scriptify = (f?: ObserverCallback) =>
|
const scriptify = (f?: ObserverCallback<Fields>) =>
|
||||||
f && ((facet: Facet, vs: Array<Value>) =>
|
f && ((facet: Facet<Fields>, vs: Array<Value>) =>
|
||||||
facet.scheduleScript(() => f.call(facet.fields, facet, vs)));
|
facet.scheduleScript(() => f.call(facet.fields, facet, vs)));
|
||||||
return this._addRawObserverEndpoint(specThunk, {
|
return this._addRawObserverEndpoint(specThunk, {
|
||||||
add: scriptify(callbacks.add),
|
add: scriptify(callbacks.add),
|
||||||
|
@ -576,7 +586,7 @@ export class Facet {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addDataflow(subjectFun: Script<void>, priority?: Priority): Endpoint {
|
addDataflow(subjectFun: Script<void, Fields>, priority?: Priority): Endpoint<Fields> {
|
||||||
return this.addEndpoint(() => {
|
return this.addEndpoint(() => {
|
||||||
let subjectId = this.actor.dataspace.dataflow.currentSubjectId;
|
let subjectId = this.actor.dataspace.dataflow.currentSubjectId;
|
||||||
this.scheduleScript(() => {
|
this.scheduleScript(() => {
|
||||||
|
@ -607,7 +617,7 @@ export class Facet {
|
||||||
return s + ')';
|
return s + ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
invokeScript<T>(script: Script<T>, propagateErrors = false): T | undefined {
|
invokeScript<T>(script: Script<T, Fields>, propagateErrors = false): T | undefined {
|
||||||
try {
|
try {
|
||||||
// console.group('Facet', facet && facet.toString());
|
// console.group('Facet', facet && facet.toString());
|
||||||
return script.call(this.fields, this);
|
return script.call(this.fields, this);
|
||||||
|
@ -623,11 +633,18 @@ export class Facet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wrap<T extends Array<any>, R>(fn: (f: Facet, ... args: T) => R): (... args: T) => R {
|
wrap<T extends Array<any>, R>(
|
||||||
|
fn: (this: Fields & DataflowObservableObject,
|
||||||
|
f: Facet<Fields>, ... args: T) => R
|
||||||
|
): (... args: T) => R
|
||||||
|
{
|
||||||
return (... actuals) => this.invokeScript(f => fn.call(f.fields, f, ... actuals), true)!;
|
return (... actuals) => this.invokeScript(f => fn.call(f.fields, f, ... actuals), true)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapExternal<T extends Array<any>>(fn: (f: Facet, ... args: T) => void): (... args: T) => void {
|
wrapExternal<T extends Array<any>>(
|
||||||
|
fn: (this: Fields & DataflowObservableObject,
|
||||||
|
f: Facet<Fields>, ... args: T) => void
|
||||||
|
): (... args: T) => void {
|
||||||
const ac = this.actor;
|
const ac = this.actor;
|
||||||
return (... actuals) => {
|
return (... actuals) => {
|
||||||
if (this.isLive) {
|
if (this.isLive) {
|
||||||
|
@ -660,16 +677,16 @@ export class Facet {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This alias exists because of the naive expansion done by the parser.
|
// This alias exists because of the naive expansion done by the parser.
|
||||||
_spawn(name: any, bootProc: Script<void>, initialAssertions?: Set) {
|
_spawn<SpawnFields>(name: any, bootProc: Script<void, SpawnFields>, initialAssertions?: Set) {
|
||||||
this.spawn(name, bootProc, initialAssertions);
|
this.spawn(name, bootProc, initialAssertions);
|
||||||
}
|
}
|
||||||
|
|
||||||
spawn(name: any, bootProc: Script<void>, initialAssertions?: Set) {
|
spawn<SpawnFields>(name: any, bootProc: Script<void, SpawnFields>, initialAssertions?: Set) {
|
||||||
this.ensureNonFacetSetup('`spawn`');
|
this.ensureNonFacetSetup('`spawn`');
|
||||||
this.enqueueScriptAction(new Spawn(name, bootProc, initialAssertions));
|
this.enqueueScriptAction(new Spawn(name, bootProc, initialAssertions));
|
||||||
}
|
}
|
||||||
|
|
||||||
deferTurn(continuation: Script<void>) {
|
deferTurn(continuation: Script<void, Fields>) {
|
||||||
this.ensureNonFacetSetup('`deferTurn`');
|
this.ensureNonFacetSetup('`deferTurn`');
|
||||||
this.enqueueScriptAction(new DeferredTurn(this.wrap(continuation)));
|
this.enqueueScriptAction(new DeferredTurn(this.wrap(continuation)));
|
||||||
}
|
}
|
||||||
|
@ -679,7 +696,7 @@ export class Facet {
|
||||||
this.enqueueScriptAction(new Activation(script, name ?? null));
|
this.enqueueScriptAction(new Activation(script, name ?? null));
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduleScript(script: Script<void>, priority?: Priority) {
|
scheduleScript(script: Script<void, Fields>, priority?: Priority) {
|
||||||
this.actor.scheduleTask(this.wrap(script), priority);
|
this.actor.scheduleTask(this.wrap(script), priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,22 +723,22 @@ export class Facet {
|
||||||
// delete obj[prop];
|
// delete obj[prop];
|
||||||
// }
|
// }
|
||||||
|
|
||||||
addChildFacet(bootProc: Script<void>) {
|
addChildFacet<ChildFields extends Fields>(bootProc: Script<void, ChildFields>) {
|
||||||
this.actor.addFacet(this, bootProc, true);
|
this.actor.addFacet(this, bootProc, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
withSelfDo(t: Script<void>) {
|
withSelfDo(t: Script<void, Fields>) {
|
||||||
t(this);
|
t.call(this.fields, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Endpoint {
|
export class Endpoint<Fields> {
|
||||||
readonly id: EndpointId;
|
readonly id: EndpointId;
|
||||||
readonly facet: Facet;
|
readonly facet: Facet<Fields>;
|
||||||
readonly updateFun: Script<EndpointSpec>;
|
readonly updateFun: Script<EndpointSpec, Fields>;
|
||||||
spec: EndpointSpec;
|
spec: EndpointSpec;
|
||||||
|
|
||||||
constructor(facet: Facet, isDynamic: boolean, updateFun: Script<EndpointSpec>) {
|
constructor(facet: Facet<Fields>, isDynamic: boolean, updateFun: Script<EndpointSpec, Fields>) {
|
||||||
facet.ensureFacetSetup('add endpoint');
|
facet.ensureFacetSetup('add endpoint');
|
||||||
let ac = facet.actor;
|
let ac = facet.actor;
|
||||||
let ds = ac.dataspace;
|
let ds = ac.dataspace;
|
||||||
|
|
|
@ -28,9 +28,9 @@ import { Ground } from './ground.js';
|
||||||
export const $QuitDataspace = new $Special("quit-dataspace");
|
export const $QuitDataspace = new $Special("quit-dataspace");
|
||||||
|
|
||||||
export class NestedDataspace extends Dataspace {
|
export class NestedDataspace extends Dataspace {
|
||||||
readonly outerFacet: Facet;
|
readonly outerFacet: Facet<{}>;
|
||||||
|
|
||||||
constructor(outerFacet: Facet, bootProc: Script<void>) {
|
constructor(outerFacet: Facet<{}>, bootProc: Script<void, {}>) {
|
||||||
super(bootProc);
|
super(bootProc);
|
||||||
this.outerFacet = outerFacet;
|
this.outerFacet = outerFacet;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ export class NestedDataspace extends Dataspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
endpointHook(facet: Facet, innerEp: Endpoint) {
|
endpointHook<InnerFields>(facet: Facet<InnerFields>, innerEp: Endpoint<InnerFields>) {
|
||||||
super.endpointHook(facet, innerEp);
|
super.endpointHook(facet, innerEp);
|
||||||
|
|
||||||
const innerAssertion = innerEp.spec.assertion;
|
const innerAssertion = innerEp.spec.assertion;
|
||||||
|
@ -105,7 +105,7 @@ export class NestedDataspace extends Dataspace {
|
||||||
return net;
|
return net;
|
||||||
}
|
}
|
||||||
|
|
||||||
hookEndpointLifecycle(innerEp: Endpoint, outerEp: Endpoint) {
|
hookEndpointLifecycle<InnerFields>(innerEp: Endpoint<InnerFields>, outerEp: Endpoint<{}>) {
|
||||||
const _refresh = innerEp.refresh;
|
const _refresh = innerEp.refresh;
|
||||||
innerEp.refresh = function () {
|
innerEp.refresh = function () {
|
||||||
_refresh.call(this);
|
_refresh.call(this);
|
||||||
|
@ -139,7 +139,7 @@ export class NestedDataspace extends Dataspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function inNestedDataspace(bootProc: Script<void>): Script<void> {
|
export function inNestedDataspace(bootProc: Script<void, {}>): Script<void, {}> {
|
||||||
return outerFacet => {
|
return outerFacet => {
|
||||||
outerFacet.addDataflow(function () {});
|
outerFacet.addDataflow(function () {});
|
||||||
// ^ eww! Dummy endpoint to keep the root facet of the relay alive.
|
// ^ eww! Dummy endpoint to keep the root facet of the relay alive.
|
||||||
|
|
Loading…
Reference in New Issue