Switch to using the schema-generated code. It's about half the speed. I wonder why?
This commit is contained in:
parent
4393561fc9
commit
5086e3b209
|
@ -10,7 +10,7 @@
|
||||||
"@preserves/schema": "^0.1.1"
|
"@preserves/schema": "^0.1.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"regenerate": "rm -rf ./src/gen && preserves-schema-ts --module Pointer=./src/actor.ts --output ./src/gen ./schemas/**/*.prs",
|
"regenerate": "rm -rf ./src/gen && preserves-schema-ts --module Actor=./src/actor.ts --module Protocol=./src/protocol.ts --output ./src/gen './schemas/**/*.prs'",
|
||||||
"regenerate:watch": "yarn regenerate --watch",
|
"regenerate:watch": "yarn regenerate --watch",
|
||||||
"compile": "tsc",
|
"compile": "tsc",
|
||||||
"compile:watch": "tsc -w",
|
"compile:watch": "tsc -w",
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
version 1 .
|
version 1 .
|
||||||
pointer Pointer.Ref .
|
pointer Actor.Ref .
|
||||||
|
|
||||||
BoxState = <BoxState int>.
|
BoxState = <BoxState int>.
|
||||||
SetBox = <SetBox int>.
|
SetBox = <SetBox int>.
|
||||||
|
|
||||||
BoxCap = BoxState / <Observe =SetBox ref>.
|
; BoxCap = BoxState / <Observe =SetBox ref>.
|
||||||
ClientCap = SetBox / <Observe =BoxState ref>.
|
; ClientCap = SetBox / <Observe =BoxState ref>.
|
||||||
|
.
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
version 1 .
|
version 1 .
|
||||||
|
pointer Actor.Ref .
|
||||||
|
|
||||||
;As implemented
|
;As implemented
|
||||||
Observe = <Observe symbol ref>.
|
Observe = <Observe @label symbol @observer ref>.
|
||||||
|
|
||||||
; ;As will be implemented soon
|
; ;As will be implemented soon
|
||||||
; Observe = <Observe Pattern ref>.
|
; Observe = <Observe Pattern ref>.
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
version 1 .
|
||||||
|
pointer Protocol.WireRef .
|
||||||
|
|
||||||
|
Assertion = any .
|
||||||
|
Handle = int .
|
||||||
|
Event = Assert / Retract / Message / Sync .
|
||||||
|
Oid = int .
|
||||||
|
Turn = [[Oid Event] ...].
|
||||||
|
|
||||||
|
Assert = <assert @assertion Assertion @handle Handle>.
|
||||||
|
Retract = <retract @handle Handle>.
|
||||||
|
Message = <message @body Assertion>.
|
||||||
|
Sync = <sync @peer ref>.
|
|
@ -1,20 +0,0 @@
|
||||||
version 1 .
|
|
||||||
|
|
||||||
ConstructorSpec = <rec any int> / <arr int> / <dict>.
|
|
||||||
|
|
||||||
Pattern = </[
|
|
||||||
<_>
|
|
||||||
<bind symbol Pattern>
|
|
||||||
<and [Pattern ...]>
|
|
||||||
<not Pattern>
|
|
||||||
<lit any>
|
|
||||||
<compound ConstructorSpec { any: Pattern ...:... }>
|
|
||||||
]>.
|
|
||||||
|
|
||||||
Template = </[
|
|
||||||
<ref symbol>
|
|
||||||
<lit any>
|
|
||||||
<compound ConstructorSpec { any: Template ...:... }>
|
|
||||||
]>.
|
|
||||||
|
|
||||||
Rewrite = <rewrite Pattern Template>.
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
version 1 .
|
||||||
|
pointer Actor.Ref .
|
||||||
|
|
||||||
|
; Each Attenuation is a stage. The sequence of Attenuations is run RIGHT-TO-LEFT.
|
||||||
|
; That is, the newest Attenuations are at the right.
|
||||||
|
SturdyRef = <ref @oid any @caveatChain [Attenuation ...] @sig bytes>.
|
||||||
|
|
||||||
|
; An individual Attenuation is run RIGHT-TO-LEFT.
|
||||||
|
; That is, the newest Caveats are at the right.
|
||||||
|
Attenuation = [Caveat ...].
|
||||||
|
|
||||||
|
; embodies 1st-party caveats over assertion structure, but nothing else
|
||||||
|
; can add 3rd-party caveats and richer predicates later
|
||||||
|
Caveat = Rewrite / Alts .
|
||||||
|
Rewrite = <rewrite @pattern Pattern @template Template>.
|
||||||
|
Alts = <or @alternatives [Rewrite ...]>.
|
||||||
|
|
||||||
|
Resolve = <resolve @sturdyref SturdyRef @observer ref>.
|
||||||
|
|
||||||
|
;---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ConstructorSpec = CRec / CArr / CDict .
|
||||||
|
CRec = <rec @label any @arity int>.
|
||||||
|
CArr = <arr @arity int>.
|
||||||
|
CDict = <dict>.
|
||||||
|
|
||||||
|
Lit = <lit @value any>.
|
||||||
|
|
||||||
|
Pattern = PDiscard / PBind / PAnd / PNot / Lit / PCompound .
|
||||||
|
PDiscard = <_>.
|
||||||
|
PBind = <bind @name symbol @pattern Pattern>.
|
||||||
|
PAnd = <and @patterns [Pattern ...]>.
|
||||||
|
PNot = <not @pattern Pattern>.
|
||||||
|
PCompound = <compound @ctor ConstructorSpec @members { any: Pattern ...:... }>.
|
||||||
|
|
||||||
|
Template = TRef / Lit / TCompound .
|
||||||
|
TRef = <ref @name symbol>.
|
||||||
|
TCompound = <compound @ctor ConstructorSpec @members { any: Template ...:... }>.
|
|
@ -1,17 +0,0 @@
|
||||||
version 1 .
|
|
||||||
|
|
||||||
SturdyRef = <ref any [Caveat ...] bytes>.
|
|
||||||
Caveat = rewrite.Rewrite / <or [rewrite.Rewrite ...]>.
|
|
||||||
|
|
||||||
Handle = int .
|
|
||||||
Event = Assert / Retract / Message / Sync .
|
|
||||||
Oid = int .
|
|
||||||
Turn = [[Oid Event] ...].
|
|
||||||
|
|
||||||
Assert = <assert @assertion any @handle Handle>.
|
|
||||||
Retract = <retract @handle Handle>.
|
|
||||||
Message = <message @body any>.
|
|
||||||
Sync = <sync @peer ref>.
|
|
||||||
|
|
||||||
; WireRef = [0 Oid] / [1 Oid AttenuationStage ...].
|
|
||||||
.
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { BoxState, SetBox } from "./gen/box-protocol.js";
|
import { BoxState, SetBox } from "./gen/box-protocol.js";
|
||||||
|
import { Observe } from "./gen/dataspace.js";
|
||||||
import { Assertion, Handle, Ref, Turn } from "./actor.js";
|
import { Assertion, Handle, Ref, Turn } from "./actor.js";
|
||||||
import { Observe } from "./dataspace.js";
|
|
||||||
|
|
||||||
let startTime = Date.now();
|
let startTime = Date.now();
|
||||||
let prevValue = 0;
|
let prevValue = 0;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { BoxState, SetBox } from "./gen/box-protocol.js";
|
import { BoxState, SetBox } from "./gen/box-protocol.js";
|
||||||
import { Observe } from "./dataspace.js";
|
import { Observe } from "./gen/dataspace.js";
|
||||||
import { Assertion, Ref, Turn } from "./actor.js";
|
import { Assertion, Ref, Turn } from "./actor.js";
|
||||||
|
|
||||||
export default function (t: Turn, ds: Ref) {
|
export default function (t: Turn, ds: Ref) {
|
||||||
|
|
|
@ -2,6 +2,9 @@ import { Assertion, Entity, Handle, Ref, Turn } from 'actor';
|
||||||
import { Dictionary, IdentityMap, is, Record, Tuple } from '@preserves/core';
|
import { Dictionary, IdentityMap, is, Record, Tuple } from '@preserves/core';
|
||||||
import { Bag, ChangeDescription } from './bag';
|
import { Bag, ChangeDescription } from './bag';
|
||||||
|
|
||||||
|
import { Observe } from './gen/dataspace';
|
||||||
|
export * from './gen/dataspace';
|
||||||
|
|
||||||
// Q. Why keep "Observe"? Why not do the clever trick of asserting the
|
// Q. Why keep "Observe"? Why not do the clever trick of asserting the
|
||||||
// observer, and having the dataspace read the implicit pattern it's
|
// observer, and having the dataspace read the implicit pattern it's
|
||||||
// interested in off its attenuator?
|
// interested in off its attenuator?
|
||||||
|
@ -14,7 +17,12 @@ import { Bag, ChangeDescription } from './bag';
|
||||||
// Because we want to have onlookers have some hope of seeing whether
|
// Because we want to have onlookers have some hope of seeing whether
|
||||||
// a pattern of interest to them is being observed, and if we used
|
// a pattern of interest to them is being observed, and if we used
|
||||||
// attenuators to match, we'd have to expose visibility into
|
// attenuators to match, we'd have to expose visibility into
|
||||||
// attenuators into the pattern language. See next question.
|
// attenuators into the pattern language. See next question. (3)
|
||||||
|
// Because reflection on attenuators is a big, heavy hammer, and it's
|
||||||
|
// better to be explicit about patterns! Also, some attenuations
|
||||||
|
// happen behind a veil of secrecy - they're not all open for the
|
||||||
|
// world to read about. Actors may proxy communications in arbitrary,
|
||||||
|
// secret ways.
|
||||||
//
|
//
|
||||||
// Q. What kinds of constraints on the pattern language are there?
|
// Q. What kinds of constraints on the pattern language are there?
|
||||||
//
|
//
|
||||||
|
@ -26,9 +34,6 @@ import { Bag, ChangeDescription } from './bag';
|
||||||
// that enforced some kind of normal forms for its patterns, so
|
// that enforced some kind of normal forms for its patterns, so
|
||||||
// observer-observers and attenuator patterns don't have to deal with
|
// observer-observers and attenuator patterns don't have to deal with
|
||||||
// spurious variation.
|
// spurious variation.
|
||||||
//
|
|
||||||
export const Observe = Record.makeConstructor<{label: Assertion, observer: Ref}, Ref>()(
|
|
||||||
Symbol.for('Observe'), ['label', 'observer']);
|
|
||||||
|
|
||||||
export class Dataspace implements Partial<Entity> {
|
export class Dataspace implements Partial<Entity> {
|
||||||
readonly handleMap: IdentityMap<Handle, Record<Assertion, any, Ref>> = new IdentityMap();
|
readonly handleMap: IdentityMap<Handle, Record<Assertion, any, Ref>> = new IdentityMap();
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import * as _ from "@preserves/core";
|
import * as _ from "@preserves/core";
|
||||||
import * as _i_Pointer from "../actor";
|
import * as _i_Actor from "../actor";
|
||||||
|
|
||||||
export const $BoxState = Symbol.for("BoxState");
|
export const $BoxState = Symbol.for("BoxState");
|
||||||
export const $Observe = Symbol.for("Observe");
|
|
||||||
export const $SetBox = Symbol.for("SetBox");
|
export const $SetBox = Symbol.for("SetBox");
|
||||||
|
|
||||||
export const BoxState = _.Record.makeConstructor<{"_field0": number}, _ptr>()($BoxState, ["_field0"]);
|
export const BoxState = _.Record.makeConstructor<{"_field0": number}, _ptr>()($BoxState, ["_field0"]);
|
||||||
|
@ -13,11 +12,7 @@ export const SetBox = _.Record.makeConstructor<{"_field0": number}, _ptr>()($Set
|
||||||
|
|
||||||
export type SetBox = _.Record<(typeof $SetBox), [number], _ptr>;
|
export type SetBox = _.Record<(typeof $SetBox), [number], _ptr>;
|
||||||
|
|
||||||
export type BoxCap = (BoxState | _.Record<(typeof $Observe), [(typeof $SetBox), _ptr], _ptr>);
|
export type _ptr = _i_Actor.Ref;
|
||||||
|
|
||||||
export type ClientCap = (SetBox | _.Record<(typeof $Observe), [(typeof $BoxState), _ptr], _ptr>);
|
|
||||||
|
|
||||||
export type _ptr = _i_Pointer.Ref;
|
|
||||||
|
|
||||||
export type _val = _.Value<_ptr>;
|
export type _val = _.Value<_ptr>;
|
||||||
|
|
||||||
|
@ -46,33 +41,3 @@ export function asSetBox(v: any): SetBox {
|
||||||
if (!isSetBox(v)) {throw new TypeError(`Invalid SetBox: ${_.stringify(v)}`);} else {return v;};
|
if (!isSetBox(v)) {throw new TypeError(`Invalid SetBox: ${_.stringify(v)}`);} else {return v;};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isBoxCap(v: any): v is BoxCap {
|
|
||||||
return (
|
|
||||||
isBoxState(v) ||
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
|
||||||
_.is(v.label, $Observe) &&
|
|
||||||
((v.length === 2) && _.is(v[0], $SetBox) && _.isPointer(v[1]))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function asBoxCap(v: any): BoxCap {
|
|
||||||
if (!isBoxCap(v)) {throw new TypeError(`Invalid BoxCap: ${_.stringify(v)}`);} else {return v;};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isClientCap(v: any): v is ClientCap {
|
|
||||||
return (
|
|
||||||
isSetBox(v) ||
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
|
||||||
_.is(v.label, $Observe) &&
|
|
||||||
((v.length === 2) && _.is(v[0], $BoxState) && _.isPointer(v[1]))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function asClientCap(v: any): ClientCap {
|
|
||||||
if (!isClientCap(v)) {throw new TypeError(`Invalid ClientCap: ${_.stringify(v)}`);} else {return v;};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import * as _ from "@preserves/core";
|
import * as _ from "@preserves/core";
|
||||||
|
import * as _i_Actor from "../actor";
|
||||||
|
|
||||||
export const $Observe = Symbol.for("Observe");
|
export const $Observe = Symbol.for("Observe");
|
||||||
|
|
||||||
export const Observe = _.Record.makeConstructor<{"_field0": symbol, "_field1": _ptr}, _ptr>()($Observe, ["_field0","_field1"]);
|
export const Observe = _.Record.makeConstructor<{"label": symbol, "observer": _ptr}, _ptr>()($Observe, ["label","observer"]);
|
||||||
|
|
||||||
export type Observe = _.Record<(typeof $Observe), [symbol, _ptr], _ptr>;
|
export type Observe = _.Record<(typeof $Observe), [symbol, _ptr], _ptr>;
|
||||||
|
|
||||||
export type _ptr = never;
|
export type _ptr = _i_Actor.Ref;
|
||||||
|
|
||||||
export type _val = _.Value<_ptr>;
|
export type _val = _.Value<_ptr>;
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
import * as _ from "@preserves/core";
|
import * as _ from "@preserves/core";
|
||||||
import * as _i_rewrite from "./rewrite";
|
import * as _i_Protocol from "../protocol";
|
||||||
|
|
||||||
export const $assert = Symbol.for("assert");
|
export const $assert = Symbol.for("assert");
|
||||||
export const $message = Symbol.for("message");
|
export const $message = Symbol.for("message");
|
||||||
export const $or = Symbol.for("or");
|
|
||||||
export const $ref = Symbol.for("ref");
|
|
||||||
export const $retract = Symbol.for("retract");
|
export const $retract = Symbol.for("retract");
|
||||||
export const $sync = Symbol.for("sync");
|
export const $sync = Symbol.for("sync");
|
||||||
|
|
||||||
export const SturdyRef = _.Record.makeConstructor<{"_field0": _val, "_field1": Array<Caveat>, "_field2": _.Bytes}, _ptr>()($ref, ["_field0","_field1","_field2"]);
|
export type Assertion = _val;
|
||||||
|
|
||||||
export type SturdyRef = _.Record<(typeof $ref), [_val, Array<Caveat>, _.Bytes], _ptr>;
|
|
||||||
|
|
||||||
export type Caveat = (_i_rewrite.Rewrite | _.Record<(typeof $or), [Array<_i_rewrite.Rewrite>], _ptr>);
|
|
||||||
|
|
||||||
export type Handle = number;
|
export type Handle = number;
|
||||||
|
|
||||||
|
@ -22,70 +16,31 @@ export type Oid = number;
|
||||||
|
|
||||||
export type Turn = Array<[Oid, Event]>;
|
export type Turn = Array<[Oid, Event]>;
|
||||||
|
|
||||||
export const Assert = _.Record.makeConstructor<{"assertion": _val, "handle": Handle}, _ptr>()($assert, ["assertion","handle"]);
|
export const Assert = _.Record.makeConstructor<{"assertion": Assertion, "handle": Handle}, _ptr>()($assert, ["assertion","handle"]);
|
||||||
|
|
||||||
export type Assert = _.Record<(typeof $assert), [_val, Handle], _ptr>;
|
export type Assert = _.Record<(typeof $assert), [Assertion, Handle], _ptr>;
|
||||||
|
|
||||||
export const Retract = _.Record.makeConstructor<{"handle": Handle}, _ptr>()($retract, ["handle"]);
|
export const Retract = _.Record.makeConstructor<{"handle": Handle}, _ptr>()($retract, ["handle"]);
|
||||||
|
|
||||||
export type Retract = _.Record<(typeof $retract), [Handle], _ptr>;
|
export type Retract = _.Record<(typeof $retract), [Handle], _ptr>;
|
||||||
|
|
||||||
export const Message = _.Record.makeConstructor<{"body": _val}, _ptr>()($message, ["body"]);
|
export const Message = _.Record.makeConstructor<{"body": Assertion}, _ptr>()($message, ["body"]);
|
||||||
|
|
||||||
export type Message = _.Record<(typeof $message), [_val], _ptr>;
|
export type Message = _.Record<(typeof $message), [Assertion], _ptr>;
|
||||||
|
|
||||||
export const Sync = _.Record.makeConstructor<{"peer": _ptr}, _ptr>()($sync, ["peer"]);
|
export const Sync = _.Record.makeConstructor<{"peer": _ptr}, _ptr>()($sync, ["peer"]);
|
||||||
|
|
||||||
export type Sync = _.Record<(typeof $sync), [_ptr], _ptr>;
|
export type Sync = _.Record<(typeof $sync), [_ptr], _ptr>;
|
||||||
|
|
||||||
export type _ptr = never;
|
export type _ptr = _i_Protocol.WireRef;
|
||||||
|
|
||||||
export type _val = _.Value<_ptr>;
|
export type _val = _.Value<_ptr>;
|
||||||
|
|
||||||
|
|
||||||
export function isSturdyRef(v: any): v is SturdyRef {
|
export function isAssertion(v: any): v is Assertion {return true;}
|
||||||
return (
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
|
||||||
_.is(v.label, $ref) &&
|
|
||||||
(
|
|
||||||
(v.length === 3) &&
|
|
||||||
true &&
|
|
||||||
(
|
|
||||||
_.Array.isArray(v[1]) &&
|
|
||||||
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[1]) &&
|
|
||||||
(v[1].length >= 0) &&
|
|
||||||
v[1].slice(0).every(v => (isCaveat(v)))
|
|
||||||
) &&
|
|
||||||
_.Bytes.isBytes(v[2])
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function asSturdyRef(v: any): SturdyRef {
|
export function asAssertion(v: any): Assertion {
|
||||||
if (!isSturdyRef(v)) {throw new TypeError(`Invalid SturdyRef: ${_.stringify(v)}`);} else {return v;};
|
if (!isAssertion(v)) {throw new TypeError(`Invalid Assertion: ${_.stringify(v)}`);} else {return v;};
|
||||||
}
|
|
||||||
|
|
||||||
export function isCaveat(v: any): v is Caveat {
|
|
||||||
return (
|
|
||||||
_i_rewrite.isRewrite(v) ||
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
|
||||||
_.is(v.label, $or) &&
|
|
||||||
(
|
|
||||||
(v.length === 1) &&
|
|
||||||
(
|
|
||||||
_.Array.isArray(v[0]) &&
|
|
||||||
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0]) &&
|
|
||||||
(v[0].length >= 0) &&
|
|
||||||
v[0].slice(0).every(v => (_i_rewrite.isRewrite(v)))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function asCaveat(v: any): Caveat {
|
|
||||||
if (!isCaveat(v)) {throw new TypeError(`Invalid Caveat: ${_.stringify(v)}`);} else {return v;};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isHandle(v: any): v is Handle {return typeof v === 'number';}
|
export function isHandle(v: any): v is Handle {return typeof v === 'number';}
|
||||||
|
@ -131,7 +86,7 @@ export function isAssert(v: any): v is Assert {
|
||||||
return (
|
return (
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
_.is(v.label, $assert) &&
|
_.is(v.label, $assert) &&
|
||||||
((v.length === 2) && true && isHandle(v[1]))
|
((v.length === 2) && isAssertion(v[0]) && isHandle(v[1]))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +110,7 @@ export function isMessage(v: any): v is Message {
|
||||||
return (
|
return (
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
_.is(v.label, $message) &&
|
_.is(v.label, $message) &&
|
||||||
((v.length === 1) && true)
|
((v.length === 1) && isAssertion(v[0]))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,227 +0,0 @@
|
||||||
import * as _ from "@preserves/core";
|
|
||||||
|
|
||||||
export const $__ = Symbol.for("_");
|
|
||||||
export const $and = Symbol.for("and");
|
|
||||||
export const $arr = Symbol.for("arr");
|
|
||||||
export const $bind = Symbol.for("bind");
|
|
||||||
export const $compound = Symbol.for("compound");
|
|
||||||
export const $dict = Symbol.for("dict");
|
|
||||||
export const $lit = Symbol.for("lit");
|
|
||||||
export const $not = Symbol.for("not");
|
|
||||||
export const $rec = Symbol.for("rec");
|
|
||||||
export const $ref = Symbol.for("ref");
|
|
||||||
export const $rewrite = Symbol.for("rewrite");
|
|
||||||
export const __lit3 = Symbol.for("/");
|
|
||||||
|
|
||||||
export type ConstructorSpec = (
|
|
||||||
_.Record<(typeof $rec), [_val, number], _ptr> |
|
|
||||||
_.Record<(typeof $arr), [number], _ptr> |
|
|
||||||
_.Record<(typeof $dict), [], _ptr>
|
|
||||||
);
|
|
||||||
|
|
||||||
export const Pattern = _.Record.makeConstructor<{
|
|
||||||
"_field0": [
|
|
||||||
_.Record<(typeof $__), [], _ptr>,
|
|
||||||
_.Record<(typeof $bind), [symbol, Pattern], _ptr>,
|
|
||||||
_.Record<(typeof $and), [Array<Pattern>], _ptr>,
|
|
||||||
_.Record<(typeof $not), [Pattern], _ptr>,
|
|
||||||
_.Record<(typeof $lit), [_val], _ptr>,
|
|
||||||
_.Record<(typeof $compound), [ConstructorSpec, _.KeyedDictionary<_val, Pattern>], _ptr>
|
|
||||||
]
|
|
||||||
}, _ptr>()(__lit3, ["_field0"]);
|
|
||||||
|
|
||||||
export type Pattern = _.Record<
|
|
||||||
(typeof __lit3),
|
|
||||||
[
|
|
||||||
[
|
|
||||||
_.Record<(typeof $__), [], _ptr>,
|
|
||||||
_.Record<(typeof $bind), [symbol, Pattern], _ptr>,
|
|
||||||
_.Record<(typeof $and), [Array<Pattern>], _ptr>,
|
|
||||||
_.Record<(typeof $not), [Pattern], _ptr>,
|
|
||||||
_.Record<(typeof $lit), [_val], _ptr>,
|
|
||||||
_.Record<(typeof $compound), [ConstructorSpec, _.KeyedDictionary<_val, Pattern>], _ptr>
|
|
||||||
]
|
|
||||||
],
|
|
||||||
_ptr
|
|
||||||
>;
|
|
||||||
|
|
||||||
export const Template = _.Record.makeConstructor<{
|
|
||||||
"_field0": [
|
|
||||||
_.Record<(typeof $ref), [symbol], _ptr>,
|
|
||||||
_.Record<(typeof $lit), [_val], _ptr>,
|
|
||||||
_.Record<(typeof $compound), [ConstructorSpec, _.KeyedDictionary<_val, Template>], _ptr>
|
|
||||||
]
|
|
||||||
}, _ptr>()(__lit3, ["_field0"]);
|
|
||||||
|
|
||||||
export type Template = _.Record<
|
|
||||||
(typeof __lit3),
|
|
||||||
[
|
|
||||||
[
|
|
||||||
_.Record<(typeof $ref), [symbol], _ptr>,
|
|
||||||
_.Record<(typeof $lit), [_val], _ptr>,
|
|
||||||
_.Record<(typeof $compound), [ConstructorSpec, _.KeyedDictionary<_val, Template>], _ptr>
|
|
||||||
]
|
|
||||||
],
|
|
||||||
_ptr
|
|
||||||
>;
|
|
||||||
|
|
||||||
export const Rewrite = _.Record.makeConstructor<{"_field0": Pattern, "_field1": Template}, _ptr>()($rewrite, ["_field0","_field1"]);
|
|
||||||
|
|
||||||
export type Rewrite = _.Record<(typeof $rewrite), [Pattern, Template], _ptr>;
|
|
||||||
|
|
||||||
export type _ptr = never;
|
|
||||||
|
|
||||||
export type _val = _.Value<_ptr>;
|
|
||||||
|
|
||||||
|
|
||||||
export function isConstructorSpec(v: any): v is ConstructorSpec {
|
|
||||||
return (
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
|
||||||
_.is(v.label, $rec) &&
|
|
||||||
((v.length === 2) && true && typeof v[1] === 'number')
|
|
||||||
) ||
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
|
||||||
_.is(v.label, $arr) &&
|
|
||||||
((v.length === 1) && typeof v[0] === 'number')
|
|
||||||
) ||
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
|
||||||
_.is(v.label, $dict) &&
|
|
||||||
((v.length === 0))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function asConstructorSpec(v: any): ConstructorSpec {
|
|
||||||
if (!isConstructorSpec(v)) {throw new TypeError(`Invalid ConstructorSpec: ${_.stringify(v)}`);} else {return v;};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isPattern(v: any): v is Pattern {
|
|
||||||
return (
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
|
||||||
_.is(v.label, __lit3) &&
|
|
||||||
(
|
|
||||||
(v.length === 1) &&
|
|
||||||
(
|
|
||||||
_.Array.isArray(v[0]) &&
|
|
||||||
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0]) &&
|
|
||||||
(v[0].length === 6) &&
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0][0]) &&
|
|
||||||
_.is(v[0][0].label, $__) &&
|
|
||||||
((v[0][0].length === 0))
|
|
||||||
) &&
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0][1]) &&
|
|
||||||
_.is(v[0][1].label, $bind) &&
|
|
||||||
(
|
|
||||||
(v[0][1].length === 2) &&
|
|
||||||
typeof v[0][1][0] === 'symbol' &&
|
|
||||||
isPattern(v[0][1][1])
|
|
||||||
)
|
|
||||||
) &&
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0][2]) &&
|
|
||||||
_.is(v[0][2].label, $and) &&
|
|
||||||
(
|
|
||||||
(v[0][2].length === 1) &&
|
|
||||||
(
|
|
||||||
_.Array.isArray(v[0][2][0]) &&
|
|
||||||
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0][2][0]) &&
|
|
||||||
(v[0][2][0].length >= 0) &&
|
|
||||||
v[0][2][0].slice(0).every(v => (isPattern(v)))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) &&
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0][3]) &&
|
|
||||||
_.is(v[0][3].label, $not) &&
|
|
||||||
((v[0][3].length === 1) && isPattern(v[0][3][0]))
|
|
||||||
) &&
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0][4]) &&
|
|
||||||
_.is(v[0][4].label, $lit) &&
|
|
||||||
((v[0][4].length === 1) && true)
|
|
||||||
) &&
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0][5]) &&
|
|
||||||
_.is(v[0][5].label, $compound) &&
|
|
||||||
(
|
|
||||||
(v[0][5].length === 2) &&
|
|
||||||
isConstructorSpec(v[0][5][0]) &&
|
|
||||||
(
|
|
||||||
_.Dictionary.isDictionary<_val, _ptr>(v[0][5][1]) &&
|
|
||||||
((() => {
|
|
||||||
for (const e of v[0][5][1]) {if (!(true)) return false; if (!(isPattern(e[1]))) return false;};
|
|
||||||
return true;
|
|
||||||
})())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function asPattern(v: any): Pattern {
|
|
||||||
if (!isPattern(v)) {throw new TypeError(`Invalid Pattern: ${_.stringify(v)}`);} else {return v;};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isTemplate(v: any): v is Template {
|
|
||||||
return (
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
|
||||||
_.is(v.label, __lit3) &&
|
|
||||||
(
|
|
||||||
(v.length === 1) &&
|
|
||||||
(
|
|
||||||
_.Array.isArray(v[0]) &&
|
|
||||||
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0]) &&
|
|
||||||
(v[0].length === 3) &&
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0][0]) &&
|
|
||||||
_.is(v[0][0].label, $ref) &&
|
|
||||||
((v[0][0].length === 1) && typeof v[0][0][0] === 'symbol')
|
|
||||||
) &&
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0][1]) &&
|
|
||||||
_.is(v[0][1].label, $lit) &&
|
|
||||||
((v[0][1].length === 1) && true)
|
|
||||||
) &&
|
|
||||||
(
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0][2]) &&
|
|
||||||
_.is(v[0][2].label, $compound) &&
|
|
||||||
(
|
|
||||||
(v[0][2].length === 2) &&
|
|
||||||
isConstructorSpec(v[0][2][0]) &&
|
|
||||||
(
|
|
||||||
_.Dictionary.isDictionary<_val, _ptr>(v[0][2][1]) &&
|
|
||||||
((() => {
|
|
||||||
for (const e of v[0][2][1]) {if (!(true)) return false; if (!(isTemplate(e[1]))) return false;};
|
|
||||||
return true;
|
|
||||||
})())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function asTemplate(v: any): Template {
|
|
||||||
if (!isTemplate(v)) {throw new TypeError(`Invalid Template: ${_.stringify(v)}`);} else {return v;};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isRewrite(v: any): v is Rewrite {
|
|
||||||
return (
|
|
||||||
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
|
||||||
_.is(v.label, $rewrite) &&
|
|
||||||
((v.length === 2) && isPattern(v[0]) && isTemplate(v[1]))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function asRewrite(v: any): Rewrite {
|
|
||||||
if (!isRewrite(v)) {throw new TypeError(`Invalid Rewrite: ${_.stringify(v)}`);} else {return v;};
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,372 @@
|
||||||
|
import * as _ from "@preserves/core";
|
||||||
|
import * as _i_Actor from "../actor";
|
||||||
|
|
||||||
|
export const $__ = Symbol.for("_");
|
||||||
|
export const $and = Symbol.for("and");
|
||||||
|
export const $arr = Symbol.for("arr");
|
||||||
|
export const $bind = Symbol.for("bind");
|
||||||
|
export const $compound = Symbol.for("compound");
|
||||||
|
export const $dict = Symbol.for("dict");
|
||||||
|
export const $lit = Symbol.for("lit");
|
||||||
|
export const $not = Symbol.for("not");
|
||||||
|
export const $or = Symbol.for("or");
|
||||||
|
export const $rec = Symbol.for("rec");
|
||||||
|
export const $ref = Symbol.for("ref");
|
||||||
|
export const $resolve = Symbol.for("resolve");
|
||||||
|
export const $rewrite = Symbol.for("rewrite");
|
||||||
|
|
||||||
|
export const SturdyRef = _.Record.makeConstructor<{"oid": _val, "caveatChain": Array<Attenuation>, "sig": _.Bytes}, _ptr>()($ref, ["oid","caveatChain","sig"]);
|
||||||
|
|
||||||
|
export type SturdyRef = _.Record<(typeof $ref), [_val, Array<Attenuation>, _.Bytes], _ptr>;
|
||||||
|
|
||||||
|
export type Attenuation = Array<Caveat>;
|
||||||
|
|
||||||
|
export type Caveat = (Rewrite | Alts);
|
||||||
|
|
||||||
|
export const Rewrite = _.Record.makeConstructor<{"pattern": Pattern, "template": Template}, _ptr>()($rewrite, ["pattern","template"]);
|
||||||
|
|
||||||
|
export type Rewrite = _.Record<(typeof $rewrite), [Pattern, Template], _ptr>;
|
||||||
|
|
||||||
|
export const Alts = _.Record.makeConstructor<{"alternatives": Array<Rewrite>}, _ptr>()($or, ["alternatives"]);
|
||||||
|
|
||||||
|
export type Alts = _.Record<(typeof $or), [Array<Rewrite>], _ptr>;
|
||||||
|
|
||||||
|
export const Resolve = _.Record.makeConstructor<{"sturdyref": SturdyRef, "observer": _ptr}, _ptr>()($resolve, ["sturdyref","observer"]);
|
||||||
|
|
||||||
|
export type Resolve = _.Record<(typeof $resolve), [SturdyRef, _ptr], _ptr>;
|
||||||
|
|
||||||
|
export type ConstructorSpec = (CRec | CArr | CDict);
|
||||||
|
|
||||||
|
export const CRec = _.Record.makeConstructor<{"label": _val, "arity": number}, _ptr>()($rec, ["label","arity"]);
|
||||||
|
|
||||||
|
export type CRec = _.Record<(typeof $rec), [_val, number], _ptr>;
|
||||||
|
|
||||||
|
export const CArr = _.Record.makeConstructor<{"arity": number}, _ptr>()($arr, ["arity"]);
|
||||||
|
|
||||||
|
export type CArr = _.Record<(typeof $arr), [number], _ptr>;
|
||||||
|
|
||||||
|
export const CDict = _.Record.makeConstructor<{}, _ptr>()($dict, []);
|
||||||
|
|
||||||
|
export type CDict = _.Record<(typeof $dict), [], _ptr>;
|
||||||
|
|
||||||
|
export const Lit = _.Record.makeConstructor<{"value": _val}, _ptr>()($lit, ["value"]);
|
||||||
|
|
||||||
|
export type Lit = _.Record<(typeof $lit), [_val], _ptr>;
|
||||||
|
|
||||||
|
export type Pattern = (PDiscard | PBind | PAnd | PNot | Lit | PCompound);
|
||||||
|
|
||||||
|
export const PDiscard = _.Record.makeConstructor<{}, _ptr>()($__, []);
|
||||||
|
|
||||||
|
export type PDiscard = _.Record<(typeof $__), [], _ptr>;
|
||||||
|
|
||||||
|
export const PBind = _.Record.makeConstructor<{"name": symbol, "pattern": Pattern}, _ptr>()($bind, ["name","pattern"]);
|
||||||
|
|
||||||
|
export type PBind = _.Record<(typeof $bind), [symbol, Pattern], _ptr>;
|
||||||
|
|
||||||
|
export const PAnd = _.Record.makeConstructor<{"patterns": Array<Pattern>}, _ptr>()($and, ["patterns"]);
|
||||||
|
|
||||||
|
export type PAnd = _.Record<(typeof $and), [Array<Pattern>], _ptr>;
|
||||||
|
|
||||||
|
export const PNot = _.Record.makeConstructor<{"pattern": Pattern}, _ptr>()($not, ["pattern"]);
|
||||||
|
|
||||||
|
export type PNot = _.Record<(typeof $not), [Pattern], _ptr>;
|
||||||
|
|
||||||
|
export const PCompound = _.Record.makeConstructor<{"ctor": ConstructorSpec, "members": _.KeyedDictionary<_val, Pattern, _ptr>}, _ptr>()($compound, ["ctor","members"]);
|
||||||
|
|
||||||
|
export type PCompound = _.Record<
|
||||||
|
(typeof $compound),
|
||||||
|
[ConstructorSpec, _.KeyedDictionary<_val, Pattern, _ptr>],
|
||||||
|
_ptr
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type Template = (TRef | Lit | TCompound);
|
||||||
|
|
||||||
|
export const TRef = _.Record.makeConstructor<{"name": symbol}, _ptr>()($ref, ["name"]);
|
||||||
|
|
||||||
|
export type TRef = _.Record<(typeof $ref), [symbol], _ptr>;
|
||||||
|
|
||||||
|
export const TCompound = _.Record.makeConstructor<{"ctor": ConstructorSpec, "members": _.KeyedDictionary<_val, Template, _ptr>}, _ptr>()($compound, ["ctor","members"]);
|
||||||
|
|
||||||
|
export type TCompound = _.Record<
|
||||||
|
(typeof $compound),
|
||||||
|
[ConstructorSpec, _.KeyedDictionary<_val, Template, _ptr>],
|
||||||
|
_ptr
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type _ptr = _i_Actor.Ref;
|
||||||
|
|
||||||
|
export type _val = _.Value<_ptr>;
|
||||||
|
|
||||||
|
|
||||||
|
export function isSturdyRef(v: any): v is SturdyRef {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $ref) &&
|
||||||
|
(
|
||||||
|
(v.length === 3) &&
|
||||||
|
true &&
|
||||||
|
(
|
||||||
|
_.Array.isArray(v[1]) &&
|
||||||
|
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[1]) &&
|
||||||
|
(v[1].length >= 0) &&
|
||||||
|
v[1].slice(0).every(v => (isAttenuation(v)))
|
||||||
|
) &&
|
||||||
|
_.Bytes.isBytes(v[2])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asSturdyRef(v: any): SturdyRef {
|
||||||
|
if (!isSturdyRef(v)) {throw new TypeError(`Invalid SturdyRef: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isAttenuation(v: any): v is Attenuation {
|
||||||
|
return (
|
||||||
|
_.Array.isArray(v) &&
|
||||||
|
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
(v.length >= 0) &&
|
||||||
|
v.slice(0).every(v => (isCaveat(v)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asAttenuation(v: any): Attenuation {
|
||||||
|
if (!isAttenuation(v)) {throw new TypeError(`Invalid Attenuation: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCaveat(v: any): v is Caveat {return (isRewrite(v) || isAlts(v));}
|
||||||
|
|
||||||
|
export function asCaveat(v: any): Caveat {
|
||||||
|
if (!isCaveat(v)) {throw new TypeError(`Invalid Caveat: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isRewrite(v: any): v is Rewrite {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $rewrite) &&
|
||||||
|
((v.length === 2) && isPattern(v[0]) && isTemplate(v[1]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asRewrite(v: any): Rewrite {
|
||||||
|
if (!isRewrite(v)) {throw new TypeError(`Invalid Rewrite: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isAlts(v: any): v is Alts {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $or) &&
|
||||||
|
(
|
||||||
|
(v.length === 1) &&
|
||||||
|
(
|
||||||
|
_.Array.isArray(v[0]) &&
|
||||||
|
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0]) &&
|
||||||
|
(v[0].length >= 0) &&
|
||||||
|
v[0].slice(0).every(v => (isRewrite(v)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asAlts(v: any): Alts {
|
||||||
|
if (!isAlts(v)) {throw new TypeError(`Invalid Alts: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isResolve(v: any): v is Resolve {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $resolve) &&
|
||||||
|
((v.length === 2) && isSturdyRef(v[0]) && _.isPointer(v[1]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asResolve(v: any): Resolve {
|
||||||
|
if (!isResolve(v)) {throw new TypeError(`Invalid Resolve: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isConstructorSpec(v: any): v is ConstructorSpec {return (isCRec(v) || isCArr(v) || isCDict(v));}
|
||||||
|
|
||||||
|
export function asConstructorSpec(v: any): ConstructorSpec {
|
||||||
|
if (!isConstructorSpec(v)) {throw new TypeError(`Invalid ConstructorSpec: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCRec(v: any): v is CRec {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $rec) &&
|
||||||
|
((v.length === 2) && true && typeof v[1] === 'number')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asCRec(v: any): CRec {
|
||||||
|
if (!isCRec(v)) {throw new TypeError(`Invalid CRec: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCArr(v: any): v is CArr {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $arr) &&
|
||||||
|
((v.length === 1) && typeof v[0] === 'number')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asCArr(v: any): CArr {
|
||||||
|
if (!isCArr(v)) {throw new TypeError(`Invalid CArr: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isCDict(v: any): v is CDict {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $dict) &&
|
||||||
|
((v.length === 0))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asCDict(v: any): CDict {
|
||||||
|
if (!isCDict(v)) {throw new TypeError(`Invalid CDict: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isLit(v: any): v is Lit {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $lit) &&
|
||||||
|
((v.length === 1) && true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asLit(v: any): Lit {
|
||||||
|
if (!isLit(v)) {throw new TypeError(`Invalid Lit: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPattern(v: any): v is Pattern {
|
||||||
|
return (
|
||||||
|
isPDiscard(v) ||
|
||||||
|
isPBind(v) ||
|
||||||
|
isPAnd(v) ||
|
||||||
|
isPNot(v) ||
|
||||||
|
isLit(v) ||
|
||||||
|
isPCompound(v)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asPattern(v: any): Pattern {
|
||||||
|
if (!isPattern(v)) {throw new TypeError(`Invalid Pattern: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPDiscard(v: any): v is PDiscard {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $__) &&
|
||||||
|
((v.length === 0))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asPDiscard(v: any): PDiscard {
|
||||||
|
if (!isPDiscard(v)) {throw new TypeError(`Invalid PDiscard: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPBind(v: any): v is PBind {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $bind) &&
|
||||||
|
((v.length === 2) && typeof v[0] === 'symbol' && isPattern(v[1]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asPBind(v: any): PBind {
|
||||||
|
if (!isPBind(v)) {throw new TypeError(`Invalid PBind: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPAnd(v: any): v is PAnd {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $and) &&
|
||||||
|
(
|
||||||
|
(v.length === 1) &&
|
||||||
|
(
|
||||||
|
_.Array.isArray(v[0]) &&
|
||||||
|
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v[0]) &&
|
||||||
|
(v[0].length >= 0) &&
|
||||||
|
v[0].slice(0).every(v => (isPattern(v)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asPAnd(v: any): PAnd {
|
||||||
|
if (!isPAnd(v)) {throw new TypeError(`Invalid PAnd: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPNot(v: any): v is PNot {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $not) &&
|
||||||
|
((v.length === 1) && isPattern(v[0]))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asPNot(v: any): PNot {
|
||||||
|
if (!isPNot(v)) {throw new TypeError(`Invalid PNot: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPCompound(v: any): v is PCompound {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $compound) &&
|
||||||
|
(
|
||||||
|
(v.length === 2) &&
|
||||||
|
isConstructorSpec(v[0]) &&
|
||||||
|
(
|
||||||
|
_.Dictionary.isDictionary<_val, _ptr>(v[1]) &&
|
||||||
|
((() => {
|
||||||
|
for (const e of v[1]) {if (!(true)) return false; if (!(isPattern(e[1]))) return false;};
|
||||||
|
return true;
|
||||||
|
})())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asPCompound(v: any): PCompound {
|
||||||
|
if (!isPCompound(v)) {throw new TypeError(`Invalid PCompound: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTemplate(v: any): v is Template {return (isTRef(v) || isLit(v) || isTCompound(v));}
|
||||||
|
|
||||||
|
export function asTemplate(v: any): Template {
|
||||||
|
if (!isTemplate(v)) {throw new TypeError(`Invalid Template: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTRef(v: any): v is TRef {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $ref) &&
|
||||||
|
((v.length === 1) && typeof v[0] === 'symbol')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asTRef(v: any): TRef {
|
||||||
|
if (!isTRef(v)) {throw new TypeError(`Invalid TRef: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTCompound(v: any): v is TCompound {
|
||||||
|
return (
|
||||||
|
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
|
||||||
|
_.is(v.label, $compound) &&
|
||||||
|
(
|
||||||
|
(v.length === 2) &&
|
||||||
|
isConstructorSpec(v[0]) &&
|
||||||
|
(
|
||||||
|
_.Dictionary.isDictionary<_val, _ptr>(v[1]) &&
|
||||||
|
((() => {
|
||||||
|
for (const e of v[1]) {if (!(true)) return false; if (!(isTemplate(e[1]))) return false;};
|
||||||
|
return true;
|
||||||
|
})())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function asTCompound(v: any): TCompound {
|
||||||
|
if (!isTCompound(v)) {throw new TypeError(`Invalid TCompound: ${_.stringify(v)}`);} else {return v;};
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { Actor, Assertion, Turn } from './actor.js';
|
import { Actor, Assertion, Ref, Turn } from './actor.js';
|
||||||
import { Dictionary, Record } from '@preserves/core';
|
import { Dictionary, Record } from '@preserves/core';
|
||||||
import { Dataspace, Observe } from './dataspace.js';
|
import { Dataspace, Observe } from './dataspace.js';
|
||||||
import { Worker } from 'worker_threads';
|
import { Worker } from 'worker_threads';
|
||||||
import { Relay, spawnRelay } from './relay.js';
|
import { Relay, spawnRelay } from './relay.js';
|
||||||
import { BoxState, SetBox } from './gen/box-protocol.js';
|
|
||||||
import { attenuate, CRec, Lit, Pattern, PCompound, rfilter } from './rewrite.js';
|
import { attenuate, CRec, Lit, Pattern, PCompound, rfilter } from './rewrite.js';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
|
import { BoxState, SetBox } from './gen/box-protocol.js';
|
||||||
|
|
||||||
const Instance = Record.makeConstructor<{moduleName: string, arg: Assertion}>()(
|
const Instance = Record.makeConstructor<{moduleName: string, arg: Assertion}>()(
|
||||||
Symbol.for('Instance'), ['moduleName', 'arg']);
|
Symbol.for('Instance'), ['moduleName', 'arg']);
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ Turn.for(new Actor(), async (t: Turn) => {
|
||||||
new Dictionary()),
|
new Dictionary()),
|
||||||
PCompound(CRec(Observe.constructorInfo.label,
|
PCompound(CRec(Observe.constructorInfo.label,
|
||||||
Observe.constructorInfo.arity),
|
Observe.constructorInfo.arity),
|
||||||
new Dictionary<Pattern, never>([
|
new Dictionary<Pattern, Ref>([
|
||||||
[0, Lit(SetBox.constructorInfo.label)]]))));
|
[0, Lit(SetBox.constructorInfo.label)]]))));
|
||||||
|
|
||||||
const ds_for_client = attenuate(
|
const ds_for_client = attenuate(
|
||||||
|
@ -70,7 +71,7 @@ Turn.for(new Actor(), async (t: Turn) => {
|
||||||
new Dictionary()),
|
new Dictionary()),
|
||||||
PCompound(CRec(Observe.constructorInfo.label,
|
PCompound(CRec(Observe.constructorInfo.label,
|
||||||
Observe.constructorInfo.arity),
|
Observe.constructorInfo.arity),
|
||||||
new Dictionary<Pattern, never>([
|
new Dictionary<Pattern, Ref>([
|
||||||
[0, Lit(BoxState.constructorInfo.label)]]))));
|
[0, Lit(BoxState.constructorInfo.label)]]))));
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,77 +1,17 @@
|
||||||
import { Handle, Ref } from './actor.js';
|
import { Attenuation } from './gen/sturdy.js';
|
||||||
import { Attenuation, Pattern, Template } from './rewrite.js';
|
import * as IO from './gen/protocol.js';
|
||||||
import { Record, Value } from '@preserves/core';
|
import { Ref } from './actor.js';
|
||||||
|
|
||||||
export const _Assert = Symbol.for('assert');
|
export type WireSymbol = { oid: IO.Oid, ref: Ref, count: number };
|
||||||
export const _Retract = Symbol.for('retract');
|
|
||||||
export const _Message = Symbol.for('message');
|
|
||||||
export const _Sync = Symbol.for('sync');
|
|
||||||
|
|
||||||
function mk<T extends object>() {
|
|
||||||
return {
|
|
||||||
Assert: Record.makeConstructor<{assertion: Value<T>, handle: Handle}, T>()(
|
|
||||||
_Assert, ['assertion', 'handle']),
|
|
||||||
Retract: Record.makeConstructor<{handle: Handle}, T>()(
|
|
||||||
_Retract, ['handle']),
|
|
||||||
Message: Record.makeConstructor<{body: Value<T>}, T>()(
|
|
||||||
_Message, ['body']),
|
|
||||||
Sync: Record.makeConstructor<{peer: T}, T>()(
|
|
||||||
_Sync, ['peer']),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export type EntityMessage<T extends object> =
|
|
||||||
| Record<typeof _Assert, [Value<T>, Handle], T>
|
|
||||||
| Record<typeof _Retract, [Handle], T>
|
|
||||||
| Record<typeof _Message, [Value<T>], T>
|
|
||||||
| Record<typeof _Sync, [T], T>;
|
|
||||||
|
|
||||||
export type TurnMessage<T extends object> = Array<[Oid, EntityMessage<T>]>;
|
|
||||||
|
|
||||||
export type Oid = number;
|
|
||||||
|
|
||||||
export type WireSymbol = { oid: Oid, ref: Ref, count: number };
|
|
||||||
|
|
||||||
export type WireRef =
|
export type WireRef =
|
||||||
| { loc: "mine", oid: Oid }
|
| { loc: "mine", oid: IO.Oid }
|
||||||
| { loc: "your", oid: Oid, attenuation: EncodedAttenuation };
|
| { loc: "your", oid: IO.Oid, attenuation: Attenuation };
|
||||||
|
|
||||||
export const IO = mk<WireRef>();
|
export function myRef(oid: IO.Oid): WireRef & { loc: "mine" } {
|
||||||
|
|
||||||
export function myRef(oid: Oid): WireRef & { loc: "mine" } {
|
|
||||||
return { loc: 'mine', oid };
|
return { loc: 'mine', oid };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function yourRef(oid: Oid, attenuation: EncodedAttenuation): WireRef & { loc: "your" } {
|
export function yourRef(oid: IO.Oid, attenuation: Attenuation): WireRef & { loc: "your" } {
|
||||||
return { loc: 'your', oid, attenuation };
|
return { loc: 'your', oid, attenuation };
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EncodedAttenuation = Array<Array<[Value<WireRef>, Value<WireRef>]>>;
|
|
||||||
|
|
||||||
export function encodeAttenuation(a: Attenuation | undefined): EncodedAttenuation {
|
|
||||||
if (a === void 0) return [];
|
|
||||||
return a.map(s => s.map(({pattern, template}) => [
|
|
||||||
pattern as Value<WireRef>,
|
|
||||||
template as Value<WireRef>,
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function decodeAttenuation(v: Array<Value<WireRef>>): Attenuation {
|
|
||||||
function complain(): never {
|
|
||||||
throw new Error(
|
|
||||||
`Received invalid attenuation ${v.asPreservesText()} from peer`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v.length === 0) return [];
|
|
||||||
return v.map(s => {
|
|
||||||
if (!Array.isArray(s)) complain();
|
|
||||||
return s.map(e => {
|
|
||||||
if (!(Array.isArray(e) && e.length === 2)) complain();
|
|
||||||
// TODO: check structure of pattern and template
|
|
||||||
return {
|
|
||||||
pattern: e[0] as Pattern,
|
|
||||||
template: e[1] as Template,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
69
src/relay.ts
69
src/relay.ts
|
@ -1,24 +1,11 @@
|
||||||
import { Actor, Assertion, Entity, Handle, Ref, Turn } from './actor.js';
|
import { Actor, Assertion, Entity, Handle, Ref, Turn } from './actor.js';
|
||||||
import { BytesLike, canonicalString, Decoder, encode, FlexMap, IdentityMap, mapPointers, underlying, Value } from '@preserves/core';
|
import { BytesLike, canonicalString, Decoder, encode, FlexMap, IdentityMap, mapPointers, underlying, Value } from '@preserves/core';
|
||||||
import {
|
import * as IO from './gen/protocol.js';
|
||||||
EncodedAttenuation,
|
import { myRef, WireRef, WireSymbol, yourRef } from './protocol.js';
|
||||||
EntityMessage,
|
|
||||||
IO,
|
|
||||||
Oid,
|
|
||||||
TurnMessage,
|
|
||||||
WireRef,
|
|
||||||
WireSymbol,
|
|
||||||
_Assert,
|
|
||||||
_Message,
|
|
||||||
_Retract,
|
|
||||||
_Sync,
|
|
||||||
decodeAttenuation,
|
|
||||||
encodeAttenuation,
|
|
||||||
myRef,
|
|
||||||
yourRef,
|
|
||||||
} from './protocol.js';
|
|
||||||
import { queueTask } from './task.js';
|
import { queueTask } from './task.js';
|
||||||
import { attenuate } from './rewrite.js';
|
import { attenuate } from './rewrite.js';
|
||||||
|
import { asAttenuation, Attenuation } from './gen/sturdy.js';
|
||||||
|
import { pointerNotAllowed } from './sturdy.js';
|
||||||
|
|
||||||
export class SyncPeerEntity implements Entity {
|
export class SyncPeerEntity implements Entity {
|
||||||
readonly relay: Relay;
|
readonly relay: Relay;
|
||||||
|
@ -53,14 +40,14 @@ export class SyncPeerEntity implements Entity {
|
||||||
|
|
||||||
export class RelayEntity implements Entity {
|
export class RelayEntity implements Entity {
|
||||||
readonly relay: Relay;
|
readonly relay: Relay;
|
||||||
readonly oid: Oid;
|
readonly oid: IO.Oid;
|
||||||
|
|
||||||
constructor(relay: Relay, oid: Oid) {
|
constructor(relay: Relay, oid: IO.Oid) {
|
||||||
this.relay = relay;
|
this.relay = relay;
|
||||||
this.oid = oid;
|
this.oid = oid;
|
||||||
}
|
}
|
||||||
|
|
||||||
send(m: EntityMessage<WireRef>): void {
|
send(m: IO.Event): void {
|
||||||
this.relay.send(this.oid, m);
|
this.relay.send(this.oid, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +74,7 @@ export class RelayEntity implements Entity {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Membrane {
|
export class Membrane {
|
||||||
readonly byOid = new IdentityMap<Oid, WireSymbol>();
|
readonly byOid = new IdentityMap<IO.Oid, WireSymbol>();
|
||||||
readonly byRef = new IdentityMap<Ref, WireSymbol>();
|
readonly byRef = new IdentityMap<Ref, WireSymbol>();
|
||||||
|
|
||||||
grab<Table extends "byOid" | "byRef">(table: Table,
|
grab<Table extends "byOid" | "byRef">(table: Table,
|
||||||
|
@ -142,8 +129,8 @@ export class Relay {
|
||||||
readonly outboundAssertions = new IdentityMap<Handle, Array<WireSymbol>>();
|
readonly outboundAssertions = new IdentityMap<Handle, Array<WireSymbol>>();
|
||||||
readonly exported = new Membrane();
|
readonly exported = new Membrane();
|
||||||
readonly imported = new Membrane();
|
readonly imported = new Membrane();
|
||||||
nextLocalOid: Oid = 0;
|
nextLocalOid: IO.Oid = 0;
|
||||||
pendingTurn: TurnMessage<WireRef> = [];
|
pendingTurn: IO.Turn = [];
|
||||||
debug: boolean;
|
debug: boolean;
|
||||||
trustPeer: boolean;
|
trustPeer: boolean;
|
||||||
|
|
||||||
|
@ -157,14 +144,13 @@ export class Relay {
|
||||||
if (!(Array.isArray(v) && v.length >= 2 && typeof v[1] === 'number')) {
|
if (!(Array.isArray(v) && v.length >= 2 && typeof v[1] === 'number')) {
|
||||||
complain();
|
complain();
|
||||||
}
|
}
|
||||||
const oid = v[1] as Oid;
|
const oid = v[1] as IO.Oid;
|
||||||
switch (v[0]) {
|
switch (v[0]) {
|
||||||
case 0:
|
case 0:
|
||||||
if (v.length > 2) complain();
|
if (v.length > 2) complain();
|
||||||
return myRef(oid);
|
return myRef(oid);
|
||||||
case 1:
|
case 1:
|
||||||
// TODO: check EncodedAttenuation
|
return yourRef(oid, asAttenuation(v.slice(2)));
|
||||||
return yourRef(oid, v.slice(2) as EncodedAttenuation);
|
|
||||||
default:
|
default:
|
||||||
complain();
|
complain();
|
||||||
}
|
}
|
||||||
|
@ -212,7 +198,7 @@ export class Relay {
|
||||||
// This reference has been attenuated since it was sent to us.
|
// This reference has been attenuated since it was sent to us.
|
||||||
// Do we trust the peer to enforce such attenuation on our behalf?
|
// Do we trust the peer to enforce such attenuation on our behalf?
|
||||||
if (this.trustPeer) {
|
if (this.trustPeer) {
|
||||||
return yourRef(r.target.oid, encodeAttenuation(r.attenuation));
|
return yourRef(r.target.oid, r.attenuation);
|
||||||
} else {
|
} else {
|
||||||
// fall through: treat the attenuated ref as a local ref, and re-export it.
|
// fall through: treat the attenuated ref as a local ref, and re-export it.
|
||||||
}
|
}
|
||||||
|
@ -239,13 +225,13 @@ export class Relay {
|
||||||
if (n.attenuation.length === 0 || r === INERT_REF) {
|
if (n.attenuation.length === 0 || r === INERT_REF) {
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
type AttenuatedRef = Ref & { __attenuations?: FlexMap<EncodedAttenuation, Ref> };
|
type AttenuatedRef = Ref & { __attenuations?: FlexMap<Attenuation, Ref> };
|
||||||
const ar = r as AttenuatedRef;
|
const ar = r as AttenuatedRef;
|
||||||
if (ar.__attenuations === void 0) {
|
if (ar.__attenuations === void 0) {
|
||||||
ar.__attenuations = new FlexMap(canonicalString);
|
ar.__attenuations = new FlexMap(canonicalString);
|
||||||
}
|
}
|
||||||
return ar.__attenuations.getOrSet(n.attenuation, () =>
|
return ar.__attenuations.getOrSet(n.attenuation, () =>
|
||||||
attenuate(r, ... decodeAttenuation(n.attenuation)));
|
attenuate(r, ... n.attenuation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'mine': {
|
case 'mine': {
|
||||||
|
@ -257,7 +243,7 @@ export class Relay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
send(remoteOid: Oid, m: EntityMessage<WireRef>): void {
|
send(remoteOid: IO.Oid, m: IO.Event): void {
|
||||||
if (this.pendingTurn.length === 0) {
|
if (this.pendingTurn.length === 0) {
|
||||||
queueTask(() => {
|
queueTask(() => {
|
||||||
if (this.debug) console.log('OUT', this.pendingTurn.asPreservesText());
|
if (this.debug) console.log('OUT', this.pendingTurn.asPreservesText());
|
||||||
|
@ -266,7 +252,8 @@ export class Relay {
|
||||||
encodePointer: n => {
|
encodePointer: n => {
|
||||||
switch (n.loc) {
|
switch (n.loc) {
|
||||||
case 'mine': return [0, n.oid];
|
case 'mine': return [0, n.oid];
|
||||||
case 'your': return [1, n.oid, ... n.attenuation];
|
case 'your': return [1, n.oid, ... mapPointers<Ref, IO._ptr>(
|
||||||
|
n.attenuation, pointerNotAllowed) as Array<IO._val>];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})));
|
})));
|
||||||
|
@ -276,7 +263,7 @@ export class Relay {
|
||||||
this.pendingTurn.push([remoteOid, m]);
|
this.pendingTurn.push([remoteOid, m]);
|
||||||
}
|
}
|
||||||
|
|
||||||
lookupLocal(localOid: Oid): Ref {
|
lookupLocal(localOid: IO.Oid): Ref {
|
||||||
return this.exported.byOid.get(localOid)?.ref ?? INERT_REF;
|
return this.exported.byOid.get(localOid)?.ref ?? INERT_REF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,7 +271,7 @@ export class Relay {
|
||||||
Turn.for(this.actor, t => {
|
Turn.for(this.actor, t => {
|
||||||
this.decoder.write(bs);
|
this.decoder.write(bs);
|
||||||
while (true) {
|
while (true) {
|
||||||
const wireTurn = this.decoder.try_next() as (TurnMessage<WireRef> | undefined);
|
const wireTurn = this.decoder.try_next() as (IO.Turn | undefined);
|
||||||
if (wireTurn === void 0) break;
|
if (wireTurn === void 0) break;
|
||||||
// TODO: deep check that wireTurn really is a TurnMessage
|
// TODO: deep check that wireTurn really is a TurnMessage
|
||||||
if (this.debug) console.log('IN', wireTurn.asPreservesText());
|
if (this.debug) console.log('IN', wireTurn.asPreservesText());
|
||||||
|
@ -296,9 +283,9 @@ export class Relay {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handle(t: Turn, r: Ref, m: EntityMessage<WireRef>) {
|
handle(t: Turn, r: Ref, m: IO.Event) {
|
||||||
switch (m.label) {
|
switch (m.label) {
|
||||||
case _Assert: {
|
case IO.$assert: {
|
||||||
const [a, imported] = this.rewriteIn(t, IO.Assert._.assertion(m));
|
const [a, imported] = this.rewriteIn(t, IO.Assert._.assertion(m));
|
||||||
this.inboundAssertions.set(IO.Assert._.handle(m), {
|
this.inboundAssertions.set(IO.Assert._.handle(m), {
|
||||||
localHandle: t.assert(r, a),
|
localHandle: t.assert(r, a),
|
||||||
|
@ -306,7 +293,7 @@ export class Relay {
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _Retract: {
|
case IO.$retract: {
|
||||||
const remoteHandle = IO.Retract._.handle(m);
|
const remoteHandle = IO.Retract._.handle(m);
|
||||||
const h = this.inboundAssertions.get(remoteHandle);
|
const h = this.inboundAssertions.get(remoteHandle);
|
||||||
if (h === void 0) throw new Error(`Peer retracted invalid handle ${remoteHandle}`);
|
if (h === void 0) throw new Error(`Peer retracted invalid handle ${remoteHandle}`);
|
||||||
|
@ -315,13 +302,13 @@ export class Relay {
|
||||||
t.retract(h.localHandle);
|
t.retract(h.localHandle);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _Message: {
|
case IO.$message: {
|
||||||
const [a, imported] = this.rewriteIn(t, IO.Message._.body(m));
|
const [a, imported] = this.rewriteIn(t, IO.Message._.body(m));
|
||||||
if (imported.length > 0) throw new Error("Cannot receive transient reference");
|
if (imported.length > 0) throw new Error("Cannot receive transient reference");
|
||||||
t.message(r, a);
|
t.message(r, a);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case _Sync: {
|
case IO.$sync: {
|
||||||
const imported: Array<WireSymbol> = [];
|
const imported: Array<WireSymbol> = [];
|
||||||
const k = this.rewriteRefIn(t, IO.Sync._.peer(m), imported);
|
const k = this.rewriteRefIn(t, IO.Sync._.peer(m), imported);
|
||||||
t.sync(r).then(t => {
|
t.sync(r).then(t => {
|
||||||
|
@ -335,12 +322,12 @@ export class Relay {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RelayActorOptions extends RelayOptions {
|
export interface RelayActorOptions extends RelayOptions {
|
||||||
initialOid?: Oid;
|
initialOid?: IO.Oid;
|
||||||
initialRef?: Ref;
|
initialRef?: Ref;
|
||||||
nextLocalOid?: Oid;
|
nextLocalOid?: IO.Oid;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function spawnRelay(t: Turn, options: RelayActorOptions & {initialOid: Oid}): Promise<Ref>;
|
export function spawnRelay(t: Turn, options: RelayActorOptions & {initialOid: IO.Oid}): Promise<Ref>;
|
||||||
export function spawnRelay(t: Turn, options: Omit<RelayActorOptions, 'initialOid'>): Promise<null>;
|
export function spawnRelay(t: Turn, options: Omit<RelayActorOptions, 'initialOid'>): Promise<null>;
|
||||||
export function spawnRelay(t: Turn, options: RelayActorOptions): Promise<Ref | null>
|
export function spawnRelay(t: Turn, options: RelayActorOptions): Promise<Ref | null>
|
||||||
{
|
{
|
||||||
|
|
172
src/rewrite.ts
172
src/rewrite.ts
|
@ -1,124 +1,59 @@
|
||||||
import type { Assertion, Bindings, Handle, Ref, Turn } from "./actor.js";
|
import type { Assertion, Bindings, Handle, Ref, Turn } from "./actor.js";
|
||||||
import { Dictionary, IdentityMap, is, Record, Tuple, Value } from "@preserves/core";
|
import { Dictionary, IdentityMap, is, Record, Tuple } from "@preserves/core";
|
||||||
|
|
||||||
export type Attenuation = Array<RewriteStage>; // array of stages, each a list of alternatives
|
import * as S from './gen/sturdy.js';
|
||||||
export type RewriteStage = Array<Rewrite>;
|
export * from './gen/sturdy.js';
|
||||||
export type Rewrite = { pattern: Pattern, template: Template };
|
|
||||||
|
|
||||||
export const _CRec = Symbol.for('rec');
|
export function match(p: S.Pattern, v: Assertion): Bindings | null {
|
||||||
export const CRec = Record.makeConstructor<{label: Value<never>, arity: number}, never>()(
|
|
||||||
_CRec, ['label', 'arity']);
|
|
||||||
|
|
||||||
export const _CArr = Symbol.for('arr');
|
|
||||||
export const CArr = Record.makeConstructor<{arity: number}, never>()(
|
|
||||||
_CArr, ['arity']);
|
|
||||||
|
|
||||||
export const _CDict = Symbol.for('dict');
|
|
||||||
export const CDict = Record.makeConstructor<{}, never>()(
|
|
||||||
_CDict, []);
|
|
||||||
|
|
||||||
export type ConstructorSpec =
|
|
||||||
| Record<typeof _CRec, [Value<never>, number], never>
|
|
||||||
| Record<typeof _CArr, [number], never>
|
|
||||||
| Record<typeof _CDict, [], never>;
|
|
||||||
|
|
||||||
export const _PDiscard = Symbol.for('_');
|
|
||||||
export const PDiscard = Record.makeConstructor<{}, never>()(
|
|
||||||
_PDiscard, []);
|
|
||||||
|
|
||||||
export const _PBind = Symbol.for('bind');
|
|
||||||
export const PBind = Record.makeConstructor<{name: symbol, pattern: Pattern}, never>()(
|
|
||||||
_PBind, ['name', 'pattern']);
|
|
||||||
|
|
||||||
export const _PAnd = Symbol.for('and');
|
|
||||||
export const PAnd = Record.makeConstructor<{patterns: Array<Pattern>}, never>()(
|
|
||||||
_PAnd, ['patterns']);
|
|
||||||
|
|
||||||
export const _PNot = Symbol.for('not');
|
|
||||||
export const PNot = Record.makeConstructor<{pattern: Pattern}, never>()(
|
|
||||||
_PNot, ['pattern']);
|
|
||||||
|
|
||||||
export const _Lit = Symbol.for('lit');
|
|
||||||
export const Lit = Record.makeConstructor<{value: Value<never>}, never>()(
|
|
||||||
_Lit, ['value']);
|
|
||||||
|
|
||||||
export const _PCompound = Symbol.for('compound');
|
|
||||||
export const PCompound =
|
|
||||||
Record.makeConstructor<{ctor: ConstructorSpec, members: Dictionary<Pattern, never>}, never>()(
|
|
||||||
_PCompound, ['ctor', 'members']);
|
|
||||||
|
|
||||||
export type Pattern =
|
|
||||||
| Record<typeof _PDiscard, [], never>
|
|
||||||
| Record<typeof _PBind, [symbol, Pattern], never>
|
|
||||||
| Record<typeof _PAnd, [Pattern[]], never>
|
|
||||||
| Record<typeof _PNot, [Pattern], never>
|
|
||||||
| Record<typeof _Lit, [Value<never>], never>
|
|
||||||
| Record<typeof _PCompound, [ConstructorSpec, Dictionary<Pattern, never>], never>;
|
|
||||||
|
|
||||||
export const _TRef = Symbol.for('ref');
|
|
||||||
export const TRef = Record.makeConstructor<{name: symbol}, never>()(
|
|
||||||
_TRef, ['name']);
|
|
||||||
|
|
||||||
export const _TCompound = Symbol.for('compound');
|
|
||||||
export const TCompound =
|
|
||||||
Record.makeConstructor<{ctor: ConstructorSpec, members: Dictionary<Template, never>}, never>()(
|
|
||||||
_TCompound, ['ctor', 'members']);
|
|
||||||
|
|
||||||
export type Template =
|
|
||||||
| Record<typeof _TRef, [symbol], never>
|
|
||||||
| Record<typeof _Lit, [Value<never>], never>
|
|
||||||
| Record<typeof _TCompound, [ConstructorSpec, Dictionary<Template, never>], never>;
|
|
||||||
|
|
||||||
export function match(p: Pattern, v: Assertion): Bindings | null {
|
|
||||||
let bindings: Bindings = {};
|
let bindings: Bindings = {};
|
||||||
|
|
||||||
function walk(p: Pattern, v: Assertion): boolean {
|
function walk(p: S.Pattern, v: Assertion): boolean {
|
||||||
switch (p.label) {
|
switch (p.label) {
|
||||||
case _PDiscard:
|
case S.$__:
|
||||||
return true;
|
return true;
|
||||||
case _PBind:
|
case S.$bind:
|
||||||
if (walk(PBind._.pattern(p), v)) {
|
if (walk(S.PBind._.pattern(p), v)) {
|
||||||
bindings[PBind._.name(p).asPreservesText()] = v;
|
bindings[S.PBind._.name(p).asPreservesText()] = v;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
case _PAnd:
|
case S.$and:
|
||||||
for (const pp of PAnd._.patterns(p)) {
|
for (const pp of S.PAnd._.patterns(p)) {
|
||||||
if (!walk(pp, v)) return false;
|
if (!walk(pp, v)) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case _PNot: {
|
case S.$not: {
|
||||||
const savedBindings = bindings;
|
const savedBindings = bindings;
|
||||||
bindings = {};
|
bindings = {};
|
||||||
const result = !walk(PNot._.pattern(p), v)
|
const result = !walk(S.PNot._.pattern(p), v)
|
||||||
bindings = savedBindings;
|
bindings = savedBindings;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
case _Lit:
|
case S.$lit:
|
||||||
return is(Lit._.value(p), v);
|
return is(S.Lit._.value(p), v);
|
||||||
case _PCompound: {
|
case S.$compound: {
|
||||||
const ctor = PCompound._.ctor(p);
|
const ctor = S.PCompound._.ctor(p);
|
||||||
const members = PCompound._.members(p);
|
const members = S.PCompound._.members(p);
|
||||||
switch (ctor.label) {
|
switch (ctor.label) {
|
||||||
case _CRec:
|
case S.$rec:
|
||||||
if (!Record.isRecord<Assertion, Tuple<Assertion>, Ref>(v)) return false;
|
if (!Record.isRecord<Assertion, Tuple<Assertion>, Ref>(v)) return false;
|
||||||
if (!is(CRec._.label(ctor), v.label)) return false;
|
if (!is(S.CRec._.label(ctor), v.label)) return false;
|
||||||
if (CRec._.arity(ctor) !== v.length) return false;
|
if (S.CRec._.arity(ctor) !== v.length) return false;
|
||||||
for (const [key, pp] of members) {
|
for (const [key, pp] of members) {
|
||||||
if (typeof key !== 'number') return false;
|
if (typeof key !== 'number') return false;
|
||||||
if (!walk(pp, v[key])) return false;
|
if (!walk(pp, v[key])) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case _CArr:
|
case S.$arr:
|
||||||
if (!Array.isArray(v)) return false;
|
if (!Array.isArray(v)) return false;
|
||||||
if ('label' in v) return false;
|
if ('label' in v) return false;
|
||||||
if (CArr._.arity(ctor) !== v.length) return false;
|
if (S.CArr._.arity(ctor) !== v.length) return false;
|
||||||
for (const [key, pp] of members) {
|
for (const [key, pp] of members) {
|
||||||
if (typeof key !== 'number') return false;
|
if (typeof key !== 'number') return false;
|
||||||
if (!walk(pp, v[key])) return false;
|
if (!walk(pp, v[key])) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case _CDict:
|
case S.$dict:
|
||||||
if (!Dictionary.isDictionary<Assertion, Ref>(v)) return false;
|
if (!Dictionary.isDictionary<Assertion, Ref>(v)) return false;
|
||||||
for (const [key, pp] of members) {
|
for (const [key, pp] of members) {
|
||||||
const vv = v.get(key as Assertion);
|
const vv = v.get(key as Assertion);
|
||||||
|
@ -134,41 +69,41 @@ export function match(p: Pattern, v: Assertion): Bindings | null {
|
||||||
return walk(p, v) ? bindings : null;
|
return walk(p, v) ? bindings : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function instantiate(t: Template, b: Bindings): Assertion {
|
export function instantiate(t: S.Template, b: Bindings): Assertion {
|
||||||
function walk(t: Template): Assertion {
|
function walk(t: S.Template): Assertion {
|
||||||
switch (t.label) {
|
switch (t.label) {
|
||||||
case _TRef: {
|
case S.$ref: {
|
||||||
const n = TRef._.name(t).asPreservesText()
|
const n = S.TRef._.name(t).asPreservesText()
|
||||||
const v = b[n];
|
const v = b[n];
|
||||||
if (v === void 0) throw new Error(`Unbound reference: ${n}`);
|
if (v === void 0) throw new Error(`Unbound reference: ${n}`);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
case _Lit:
|
case S.$lit:
|
||||||
return Lit._.value(t) as Assertion;
|
return S.Lit._.value(t) as Assertion;
|
||||||
case _TCompound: {
|
case S.$compound: {
|
||||||
const ctor = TCompound._.ctor(t);
|
const ctor = S.TCompound._.ctor(t);
|
||||||
const members = TCompound._.members(t);
|
const members = S.TCompound._.members(t);
|
||||||
switch (ctor.label) {
|
switch (ctor.label) {
|
||||||
case _CRec: {
|
case S.$rec: {
|
||||||
const v = Record(
|
const v = Record(
|
||||||
CRec._.label(ctor) as Assertion,
|
S.CRec._.label(ctor) as Assertion,
|
||||||
[] as Assertion[],
|
[] as Assertion[],
|
||||||
);
|
);
|
||||||
v.length = CRec._.arity(ctor);
|
v.length = S.CRec._.arity(ctor);
|
||||||
for (const [key, tt] of members) {
|
for (const [key, tt] of members) {
|
||||||
v[key as number] = walk(tt);
|
v[key as number] = walk(tt);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
case _CArr: {
|
case S.$arr: {
|
||||||
const v = [];
|
const v = [];
|
||||||
v.length = CArr._.arity(ctor);
|
v.length = S.CArr._.arity(ctor);
|
||||||
for (const [key, tt] of members) {
|
for (const [key, tt] of members) {
|
||||||
v[key as number] = walk(tt);
|
v[key as number] = walk(tt);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
case _CDict: {
|
case S.$dict: {
|
||||||
const v = new Dictionary<Assertion, Ref>();
|
const v = new Dictionary<Assertion, Ref>();
|
||||||
for (const [key, tt] of members) {
|
for (const [key, tt] of members) {
|
||||||
v.set(key as Assertion, walk(tt));
|
v.set(key as Assertion, walk(tt));
|
||||||
|
@ -183,21 +118,25 @@ export function instantiate(t: Template, b: Bindings): Assertion {
|
||||||
return walk(t);
|
return walk(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function rewrite(r: Rewrite, v: Assertion): Assertion | null {
|
export function rewrite(r: S.Rewrite, v: Assertion): Assertion | null {
|
||||||
const bindings = match(r.pattern, v);
|
const bindings = match(S.Rewrite._.pattern(r), v);
|
||||||
if (bindings === null) return null;
|
if (bindings === null) return null;
|
||||||
return instantiate(r.template, bindings);
|
return instantiate(S.Rewrite._.template(r), bindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function examineAlternatives(alternatives: RewriteStage, v: Assertion): Assertion | null {
|
export function examineAlternatives(cav: S.Caveat, v: Assertion): Assertion | null {
|
||||||
for (const r of alternatives) {
|
if (cav.label === S.$or) {
|
||||||
const w = rewrite(r, v);
|
for (const r of S.Alts._.alternatives(cav)) {
|
||||||
if (w !== null) return w;
|
const w = rewrite(r, v);
|
||||||
|
if (w !== null) return w;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return rewrite(cav, v);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function runRewrites(a: Attenuation | undefined, v: Assertion): Assertion | null {
|
export function runRewrites(a: S.Attenuation | undefined, v: Assertion): Assertion | null {
|
||||||
if (a !== void 0) {
|
if (a !== void 0) {
|
||||||
for (const stage of a) {
|
for (const stage of a) {
|
||||||
const w = examineAlternatives(stage, v);
|
const w = examineAlternatives(stage, v);
|
||||||
|
@ -210,11 +149,12 @@ export function runRewrites(a: Attenuation | undefined, v: Assertion): Assertion
|
||||||
|
|
||||||
const _a = Symbol.for('a');
|
const _a = Symbol.for('a');
|
||||||
|
|
||||||
export function rfilter(... patterns: Pattern[]): RewriteStage {
|
export function rfilter(... patterns: S.Pattern[]): S.Caveat {
|
||||||
return patterns.map(p => ({ pattern: PBind(_a, p), template: TRef(_a) }));
|
const ps = patterns.map(p => S.Rewrite(S.PBind(_a, p), S.TRef(_a)));
|
||||||
|
return ps.length === 1 ? ps[0] : S.Alts(ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function attenuate(ref: Ref, ... a: Attenuation): Ref {
|
export function attenuate(ref: Ref, ... a: S.Attenuation): Ref {
|
||||||
return { ... ref, attenuation: [... a, ... (ref.attenuation ?? [])] };
|
return { ... ref, attenuation: [... a, ... (ref.attenuation ?? [])] };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Actor, Assertion, Ref, Turn } from "./actor.js";
|
import { Actor, Ref, Turn } from "./actor";
|
||||||
import { Relay, spawnRelay } from "./relay.js";
|
import { Relay, spawnRelay } from "./relay";
|
||||||
import { sturdyDecode } from "./sturdy.js";
|
import { sturdyDecode } from "./sturdy";
|
||||||
import { Observe } from "./dataspace.js";
|
import { Resolve, asSturdyRef } from "./gen/sturdy";
|
||||||
|
|
||||||
import * as net from 'net';
|
import * as net from 'net';
|
||||||
import { Bytes } from "@preserves/core";
|
import { Bytes } from "@preserves/core";
|
||||||
|
@ -29,7 +29,7 @@ const socket = net.createConnection({ port: 5999, host: 'localhost' }, () => {
|
||||||
// debug: true,
|
// debug: true,
|
||||||
}).then(gatekeeper => import(moduleName).then(m => t.freshen(t => {
|
}).then(gatekeeper => import(moduleName).then(m => t.freshen(t => {
|
||||||
t.assert(shutdownRef, true);
|
t.assert(shutdownRef, true);
|
||||||
t.assert(gatekeeper, Observe(cap as Assertion, t.ref({
|
t.assert(gatekeeper, Resolve(asSturdyRef(cap), t.ref({
|
||||||
assert(t, ds) {
|
assert(t, ds) {
|
||||||
m.default(t, ds);
|
m.default(t, ds);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { Actor, Handle, Turn } from './actor.js';
|
import { Actor, Handle, Turn } from './actor.js';
|
||||||
import { Dataspace, Observe } from './dataspace.js';
|
import { Dataspace } from './dataspace.js';
|
||||||
import { Relay, spawnRelay } from './relay.js';
|
import { Relay, spawnRelay } from './relay.js';
|
||||||
import * as net from 'net';
|
import * as net from 'net';
|
||||||
|
|
||||||
import { Caveat, mint, Or, Rewrite, sturdyEncode, SturdyRef, validate, _Or, _Rewrite } from './sturdy.js';
|
import { mint, sturdyEncode, SturdyRef, validate, Resolve } from './sturdy.js';
|
||||||
import { KEY_LENGTH } from './cryptography.js';
|
import { KEY_LENGTH } from './cryptography.js';
|
||||||
import { attenuate, Attenuation } from './rewrite.js';
|
import { attenuate } from './rewrite.js';
|
||||||
import { Bytes, IdentityMap } from '@preserves/core';
|
import { Bytes, IdentityMap } from '@preserves/core';
|
||||||
|
import { Attenuation, isResolve } from './gen/sturdy.js';
|
||||||
|
|
||||||
const secretKey = new Bytes(KEY_LENGTH);
|
const secretKey = new Bytes(KEY_LENGTH);
|
||||||
mint('syndicate', secretKey).then(v => {
|
mint('syndicate', secretKey).then(v => {
|
||||||
|
@ -14,15 +15,6 @@ mint('syndicate', secretKey).then(v => {
|
||||||
console.log(sturdyEncode(v).toHex());
|
console.log(sturdyEncode(v).toHex());
|
||||||
});
|
});
|
||||||
|
|
||||||
function internalize(caveatChain: Caveat[][]): Attenuation {
|
|
||||||
const a: Attenuation = [];
|
|
||||||
caveatChain.slice().reverse().forEach(cs => a.push(... cs.map(c => {
|
|
||||||
const alts = c.label === _Rewrite ? [c] : Or<Rewrite>()._.alternatives(c);
|
|
||||||
return alts.map(r => ({ pattern: Rewrite._.pattern(r), template: Rewrite._.template(r) }));
|
|
||||||
})));
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
Turn.for(new Actor(), t => {
|
Turn.for(new Actor(), t => {
|
||||||
const ds = t.ref(new Dataspace());
|
const ds = t.ref(new Dataspace());
|
||||||
|
|
||||||
|
@ -41,19 +33,18 @@ Turn.for(new Actor(), t => {
|
||||||
initialRef: t.ref({
|
initialRef: t.ref({
|
||||||
handleMap: new IdentityMap<Handle, Handle>(),
|
handleMap: new IdentityMap<Handle, Handle>(),
|
||||||
async assert(t, a, h) {
|
async assert(t, a, h) {
|
||||||
if (!Observe.isClassOf(a)) return;
|
if (!isResolve(a)) return;
|
||||||
const r = Observe._.label(a);
|
const r = Resolve._.sturdyref(a);
|
||||||
if (!SturdyRef.isClassOf(r)) return;
|
|
||||||
if (!await validate(r, secretKey)) {
|
if (!await validate(r, secretKey)) {
|
||||||
console.warn(`Invalid SturdyRef: ${r.asPreservesText()}`);
|
console.warn(`Invalid SturdyRef: ${r.asPreservesText()}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const attenuated_ds = attenuate(
|
const cavs: Attenuation = [];
|
||||||
ds,
|
SturdyRef._.caveatChain(r).forEach(cs => cavs.push(... cs));
|
||||||
... internalize(SturdyRef._.caveatChain(r)));
|
const attenuated_ds = attenuate(ds, ... cavs);
|
||||||
t.freshen(t => this.handleMap.set(
|
t.freshen(t => this.handleMap.set(
|
||||||
h,
|
h,
|
||||||
t.assert(Observe._.observer(a), attenuated_ds)));
|
t.assert(Resolve._.observer(a), attenuated_ds)));
|
||||||
},
|
},
|
||||||
retract(t, h) {
|
retract(t, h) {
|
||||||
t.retract(this.handleMap.get(h));
|
t.retract(this.handleMap.get(h));
|
||||||
|
|
|
@ -2,15 +2,17 @@ import { newKey } from './cryptography.js';
|
||||||
import { attenuate, KEY_LENGTH, mint, Rewrite, sturdyEncode, validate } from './sturdy.js';
|
import { attenuate, KEY_LENGTH, mint, Rewrite, sturdyEncode, validate } from './sturdy.js';
|
||||||
import * as RW from './rewrite.js';
|
import * as RW from './rewrite.js';
|
||||||
import { Bytes, Dictionary } from '@preserves/core';
|
import { Bytes, Dictionary } from '@preserves/core';
|
||||||
|
import { Ref } from 'actor.js';
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const m1 = await mint('hello world', new Bytes(KEY_LENGTH));
|
const m1 = await mint('hello world', new Bytes(KEY_LENGTH));
|
||||||
console.log(m1.asPreservesText());
|
console.log(m1.asPreservesText());
|
||||||
const m2 = await attenuate(m1, Rewrite(RW.PBind(Symbol.for('a'),
|
const m2 = await attenuate(m1, Rewrite(
|
||||||
RW.PCompound(RW.CRec(Symbol.for('says'), 2),
|
RW.PBind(Symbol.for('a'),
|
||||||
new Dictionary<RW.Pattern, never>([
|
RW.PCompound(RW.CRec(Symbol.for('says'), 2),
|
||||||
[0, RW.Lit('Tony')]]))),
|
new Dictionary<RW.Pattern, Ref>([
|
||||||
RW.TRef(Symbol.for('a'))));
|
[0, RW.Lit('Tony')]]))),
|
||||||
|
RW.TRef(Symbol.for('a'))));
|
||||||
console.log(m2.asPreservesText());
|
console.log(m2.asPreservesText());
|
||||||
console.log('should be true:', await validate(m1, new Bytes(KEY_LENGTH)));
|
console.log('should be true:', await validate(m1, new Bytes(KEY_LENGTH)));
|
||||||
console.log('should be true:', await validate(m2, new Bytes(KEY_LENGTH)));
|
console.log('should be true:', await validate(m2, new Bytes(KEY_LENGTH)));
|
||||||
|
|
|
@ -7,69 +7,48 @@
|
||||||
// California: Internet Society, 2014.
|
// California: Internet Society, 2014.
|
||||||
|
|
||||||
import { mac } from './cryptography.js';
|
import { mac } from './cryptography.js';
|
||||||
import { Bytes, decode, encode, is, Record, Value } from '@preserves/core';
|
import { Bytes, decode, encode, is } from '@preserves/core';
|
||||||
import type { Pattern, Template } from './rewrite.js';
|
import * as S from './gen/sturdy.js';
|
||||||
|
export * from './gen/sturdy.js';
|
||||||
|
|
||||||
export type EmbeddedRef = never;
|
export type SturdyValue = S._val;
|
||||||
export type SturdyValue = Value<EmbeddedRef>;
|
|
||||||
|
|
||||||
export const _SturdyRef = Symbol.for('sturdyref');
|
|
||||||
export const SturdyRef = Record.makeConstructor<{
|
|
||||||
oid: SturdyValue, // (arbitrary) name of the ultimate target of the ref
|
|
||||||
caveatChain: Array<Caveat>[],
|
|
||||||
// ^ caveats/rewrites. Evaluated RIGHT-TO-LEFT; each Array<Caveat> is evaluated LEFT-TO-RIGHT
|
|
||||||
sig: Bytes, // *keyed* signature of canonicalEncode of rightmost item in [oid, ... caveatChain]
|
|
||||||
}, EmbeddedRef>()(_SturdyRef, ['oid', 'caveatChain', 'sig']);
|
|
||||||
export type SturdyRef = [SturdyValue, Array<Caveat>[], Bytes] & { label: typeof _SturdyRef };
|
|
||||||
|
|
||||||
export type Caveat = Or<Rewrite>;
|
|
||||||
// ^ embodies 1st-party caveats over assertion structure, but nothing else
|
|
||||||
// can add 3rd-party caveats and richer predicates later
|
|
||||||
|
|
||||||
export const _Or = Symbol.for('or');
|
|
||||||
export const Or = <T extends SturdyValue>() =>
|
|
||||||
Record.makeConstructor<{ alternatives: T[] }, EmbeddedRef>()(_Or, ['alternatives']);
|
|
||||||
export type Or<T extends SturdyValue> = T | Record<typeof _Or, [T[]], EmbeddedRef>;
|
|
||||||
|
|
||||||
export const _Rewrite = Symbol.for('rewrite');
|
|
||||||
export const Rewrite = Record.makeConstructor<{
|
|
||||||
pattern: Pattern,
|
|
||||||
template: Template,
|
|
||||||
}, EmbeddedRef>()(_Rewrite, ['pattern', 'template']);
|
|
||||||
export type Rewrite = ReturnType<typeof Rewrite>;
|
|
||||||
|
|
||||||
export const KEY_LENGTH = 16; // 128 bits
|
export const KEY_LENGTH = 16; // 128 bits
|
||||||
|
|
||||||
|
export function pointerNotAllowed(): never {
|
||||||
|
throw new Error("Embedded Ref not permitted in SturdyRef");
|
||||||
|
}
|
||||||
|
|
||||||
export function sturdyEncode(v: SturdyValue): Bytes {
|
export function sturdyEncode(v: SturdyValue): Bytes {
|
||||||
return encode<EmbeddedRef>(v, {
|
return encode<S._ptr>(v, {
|
||||||
canonical: true,
|
canonical: true,
|
||||||
includeAnnotations: false,
|
includeAnnotations: false,
|
||||||
encodePointer() { throw new Error("EmbeddedRef not permitted in SturdyRef"); },
|
encodePointer: pointerNotAllowed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sturdyDecode(bs: Bytes): SturdyValue {
|
export function sturdyDecode(bs: Bytes): SturdyValue {
|
||||||
return decode<EmbeddedRef>(bs, {
|
return decode<S._ptr>(bs, {
|
||||||
includeAnnotations: false,
|
includeAnnotations: false,
|
||||||
decodePointer() { throw new Error("EmbeddedRef not permitted in SturdyRef"); },
|
decodePointer: pointerNotAllowed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function mint(oid: SturdyValue, secretKey: Bytes): Promise<SturdyRef> {
|
export async function mint(oid: SturdyValue, secretKey: Bytes): Promise<S.SturdyRef> {
|
||||||
return SturdyRef(oid, [], await mac(secretKey, sturdyEncode(oid)));
|
return S.SturdyRef(oid, [], await mac(secretKey, sturdyEncode(oid)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function attenuate(r: SturdyRef, ... a: Array<Caveat>): Promise<SturdyRef> {
|
export async function attenuate(r: S.SturdyRef, ... a: S.Attenuation): Promise<S.SturdyRef> {
|
||||||
return SturdyRef(
|
return S.SturdyRef(
|
||||||
SturdyRef._.oid(r),
|
S.SturdyRef._.oid(r),
|
||||||
[... SturdyRef._.caveatChain(r), a],
|
[... S.SturdyRef._.caveatChain(r), a],
|
||||||
await mac(SturdyRef._.sig(r), sturdyEncode(a))
|
await mac(S.SturdyRef._.sig(r), sturdyEncode(a))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function validate(r: SturdyRef, secretKey: Bytes): Promise<boolean> {
|
export async function validate(r: S.SturdyRef, secretKey: Bytes): Promise<boolean> {
|
||||||
const sig = await SturdyRef._.caveatChain(r).reduce(
|
const sig = await S.SturdyRef._.caveatChain(r).reduce(
|
||||||
async (sig, a) => mac(await sig, sturdyEncode(a)),
|
async (sig, a) => mac(await sig, sturdyEncode(a)),
|
||||||
mac(secretKey, sturdyEncode(SturdyRef._.oid(r))));
|
mac(secretKey, sturdyEncode(S.SturdyRef._.oid(r))));
|
||||||
return is(sig, SturdyRef._.sig(r));
|
return is(sig, S.SturdyRef._.sig(r));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue