Update to new schema compiler backend

This commit is contained in:
Tony Garnock-Jones 2021-03-23 12:18:57 +01:00
parent 346218f26a
commit 1bd65cd283
24 changed files with 1110 additions and 1349 deletions

View File

@ -1,9 +1,9 @@
version 1 .
pointer Actor.Ref .
BoxState = <BoxState int>.
SetBox = <SetBox int>.
BoxState = <BoxState @value int>.
SetBox = <SetBox @value int>.
; BoxCap = BoxState / <Observe =SetBox ref>.
; ClientCap = SetBox / <Observe =BoxState ref>.
; BoxCap = BoxState / <Observe =SetBox @observer ref>.
; ClientCap = SetBox / <Observe =BoxState @observer ref>.
.

View File

@ -5,5 +5,5 @@ pointer Actor.Ref .
Observe = <Observe @label symbol @observer ref>.
; ;As will be implemented soon
; Observe = <Observe Pattern ref>.
; Observe = <Observe @pattern Pattern @observer ref>.
.

View File

@ -5,7 +5,8 @@ Assertion = any .
Handle = int .
Event = Assert / Retract / Message / Sync .
Oid = int .
Turn = [[Oid Event] ...].
Turn = [TurnEvent ...].
TurnEvent = [@oid Oid @event Event].
Assert = <assert @assertion Assertion @handle Handle>.
Retract = <retract @handle Handle>.

View File

@ -3,7 +3,7 @@ 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>.
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.
@ -13,7 +13,7 @@ Attenuation = [Caveat ...].
; can add 3rd-party caveats and richer predicates later
Caveat = Rewrite / Alts .
Rewrite = <rewrite @pattern Pattern @template Template>.
Alts = <or @alternatives [Rewrite ...]>.
Alts = <or [@alternatives Rewrite ...]>.
Resolve = <resolve @sturdyref SturdyRef @observer ref>.
@ -29,10 +29,13 @@ Lit = <lit @value any>.
Pattern = PDiscard / PBind / PAnd / PNot / Lit / PCompound .
PDiscard = <_>.
PBind = <bind @name symbol @pattern Pattern>.
PAnd = <and @patterns [Pattern ...]>.
PAnd = <and [@patterns Pattern ...]>.
PNot = <not @pattern Pattern>.
PCompound = <compound @ctor ConstructorSpec @members { any: Pattern ...:... }>.
PCompound = <compound @ctor ConstructorSpec @members PCompoundMembers>.
PCompoundMembers = { any: Pattern ...:... }.
Template = TRef / Lit / TCompound .
TRef = <ref @name symbol>.
TCompound = <compound @ctor ConstructorSpec @members { any: Template ...:... }>.
TCompound = <compound @ctor ConstructorSpec @members TCompoundMembers>.
TCompoundMembers = { any: Template ...:... }.

View File

@ -1,3 +1,3 @@
version 1 .
Instance = <Instance string any>.
Instance = <Instance @name string @argument any>.

View File

@ -1,4 +1,4 @@
import { DecodeError, IdentitySet, TypedDecoder, Value } from '@preserves/core';
import { DecodeError, IdentitySet, Value } from '@preserves/core';
import { Attenuation, runRewrites } from './rewrite.js';
import { queueTask } from './task.js';
@ -32,8 +32,8 @@ export function isRef(v: any): v is Ref {
return 'relay' in v && v.relay instanceof Actor && 'target' in v;
}
export function decodeRef(_d: TypedDecoder<Ref>): Ref | undefined {
throw new DecodeError("Cannot decode Ref");
export function toRef(_v: any): Ref | undefined {
return isRef(_v) ? _v : void 0;
}
let nextActorId = 0;

View File

@ -10,7 +10,7 @@ export enum ChangeDescription {
}
export class Bag<T extends object = DefaultPointer> {
_items: Dictionary<number, T>;
_items: Dictionary<T, number>;
constructor(s?: Set<T>) {
this._items = new Dictionary();
@ -65,7 +65,7 @@ export class Bag<T extends object = DefaultPointer> {
this._items.forEach(f);
}
snapshot(): Dictionary<number, T> {
snapshot(): Dictionary<T, number> {
return this._items.clone();
}

View File

@ -1,5 +1,5 @@
import { BoxState, SetBox } from "./gen/box-protocol.js";
import { Observe } from "./gen/dataspace.js";
import { BoxState, $SetBox, fromBoxState } from "./gen/box-protocol.js";
import { fromObserve, Observe } from "./gen/dataspace.js";
import { Assertion, Handle, Ref, Turn } from "./actor.js";
let startTime = Date.now();
@ -12,10 +12,10 @@ export default function (t: Turn, arg: Assertion) {
console.log('Spawning Box', LIMIT, REPORT_EVERY);
let valueHandle: Handle | undefined;
function setValue(t: Turn, value: number) {
valueHandle = t.replace(ds, valueHandle, BoxState(value));
valueHandle = t.replace(ds, valueHandle, fromBoxState(BoxState(value)));
}
setValue(t, 0);
t.assert(ds, Observe(SetBox.constructorInfo.label, t.ref({
t.assert(ds, fromObserve(Observe($SetBox, t.ref({
message(t: Turn, [newValue]: [number]): void {
// console.log(`Box ${t.actor.id}: got ${newValue}`);
if (newValue % REPORT_EVERY === 0) {
@ -29,5 +29,5 @@ export default function (t: Turn, arg: Assertion) {
if (newValue === LIMIT) t.quit();
setValue(t, newValue);
}
})));
}))));
}

View File

@ -1,17 +1,17 @@
import { BoxState, SetBox } from "./gen/box-protocol.js";
import { Observe } from "./gen/dataspace.js";
import { $BoxState, fromSetBox, SetBox } from "./gen/box-protocol.js";
import { fromObserve, Observe } from "./gen/dataspace.js";
import { Assertion, Ref, Turn } from "./actor.js";
export default function (t: Turn, ds: Ref) {
console.log('Spawning Client');
let count = 0;
t.assert(ds, Observe(BoxState.constructorInfo.label, t.ref({
t.assert(ds, fromObserve(Observe($BoxState, t.ref({
assert(t: Turn, [currentValue]: [number]): void {
// console.log(`Client ${t.actor.id}: got ${currentValue}`);
t.message(ds, SetBox(currentValue + 1));
t.message(ds, fromSetBox(SetBox(currentValue + 1)));
}
})));
t.assert(ds, Observe(BoxState.constructorInfo.label, t.ref({
}))));
t.assert(ds, fromObserve(Observe($BoxState, t.ref({
assert(_t: Turn, _assertion: Assertion): void {
count++;
// console.log('inc to', count, _assertion);
@ -23,5 +23,5 @@ export default function (t: Turn, ds: Ref) {
}
// console.log('dec to', count);
},
})));
}))));
}

View File

@ -2,7 +2,7 @@ import { Assertion, Entity, Handle, Ref, Turn } from 'actor';
import { Dictionary, IdentityMap, is, Record, Tuple } from '@preserves/core';
import { Bag, ChangeDescription } from './bag';
import { Observe } from './gen/dataspace';
import { toObserve } from './gen/dataspace';
export * from './gen/dataspace';
// Q. Why keep "Observe"? Why not do the clever trick of asserting the
@ -38,22 +38,23 @@ export * from './gen/dataspace';
export class Dataspace implements Partial<Entity> {
readonly handleMap: IdentityMap<Handle, Record<Assertion, any, Ref>> = new IdentityMap();
readonly assertions = new Bag<Ref>();
readonly subscriptions = new Dictionary<Map<Ref, Dictionary<Handle, Ref>>, Ref>();
readonly subscriptions = new Dictionary<Ref, Map<Ref, Dictionary<Ref, Handle>>>();
assert(turn: Turn, rec: Assertion, handle: Handle): void {
// console.log(preserves`ds ${turn.actor.id} assert ${rec} ${handle}`);
if (!Record.isRecord<Assertion, Tuple<Assertion>, Ref>(rec)) return;
this.handleMap.set(handle, rec);
if (this.assertions.change(rec, +1) !== ChangeDescription.ABSENT_TO_PRESENT) return;
if (Observe.isClassOf(rec)) {
const label = Observe._.label(rec)!;
const observer = Observe._.observer(rec);
const seen = new Dictionary<Handle, Ref>();
if (!this.subscriptions.has(label)) this.subscriptions.set(label, new Map());
this.subscriptions.get(label)!.set(observer, seen);
this.assertions.forEach((_count, prev) =>
is((prev as Record<Assertion, any, Ref>).label, label)
&& seen.set(prev, turn.assert(observer, prev)));
{
const o = toObserve(rec);
if (o !== void 0) {
const seen = new Dictionary<Ref, Handle>();
if (!this.subscriptions.has(o.label)) this.subscriptions.set(o.label, new Map());
this.subscriptions.get(o.label)!.set(o.observer, seen);
this.assertions.forEach((_count, prev) =>
is((prev as Record<Assertion, any, Ref>).label, o.label)
&& seen.set(prev, turn.assert(o.observer, prev)));
}
}
this.subscriptions.get(rec.label)?.forEach((seen, peer) =>
seen.has(rec) || seen.set(rec, turn.assert(peer, rec)));
@ -69,10 +70,13 @@ export class Dataspace implements Partial<Entity> {
turn.retract(seen.get(rec));
seen.delete(rec);
});
if (Observe.isClassOf(rec)) {
let peerMap = this.subscriptions.get(Observe._.label(rec)!)!;
peerMap.delete(Observe._.observer(rec) as Ref);
if (peerMap.size === 0) this.subscriptions.delete(Observe._.label(rec)!);
{
const o = toObserve(rec);
if (o !== void 0) {
let peerMap = this.subscriptions.get(o.label)!;
peerMap.delete(o.observer);
if (peerMap.size === 0) this.subscriptions.delete(o.label);
}
}
}

View File

@ -4,72 +4,62 @@ import * as _i_Actor from "../actor";
export const $BoxState = Symbol.for("BoxState");
export const $SetBox = Symbol.for("SetBox");
export const BoxState = _.Record.makeConstructor<{"_field0": number}, _ptr>()($BoxState, ["_field0"]);
export type BoxState = _.Record<(typeof $BoxState), [number], _ptr>;
export const SetBox = _.Record.makeConstructor<{"_field0": number}, _ptr>()($SetBox, ["_field0"]);
export type SetBox = _.Record<(typeof $SetBox), [number], _ptr>;
export type _ptr = _i_Actor.Ref;
export type _val = _.Value<_ptr>;
export type BoxState = {"value": number};
export function isBoxState(v: any): v is BoxState {
return (
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
_.is(v.label, $BoxState) &&
((v.length === 1) && typeof v[0] === 'number')
);
export type SetBox = {"value": number};
export const _toPtr = (v: _val) => {let result: undefined | _ptr; result = _i_Actor.toRef(v); return result;};
export function BoxState(value: number): BoxState {return {value};}
export function SetBox(value: number): SetBox {return {value};}
export function asBoxState(v: _val): BoxState {
let result = toBoxState(v);
if (result === void 0) throw new TypeError(`Invalid BoxState: ${_.stringify(v)}`);
return result;
}
export function asBoxState(v: any): BoxState {
if (!isBoxState(v)) {throw new TypeError(`Invalid BoxState: ${_.stringify(v)}`);} else {return v;};
}
export function decodeBoxState(d: _.TypedDecoder<_ptr>): BoxState | undefined {
let result;
if (d.openRecord()) {
let _tmp0: any;
_tmp0 = _.asLiteral(d.nextSymbol(), $BoxState);
export function toBoxState(v: _val): undefined | BoxState {
let result: undefined | BoxState;
if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v)) {
let _tmp0: (null) | undefined;
_tmp0 = _.is(v.label, $BoxState) ? null : void 0;
if (_tmp0 !== void 0) {
let _tmp1, _tmp2: any;
_tmp2 = d.nextSignedInteger();
if (_tmp2 !== void 0) {if (d.closeCompound()) _tmp1 = [_tmp2];};
if (_tmp1 !== void 0) result = _.Record<(typeof $BoxState), [number]>(_tmp0 as any, _tmp1 as any);
let _tmp1: (number) | undefined;
_tmp1 = typeof v[0] === 'number' ? v[0] : void 0;
if (_tmp1 !== void 0) {result = {"value": _tmp1};};
};
};
return result;
}
export function isSetBox(v: any): v is SetBox {
return (
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
_.is(v.label, $SetBox) &&
((v.length === 1) && typeof v[0] === 'number')
);
export function fromBoxState(_v: BoxState): _val {return _.Record($BoxState, [_v["value"]]);}
export function asSetBox(v: _val): SetBox {
let result = toSetBox(v);
if (result === void 0) throw new TypeError(`Invalid SetBox: ${_.stringify(v)}`);
return result;
}
export function asSetBox(v: any): SetBox {
if (!isSetBox(v)) {throw new TypeError(`Invalid SetBox: ${_.stringify(v)}`);} else {return v;};
}
export function decodeSetBox(d: _.TypedDecoder<_ptr>): SetBox | undefined {
let result;
if (d.openRecord()) {
let _tmp3: any;
_tmp3 = _.asLiteral(d.nextSymbol(), $SetBox);
if (_tmp3 !== void 0) {
let _tmp4, _tmp5: any;
_tmp5 = d.nextSignedInteger();
if (_tmp5 !== void 0) {if (d.closeCompound()) _tmp4 = [_tmp5];};
if (_tmp4 !== void 0) result = _.Record<(typeof $SetBox), [number]>(_tmp3 as any, _tmp4 as any);
export function toSetBox(v: _val): undefined | SetBox {
let result: undefined | SetBox;
if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v)) {
let _tmp0: (null) | undefined;
_tmp0 = _.is(v.label, $SetBox) ? null : void 0;
if (_tmp0 !== void 0) {
let _tmp1: (number) | undefined;
_tmp1 = typeof v[0] === 'number' ? v[0] : void 0;
if (_tmp1 !== void 0) {result = {"value": _tmp1};};
};
};
return result;
}
export const _decodePtr = (d: _.TypedDecoder<_ptr>) => {let result; result = _i_Actor.decodeRef(d); return result;};
export function fromSetBox(_v: SetBox): _val {return _.Record($SetBox, [_v["value"]]);}

View File

@ -3,44 +3,40 @@ import * as _i_Actor from "../actor";
export const $Observe = Symbol.for("Observe");
export const Observe = _.Record.makeConstructor<{"label": symbol, "observer": _ptr}, _ptr>()($Observe, ["label","observer"]);
export type Observe = _.Record<(typeof $Observe), [symbol, _ptr], _ptr>;
export type _ptr = _i_Actor.Ref;
export type _val = _.Value<_ptr>;
export type Observe = {"label": symbol, "observer": _ptr};
export function isObserve(v: any): v is Observe {
return (
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
_.is(v.label, $Observe) &&
((v.length === 2) && typeof v[0] === 'symbol' && _.isPointer(v[1]))
);
export const _toPtr = (v: _val) => {let result: undefined | _ptr; result = _i_Actor.toRef(v); return result;};
export function Observe(label: symbol, observer: _ptr): Observe {return {label, observer};}
export function asObserve(v: _val): Observe {
let result = toObserve(v);
if (result === void 0) throw new TypeError(`Invalid Observe: ${_.stringify(v)}`);
return result;
}
export function asObserve(v: any): Observe {
if (!isObserve(v)) {throw new TypeError(`Invalid Observe: ${_.stringify(v)}`);} else {return v;};
}
export function decodeObserve(d: _.TypedDecoder<_ptr>): Observe | undefined {
let result;
if (d.openRecord()) {
let _tmp0: any;
_tmp0 = _.asLiteral(d.nextSymbol(), $Observe);
export function toObserve(v: _val): undefined | Observe {
let result: undefined | Observe;
if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v)) {
let _tmp0: (null) | undefined;
_tmp0 = _.is(v.label, $Observe) ? null : void 0;
if (_tmp0 !== void 0) {
let _tmp1, _tmp2, _tmp3: any;
_tmp2 = d.nextSymbol();
if (_tmp2 !== void 0) {
_tmp3 = _decodePtr(d);
if (_tmp3 !== void 0) {if (d.closeCompound()) _tmp1 = [_tmp2, _tmp3];};
let _tmp1: (symbol) | undefined;
_tmp1 = typeof v[0] === 'symbol' ? v[0] : void 0;
if (_tmp1 !== void 0) {
let _tmp2: (_ptr) | undefined;
_tmp2 = _toPtr(v[1]);
if (_tmp2 !== void 0) {result = {"label": _tmp1, "observer": _tmp2};};
};
if (_tmp1 !== void 0) result = _.Record<(typeof $Observe), [symbol, _ptr]>(_tmp0 as any, _tmp1 as any);
};
};
return result;
}
export const _decodePtr = (d: _.TypedDecoder<_ptr>) => {let result; result = _i_Actor.decodeRef(d); return result;};
export function fromObserve(_v: Observe): _val {return _.Record($Observe, [_v["label"], _v["observer"]]);}

View File

@ -6,280 +6,291 @@ export const $message = Symbol.for("message");
export const $retract = Symbol.for("retract");
export const $sync = Symbol.for("sync");
export type Assertion = _val;
export type Handle = number;
export type Event = (Assert | Retract | Message | Sync);
export type Oid = number;
export type Turn = Array<[Oid, Event]>;
export const Assert = _.Record.makeConstructor<{"assertion": Assertion, "handle": Handle}, _ptr>()($assert, ["assertion","handle"]);
export type Assert = _.Record<(typeof $assert), [Assertion, Handle], _ptr>;
export const Retract = _.Record.makeConstructor<{"handle": Handle}, _ptr>()($retract, ["handle"]);
export type Retract = _.Record<(typeof $retract), [Handle], _ptr>;
export const Message = _.Record.makeConstructor<{"body": Assertion}, _ptr>()($message, ["body"]);
export type Message = _.Record<(typeof $message), [Assertion], _ptr>;
export const Sync = _.Record.makeConstructor<{"peer": _ptr}, _ptr>()($sync, ["peer"]);
export type Sync = _.Record<(typeof $sync), [_ptr], _ptr>;
export type _ptr = _i_Protocol.WireRef;
export type _val = _.Value<_ptr>;
export type Assertion = _val;
export function isAssertion(v: any): v is Assertion {return true;}
export type Handle = number;
export function asAssertion(v: any): Assertion {
if (!isAssertion(v)) {throw new TypeError(`Invalid Assertion: ${_.stringify(v)}`);} else {return v;};
export type Event = (
{"_variant": "Assert", "value": Assert} |
{"_variant": "Retract", "value": Retract} |
{"_variant": "Message", "value": Message} |
{"_variant": "Sync", "value": Sync}
);
export type Oid = number;
export type Turn = Array<TurnEvent>;
export type TurnEvent = {"oid": Oid, "event": Event};
export type Assert = {"assertion": Assertion, "handle": Handle};
export type Retract = {"handle": Handle};
export type Message = {"body": Assertion};
export type Sync = {"peer": _ptr};
export const _toPtr = (v: _val) => {
let result: undefined | _ptr;
result = _i_Protocol.toWireRef(v);
return result;
};
export function Assertion(value: _val): Assertion {return value;}
export function Handle(value: number): Handle {return value;}
export namespace Event {
export function Assert(value: Assert): Event {return {"_variant": "Assert", value};};
export function Retract(value: Retract): Event {return {"_variant": "Retract", value};};
export function Message(value: Message): Event {return {"_variant": "Message", value};};
export function Sync(value: Sync): Event {return {"_variant": "Sync", value};};
}
export function decodeAssertion(d: _.TypedDecoder<_ptr>): Assertion | undefined {let result; result = d.next(); return result;}
export function Oid(value: number): Oid {return value;}
export function isHandle(v: any): v is Handle {return typeof v === 'number';}
export function Turn(value: Array<TurnEvent>): Turn {return value;}
export function asHandle(v: any): Handle {
if (!isHandle(v)) {throw new TypeError(`Invalid Handle: ${_.stringify(v)}`);} else {return v;};
export function TurnEvent(oid: Oid, event: Event): TurnEvent {return {oid, event};}
export function Assert(assertion: Assertion, handle: Handle): Assert {return {assertion, handle};}
export function Retract(handle: Handle): Retract {return {handle};}
export function Message(body: Assertion): Message {return {body};}
export function Sync(peer: _ptr): Sync {return {peer};}
export function asAssertion(v: _val): Assertion {
let result = toAssertion(v);
if (result === void 0) throw new TypeError(`Invalid Assertion: ${_.stringify(v)}`);
return result;
}
export function decodeHandle(d: _.TypedDecoder<_ptr>): Handle | undefined {let result; result = d.nextSignedInteger(); return result;}
export function isEvent(v: any): v is Event {
return _.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) && (
(
(
_.is(v.label, $assert) && ((v.length === 2) && isAssertion(v[0]) && isHandle(v[1]))
) ||
(_.is(v.label, $retract) && ((v.length === 1) && isHandle(v[0]))) ||
(_.is(v.label, $message) && ((v.length === 1) && isAssertion(v[0]))) ||
(_.is(v.label, $sync) && ((v.length === 1) && _.isPointer(v[0])))
)
);
export function toAssertion(v: _val): undefined | Assertion {
let _tmp0: (_val) | undefined;
let result: undefined | Assertion;
_tmp0 = v;
if (_tmp0 !== void 0) {result = _tmp0;};
return result;
}
export function asEvent(v: any): Event {
if (!isEvent(v)) {throw new TypeError(`Invalid Event: ${_.stringify(v)}`);} else {return v;};
export function fromAssertion(_v: Assertion): _val {return _v;}
export function asHandle(v: _val): Handle {
let result = toHandle(v);
if (result === void 0) throw new TypeError(`Invalid Handle: ${_.stringify(v)}`);
return result;
}
export function decodeEvent(d: _.TypedDecoder<_ptr>): Event | undefined {
let result;
if (d.openRecord()) {
let _tmp0, _tmp1: any;
_tmp0 = d.next();
_tmp1 = d.mark();
if (_.is(_tmp0, $assert)) {
let _tmp2, _tmp3, _tmp4: any;
_tmp3 = decodeAssertion(d);
if (_tmp3 !== void 0) {
_tmp4 = decodeHandle(d);
if (_tmp4 !== void 0) {if (d.closeCompound()) _tmp2 = [_tmp3, _tmp4];};
};
if (_tmp2 !== void 0) result = _.Record<(typeof $assert), [Assertion, Handle]>(_tmp0 as any, _tmp2 as any);
};
export function toHandle(v: _val): undefined | Handle {
let _tmp0: (number) | undefined;
let result: undefined | Handle;
_tmp0 = typeof v === 'number' ? v : void 0;
if (_tmp0 !== void 0) {result = _tmp0;};
return result;
}
export function fromHandle(_v: Handle): _val {return _v;}
export function asEvent(v: _val): Event {
let result = toEvent(v);
if (result === void 0) throw new TypeError(`Invalid Event: ${_.stringify(v)}`);
return result;
}
export function toEvent(v: _val): undefined | Event {
let _tmp0: (Assert) | undefined;
let result: undefined | Event;
_tmp0 = toAssert(v);
if (_tmp0 !== void 0) {result = {"_variant": "Assert", "value": _tmp0};};
if (result === void 0) {
let _tmp1: (Retract) | undefined;
_tmp1 = toRetract(v);
if (_tmp1 !== void 0) {result = {"_variant": "Retract", "value": _tmp1};};
if (result === void 0) {
d.restoreMark(_tmp1);
if (_.is(_tmp0, $retract)) {
let _tmp5, _tmp6: any;
_tmp6 = decodeHandle(d);
if (_tmp6 !== void 0) {if (d.closeCompound()) _tmp5 = [_tmp6];};
if (_tmp5 !== void 0) result = _.Record<(typeof $retract), [Handle]>(_tmp0 as any, _tmp5 as any);
};
let _tmp2: (Message) | undefined;
_tmp2 = toMessage(v);
if (_tmp2 !== void 0) {result = {"_variant": "Message", "value": _tmp2};};
if (result === void 0) {
d.restoreMark(_tmp1);
if (_.is(_tmp0, $message)) {
let _tmp7, _tmp8: any;
_tmp8 = decodeAssertion(d);
if (_tmp8 !== void 0) {if (d.closeCompound()) _tmp7 = [_tmp8];};
if (_tmp7 !== void 0) result = _.Record<(typeof $message), [Assertion]>(_tmp0 as any, _tmp7 as any);
};
if (result === void 0) {
d.restoreMark(_tmp1);
if (_.is(_tmp0, $sync)) {
let _tmp9, _tmp10: any;
_tmp10 = _decodePtr(d);
if (_tmp10 !== void 0) {if (d.closeCompound()) _tmp9 = [_tmp10];};
if (_tmp9 !== void 0) result = _.Record<(typeof $sync), [_ptr]>(_tmp0 as any, _tmp9 as any);
};
};
let _tmp3: (Sync) | undefined;
_tmp3 = toSync(v);
if (_tmp3 !== void 0) {result = {"_variant": "Sync", "value": _tmp3};};
};
};
};
return result;
}
export function isOid(v: any): v is Oid {return typeof v === 'number';}
export function asOid(v: any): Oid {
if (!isOid(v)) {throw new TypeError(`Invalid Oid: ${_.stringify(v)}`);} else {return v;};
export function fromEvent(_v: Event): _val {
switch (_v._variant) {
case "Assert": {return fromAssert(_v.value);};
case "Retract": {return fromRetract(_v.value);};
case "Message": {return fromMessage(_v.value);};
case "Sync": {return fromSync(_v.value);};
};
}
export function decodeOid(d: _.TypedDecoder<_ptr>): Oid | undefined {let result; result = d.nextSignedInteger(); return result;}
export function isTurn(v: any): v is Turn {
return (
_.Array.isArray(v) &&
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
(v.length >= 0) &&
v.every(v => (
(
_.Array.isArray(v) &&
!_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
(v.length === 2) &&
isOid(v[0]) &&
isEvent(v[1])
)
))
);
export function asOid(v: _val): Oid {
let result = toOid(v);
if (result === void 0) throw new TypeError(`Invalid Oid: ${_.stringify(v)}`);
return result;
}
export function asTurn(v: any): Turn {
if (!isTurn(v)) {throw new TypeError(`Invalid Turn: ${_.stringify(v)}`);} else {return v;};
export function toOid(v: _val): undefined | Oid {
let _tmp0: (number) | undefined;
let result: undefined | Oid;
_tmp0 = typeof v === 'number' ? v : void 0;
if (_tmp0 !== void 0) {result = _tmp0;};
return result;
}
export function decodeTurn(d: _.TypedDecoder<_ptr>): Turn | undefined {
let result;
if (d.openSequence()) {
let _tmp11: any;
{
let vN: Array<[Oid, Event]> | undefined = [];
while (!d.closeCompound()) {
let _tmp12, _tmp13: any;
_tmp11 = void 0;
if (d.openSequence()) {
_tmp12 = decodeOid(d);
if (_tmp12 !== void 0) {
_tmp13 = decodeEvent(d);
if (_tmp13 !== void 0) {if (d.closeCompound()) _tmp11 = [_tmp12, _tmp13];};
};
};
if (_tmp11 === void 0) {vN = void 0; break;};
vN.push(_tmp11);
export function fromOid(_v: Oid): _val {return _v;}
export function asTurn(v: _val): Turn {
let result = toTurn(v);
if (result === void 0) throw new TypeError(`Invalid Turn: ${_.stringify(v)}`);
return result;
}
export function toTurn(v: _val): undefined | Turn {
let result: undefined | Turn;
if (_.Array.isArray(v)) {
let _tmp0: (Array<TurnEvent>) | undefined;
_tmp0 = [];
for (const _tmp1 of v) {
let _tmp2: (TurnEvent) | undefined;
_tmp2 = toTurnEvent(_tmp1);
if (_tmp2 !== void 0) {_tmp0.push(_tmp2); continue;};
_tmp0 = void 0;
break;
};
if (_tmp0 !== void 0) {result = _tmp0;};
};
return result;
}
export function fromTurn(_v: Turn): _val {return _v.map(v => fromTurnEvent(v));}
export function asTurnEvent(v: _val): TurnEvent {
let result = toTurnEvent(v);
if (result === void 0) throw new TypeError(`Invalid TurnEvent: ${_.stringify(v)}`);
return result;
}
export function toTurnEvent(v: _val): undefined | TurnEvent {
let result: undefined | TurnEvent;
if (_.Array.isArray(v) && v.length === 2) {
let _tmp0: (Oid) | undefined;
_tmp0 = toOid(v[0]);
if (_tmp0 !== void 0) {
let _tmp1: (Event) | undefined;
_tmp1 = toEvent(v[1]);
if (_tmp1 !== void 0) {result = {"oid": _tmp0, "event": _tmp1};};
};
};
return result;
}
export function fromTurnEvent(_v: TurnEvent): _val {return [fromOid(_v["oid"]), fromEvent(_v["event"])];}
export function asAssert(v: _val): Assert {
let result = toAssert(v);
if (result === void 0) throw new TypeError(`Invalid Assert: ${_.stringify(v)}`);
return result;
}
export function toAssert(v: _val): undefined | Assert {
let result: undefined | Assert;
if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v)) {
let _tmp0: (null) | undefined;
_tmp0 = _.is(v.label, $assert) ? null : void 0;
if (_tmp0 !== void 0) {
let _tmp1: (Assertion) | undefined;
_tmp1 = toAssertion(v[0]);
if (_tmp1 !== void 0) {
let _tmp2: (Handle) | undefined;
_tmp2 = toHandle(v[1]);
if (_tmp2 !== void 0) {result = {"assertion": _tmp1, "handle": _tmp2};};
};
result = vN;
};
};
return result;
}
export function isAssert(v: any): v is Assert {
return (
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
_.is(v.label, $assert) &&
((v.length === 2) && isAssertion(v[0]) && isHandle(v[1]))
);
export function fromAssert(_v: Assert): _val {
return _.Record($assert, [fromAssertion(_v["assertion"]), fromHandle(_v["handle"])]);
}
export function asAssert(v: any): Assert {
if (!isAssert(v)) {throw new TypeError(`Invalid Assert: ${_.stringify(v)}`);} else {return v;};
export function asRetract(v: _val): Retract {
let result = toRetract(v);
if (result === void 0) throw new TypeError(`Invalid Retract: ${_.stringify(v)}`);
return result;
}
export function decodeAssert(d: _.TypedDecoder<_ptr>): Assert | undefined {
let result;
if (d.openRecord()) {
let _tmp14: any;
_tmp14 = _.asLiteral(d.nextSymbol(), $assert);
if (_tmp14 !== void 0) {
let _tmp15, _tmp16, _tmp17: any;
_tmp16 = decodeAssertion(d);
if (_tmp16 !== void 0) {
_tmp17 = decodeHandle(d);
if (_tmp17 !== void 0) {if (d.closeCompound()) _tmp15 = [_tmp16, _tmp17];};
};
if (_tmp15 !== void 0) result = _.Record<(typeof $assert), [Assertion, Handle]>(_tmp14 as any, _tmp15 as any);
export function toRetract(v: _val): undefined | Retract {
let result: undefined | Retract;
if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v)) {
let _tmp0: (null) | undefined;
_tmp0 = _.is(v.label, $retract) ? null : void 0;
if (_tmp0 !== void 0) {
let _tmp1: (Handle) | undefined;
_tmp1 = toHandle(v[0]);
if (_tmp1 !== void 0) {result = {"handle": _tmp1};};
};
};
return result;
}
export function isRetract(v: any): v is Retract {
return (
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
_.is(v.label, $retract) &&
((v.length === 1) && isHandle(v[0]))
);
export function fromRetract(_v: Retract): _val {return _.Record($retract, [fromHandle(_v["handle"])]);}
export function asMessage(v: _val): Message {
let result = toMessage(v);
if (result === void 0) throw new TypeError(`Invalid Message: ${_.stringify(v)}`);
return result;
}
export function asRetract(v: any): Retract {
if (!isRetract(v)) {throw new TypeError(`Invalid Retract: ${_.stringify(v)}`);} else {return v;};
}
export function decodeRetract(d: _.TypedDecoder<_ptr>): Retract | undefined {
let result;
if (d.openRecord()) {
let _tmp18: any;
_tmp18 = _.asLiteral(d.nextSymbol(), $retract);
if (_tmp18 !== void 0) {
let _tmp19, _tmp20: any;
_tmp20 = decodeHandle(d);
if (_tmp20 !== void 0) {if (d.closeCompound()) _tmp19 = [_tmp20];};
if (_tmp19 !== void 0) result = _.Record<(typeof $retract), [Handle]>(_tmp18 as any, _tmp19 as any);
export function toMessage(v: _val): undefined | Message {
let result: undefined | Message;
if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v)) {
let _tmp0: (null) | undefined;
_tmp0 = _.is(v.label, $message) ? null : void 0;
if (_tmp0 !== void 0) {
let _tmp1: (Assertion) | undefined;
_tmp1 = toAssertion(v[0]);
if (_tmp1 !== void 0) {result = {"body": _tmp1};};
};
};
return result;
}
export function isMessage(v: any): v is Message {
return (
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
_.is(v.label, $message) &&
((v.length === 1) && isAssertion(v[0]))
);
export function fromMessage(_v: Message): _val {return _.Record($message, [fromAssertion(_v["body"])]);}
export function asSync(v: _val): Sync {
let result = toSync(v);
if (result === void 0) throw new TypeError(`Invalid Sync: ${_.stringify(v)}`);
return result;
}
export function asMessage(v: any): Message {
if (!isMessage(v)) {throw new TypeError(`Invalid Message: ${_.stringify(v)}`);} else {return v;};
}
export function decodeMessage(d: _.TypedDecoder<_ptr>): Message | undefined {
let result;
if (d.openRecord()) {
let _tmp21: any;
_tmp21 = _.asLiteral(d.nextSymbol(), $message);
if (_tmp21 !== void 0) {
let _tmp22, _tmp23: any;
_tmp23 = decodeAssertion(d);
if (_tmp23 !== void 0) {if (d.closeCompound()) _tmp22 = [_tmp23];};
if (_tmp22 !== void 0) result = _.Record<(typeof $message), [Assertion]>(_tmp21 as any, _tmp22 as any);
export function toSync(v: _val): undefined | Sync {
let result: undefined | Sync;
if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v)) {
let _tmp0: (null) | undefined;
_tmp0 = _.is(v.label, $sync) ? null : void 0;
if (_tmp0 !== void 0) {
let _tmp1: (_ptr) | undefined;
_tmp1 = _toPtr(v[0]);
if (_tmp1 !== void 0) {result = {"peer": _tmp1};};
};
};
return result;
}
export function isSync(v: any): v is Sync {
return (
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
_.is(v.label, $sync) &&
((v.length === 1) && _.isPointer(v[0]))
);
}
export function asSync(v: any): Sync {
if (!isSync(v)) {throw new TypeError(`Invalid Sync: ${_.stringify(v)}`);} else {return v;};
}
export function decodeSync(d: _.TypedDecoder<_ptr>): Sync | undefined {
let result;
if (d.openRecord()) {
let _tmp24: any;
_tmp24 = _.asLiteral(d.nextSymbol(), $sync);
if (_tmp24 !== void 0) {
let _tmp25, _tmp26: any;
_tmp26 = _decodePtr(d);
if (_tmp26 !== void 0) {if (d.closeCompound()) _tmp25 = [_tmp26];};
if (_tmp25 !== void 0) result = _.Record<(typeof $sync), [_ptr]>(_tmp24 as any, _tmp25 as any);
};
};
return result;
}
export const _decodePtr = (d: _.TypedDecoder<_ptr>) => {let result; result = _i_Protocol.decodeWireRef(d); return result;};
export function fromSync(_v: Sync): _val {return _.Record($sync, [_v["peer"]]);}

File diff suppressed because it is too large Load Diff

View File

@ -2,44 +2,40 @@ import * as _ from "@preserves/core";
export const $Instance = Symbol.for("Instance");
export const Instance = _.Record.makeConstructor<{"_field0": string, "_field1": _val}, _ptr>()($Instance, ["_field0","_field1"]);
export type Instance = _.Record<(typeof $Instance), [string, _val], _ptr>;
export type _ptr = never;
export type _val = _.Value<_ptr>;
export type Instance = {"name": string, "argument": _val};
export function isInstance(v: any): v is Instance {
return (
_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v) &&
_.is(v.label, $Instance) &&
((v.length === 2) && typeof v[0] === 'string' && true)
);
export const _toPtr = () => { throw new _.DecodeError("Pointers forbidden"); };
export function Instance(name: string, argument: _val): Instance {return {name, argument};}
export function asInstance(v: _val): Instance {
let result = toInstance(v);
if (result === void 0) throw new TypeError(`Invalid Instance: ${_.stringify(v)}`);
return result;
}
export function asInstance(v: any): Instance {
if (!isInstance(v)) {throw new TypeError(`Invalid Instance: ${_.stringify(v)}`);} else {return v;};
}
export function decodeInstance(d: _.TypedDecoder<_ptr>): Instance | undefined {
let result;
if (d.openRecord()) {
let _tmp0: any;
_tmp0 = _.asLiteral(d.nextSymbol(), $Instance);
export function toInstance(v: _val): undefined | Instance {
let result: undefined | Instance;
if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v)) {
let _tmp0: (null) | undefined;
_tmp0 = _.is(v.label, $Instance) ? null : void 0;
if (_tmp0 !== void 0) {
let _tmp1, _tmp2, _tmp3: any;
_tmp2 = d.nextString();
if (_tmp2 !== void 0) {
_tmp3 = d.next();
if (_tmp3 !== void 0) {if (d.closeCompound()) _tmp1 = [_tmp2, _tmp3];};
let _tmp1: (string) | undefined;
_tmp1 = typeof v[0] === 'string' ? v[0] : void 0;
if (_tmp1 !== void 0) {
let _tmp2: (_val) | undefined;
_tmp2 = v[1];
if (_tmp2 !== void 0) {result = {"name": _tmp1, "argument": _tmp2};};
};
if (_tmp1 !== void 0) result = _.Record<(typeof $Instance), [string, _val]>(_tmp0 as any, _tmp1 as any);
};
};
return result;
}
export const _decodePtr = () => { throw new _.DecodeError("Pointers forbidden"); };
export function fromInstance(_v: Instance): _val {return _.Record($Instance, [_v["name"], _v["argument"]]);}

View File

@ -1,12 +1,13 @@
import { Actor, Assertion, Ref, Turn } from './actor.js';
import { Dictionary, Record } from '@preserves/core';
import { Dataspace, Observe } from './dataspace.js';
import { Dataspace } from './dataspace.js';
import { Worker } from 'worker_threads';
import { Relay, spawnRelay } from './relay.js';
import { attenuate, CRec, Lit, Pattern, PCompound, rfilter } from './rewrite.js';
import path from 'path';
import { BoxState, SetBox } from './gen/box-protocol.js';
import { attenuate, CRec, Lit, Pattern, PCompound, rfilter, ConstructorSpec } from './rewrite.js';
import { $BoxState, $SetBox } from './gen/box-protocol.js';
import { $Observe } from './gen/dataspace.js';
const Instance = Record.makeConstructor<{moduleName: string, arg: Assertion}>()(
Symbol.for('Instance'), ['moduleName', 'arg']);
@ -56,30 +57,25 @@ Turn.for(new Actor(), async (t: Turn) => {
const ds_for_box = attenuate(
ds,
rfilter(PCompound(CRec(BoxState.constructorInfo.label,
BoxState.constructorInfo.arity),
new Dictionary()),
PCompound(CRec(Observe.constructorInfo.label,
Observe.constructorInfo.arity),
new Dictionary<Pattern, Ref>([
[0, Lit(SetBox.constructorInfo.label)]]))));
rfilter(
Pattern.PCompound(PCompound(ConstructorSpec.CRec(CRec($BoxState, 1)), new Dictionary())),
Pattern.PCompound(PCompound(ConstructorSpec.CRec(CRec($Observe, 2)),
new Dictionary<Ref, Pattern>([
[0, Pattern.Lit(Lit($SetBox))]])))));
const ds_for_client = attenuate(
ds_unproxied,
rfilter(PCompound(CRec(SetBox.constructorInfo.label,
SetBox.constructorInfo.arity),
new Dictionary()),
PCompound(CRec(Observe.constructorInfo.label,
Observe.constructorInfo.arity),
new Dictionary<Pattern, Ref>([
[0, Lit(BoxState.constructorInfo.label)]]))));
rfilter(
Pattern.PCompound(PCompound(ConstructorSpec.CRec(CRec($SetBox, 1)), new Dictionary())),
Pattern.PCompound(PCompound(ConstructorSpec.CRec(CRec($Observe, 2)),
new Dictionary<Ref, Pattern>([
[0, Pattern.Lit(Lit($BoxState))]])))));
const boxpath = path.join(__dirname, 'box.js');
const clientpath = path.join(__dirname, 'client.js');
// spawnModule(t, boxpath, [ds_for_box, 500000, 25000]);
spawnWorker(t, boxpath, [ds_for_box, 50000, 2500]);
spawnModule(t, boxpath, [ds_for_box, 500000, 25000]);
// spawnWorker(t, boxpath, [ds_for_box, 50000, 2500]);
spawnModule(t, clientpath, ds_for_client);
// spawnWorker(t, clientpath, ds_for_client);

View File

@ -1,7 +1,8 @@
import { Attenuation, decodeAttenuation } from './gen/sturdy.js';
import { Attenuation, toAttenuation } from './gen/sturdy.js';
import * as IO from './gen/protocol.js';
import { decodeRef, Ref } from './actor.js';
import { TypedDecoder } from '@preserves/core';
import { Assertion, Ref } from './actor.js';
import { mapPointers } from '@preserves/core';
import { pointerNotAllowed } from './sturdy.js';
export type WireSymbol = { oid: IO.Oid, ref: Ref, count: number };
@ -17,27 +18,19 @@ export function yourRef(oid: IO.Oid, attenuation: Attenuation): WireRef & { loc:
return { loc: 'your', oid, attenuation };
}
export function decodeWireRef(d: TypedDecoder<WireRef>): WireRef | undefined {
if (d.openSequence()) {
switch (d.nextSignedInteger()) {
export function toWireRef(v: IO._val): WireRef | undefined {
if (Array.isArray(v) && v.length >= 2) {
switch (v[0]) {
case 0: {
const oid = d.nextSignedInteger();
if (oid !== void 0) {
if (d.closeCompound()) {
return myRef(oid);
}
}
const oid = v[1];
if (typeof oid === 'number') return myRef(oid);
break;
}
case 1: {
const oid = d.nextSignedInteger();
if (oid !== void 0) {
const attenuation = d.withPointerDecoder(decodeRef, d => decodeAttenuation(d));
if (attenuation !== void 0) {
if (d.closeCompound()) {
return yourRef(oid, attenuation);
}
}
const oid = v[1];
if (typeof oid === 'number') {
const attenuation = toAttenuation(mapPointers(v.slice(2), pointerNotAllowed) as Array<Assertion>);
if (attenuation !== void 0) return yourRef(oid, attenuation);
}
break;
}

View File

@ -1,10 +1,10 @@
import { Actor, Assertion, Entity, Handle, Ref, Turn } from './actor.js';
import { BytesLike, canonicalString, Decoder, encode, FlexMap, IdentityMap, mapPointers, underlying, Value } from '@preserves/core';
import * as IO from './gen/protocol.js';
import { decodeWireRef, myRef, WireRef, WireSymbol, yourRef } from './protocol.js';
import { myRef, toWireRef, WireRef, WireSymbol, yourRef } from './protocol.js';
import { queueTask } from './task.js';
import { attenuate } from './rewrite.js';
import { Attenuation } from './gen/sturdy.js';
import { Attenuation, fromAttenuation } from './gen/sturdy.js';
import { pointerNotAllowed } from './sturdy.js';
export class SyncPeerEntity implements Entity {
@ -52,16 +52,16 @@ export class RelayEntity implements Entity {
}
assert(_turn: Turn, assertion: Assertion, handle: Handle): void {
this.send(IO.Assert(this.relay.register(assertion, handle), handle));
this.send(IO.Event.Assert(IO.Assert(this.relay.register(assertion, handle), handle)))
}
retract(_turn: Turn, handle: Handle): void {
this.relay.deregister(handle);
this.send(IO.Retract(handle));
this.send(IO.Event.Retract(IO.Retract(handle)));
}
message(_turn: Turn, body: Assertion): void {
this.send(IO.Message(this.relay.register(body, null)));
this.send(IO.Event.Message(IO.Message(this.relay.register(body, null))));
}
sync(turn: Turn, peer: Ref): void {
@ -69,7 +69,7 @@ export class RelayEntity implements Entity {
const exported: Array<WireSymbol> = [];
const ior = this.relay.rewriteRefOut(turn.ref(peerEntity), false, exported);
peerEntity.e = exported[0];
this.send(IO.Sync(ior));
this.send(IO.Event.Sync(IO.Sync(ior)));
}
}
@ -135,7 +135,7 @@ export class Relay {
trustPeer: boolean;
readonly decoder = new Decoder(void 0, { includeAnnotations: false })
.replacePointerDecoder(decodeWireRef);
.replacePointerDecoder<WireRef>(d => toWireRef(d.next()));
constructor(t: Turn, options: RelayOptions) {
this.actor = t.actor;
@ -227,20 +227,20 @@ export class Relay {
if (this.pendingTurn.length === 0) {
queueTask(() => {
if (this.debug) console.log('OUT', this.pendingTurn.asPreservesText());
this.w(underlying(encode<WireRef>(this.pendingTurn, {
this.w(underlying(encode<WireRef>(IO.fromTurn(this.pendingTurn), {
canonical: true,
encodePointer: (e, n) => {
switch (n.loc) {
case 'mine': return e.push([0, n.oid]);
case 'your': return e.push([1, n.oid, ... mapPointers<Ref, IO._ptr>(
n.attenuation, pointerNotAllowed) as Array<IO._val>]);
fromAttenuation(n.attenuation), pointerNotAllowed) as Array<IO._val>]);
}
},
})));
this.pendingTurn = [];
});
}
this.pendingTurn.push([remoteOid, m]);
this.pendingTurn.push(IO.TurnEvent(remoteOid, m));
}
lookupLocal(localOid: IO.Oid): Ref {
@ -251,14 +251,13 @@ export class Relay {
Turn.for(this.actor, t => {
this.decoder.write(bs);
while (true) {
const wireTurn = this.decoder.shortGuard(
() => IO.decodeTurn(this.decoder) ?? false,
() => void 0);
if (wireTurn === void 0) break;
if (wireTurn === false) throw new Error("Bad IO.Turn");
const rawTurn = this.decoder.try_next();
if (rawTurn === void 0) break;
const wireTurn = IO.toTurn(rawTurn);
if (wireTurn === void 0) throw new Error("Bad IO.Turn");
if (this.debug) console.log('IN', wireTurn.asPreservesText());
wireTurn.forEach(v => {
const [localOid, m] = v;
const { oid: localOid, event: m } = v;
this.handle(t, this.lookupLocal(localOid), m);
});
}
@ -266,17 +265,17 @@ export class Relay {
}
handle(t: Turn, r: Ref, m: IO.Event) {
switch (m.label) {
case IO.$assert: {
const [a, imported] = this.rewriteIn(t, IO.Assert._.assertion(m));
this.inboundAssertions.set(IO.Assert._.handle(m), {
switch (m._variant) {
case 'Assert': {
const [a, imported] = this.rewriteIn(t, m.value.assertion);
this.inboundAssertions.set(m.value.handle, {
localHandle: t.assert(r, a),
imported,
});
break;
}
case IO.$retract: {
const remoteHandle = IO.Retract._.handle(m);
case 'Retract': {
const remoteHandle = m.value.handle;
const h = this.inboundAssertions.get(remoteHandle);
if (h === void 0) throw new Error(`Peer retracted invalid handle ${remoteHandle}`);
this.inboundAssertions.delete(remoteHandle);
@ -284,15 +283,15 @@ export class Relay {
t.retract(h.localHandle);
break;
}
case IO.$message: {
const [a, imported] = this.rewriteIn(t, IO.Message._.body(m));
case 'Message': {
const [a, imported] = this.rewriteIn(t, m.value.body);
if (imported.length > 0) throw new Error("Cannot receive transient reference");
t.message(r, a);
break;
}
case IO.$sync: {
case 'Sync': {
const imported: Array<WireSymbol> = [];
const k = this.rewriteRefIn(t, IO.Sync._.peer(m), imported);
const k = this.rewriteRefIn(t, m.value.peer, imported);
t.sync(r).then(t => {
t.message(k, true);
imported.forEach(e => this.imported.drop(e));

View File

@ -1,34 +1,7 @@
import type { Assertion, Handle, Ref, Turn } from "./actor.js";
import { Dictionary, IdentityMap, is, Record, Tuple } from "@preserves/core";
import {
$__,
$and,
$arr,
$bind,
$compound,
$dict,
$lit,
$not,
$or,
$rec,
$ref,
Alts,
Attenuation,
CArr,
CRec,
Caveat,
Lit,
PAnd,
PBind,
PCompound,
PNot,
Pattern,
Rewrite,
TCompound,
TRef,
Template,
} from './gen/sturdy.js';
import { Alts, Attenuation, Caveat, PBind, Pattern, Rewrite, TRef, Template } from './gen/sturdy.js';
export * from './gen/sturdy.js';
export type Bindings = { [name: string]: Assertion };
@ -37,52 +10,52 @@ export function match(p: Pattern, v: Assertion): Bindings | null {
let bindings: Bindings = {};
function walk(p: Pattern, v: Assertion): boolean {
switch (p.label) {
case $__:
switch (p._variant) {
case 'PDiscard':
return true;
case $bind:
if (walk(PBind._.pattern(p), v)) {
bindings[PBind._.name(p).asPreservesText()] = v;
case 'PBind':
if (walk(p.value.pattern, v)) {
bindings[p.value.name.asPreservesText()] = v;
return true;
}
return false;
case $and:
for (const pp of PAnd._.patterns(p)) {
case 'PAnd':
for (const pp of p.value.patterns) {
if (!walk(pp, v)) return false;
}
return true;
case $not: {
case 'PNot': {
const savedBindings = bindings;
bindings = {};
const result = !walk(PNot._.pattern(p), v)
const result = !walk(p.value.pattern, v)
bindings = savedBindings;
return result;
}
case $lit:
return is(Lit._.value(p), v);
case $compound: {
const ctor = PCompound._.ctor(p);
const members = PCompound._.members(p);
switch (ctor.label) {
case $rec:
case 'Lit':
return is(p.value.value, v);
case 'PCompound': {
const ctor = p.value.ctor;
const members = p.value.members;
switch (ctor._variant) {
case 'CRec':
if (!Record.isRecord<Assertion, Tuple<Assertion>, Ref>(v)) return false;
if (!is(CRec._.label(ctor), v.label)) return false;
if (CRec._.arity(ctor) !== v.length) return false;
if (!is(ctor.value.label, v.label)) return false;
if (ctor.value.arity !== v.length) return false;
for (const [key, pp] of members) {
if (typeof key !== 'number') return false;
if (!walk(pp, v[key])) return false;
}
return true;
case $arr:
case 'CArr':
if (!Array.isArray(v)) return false;
if ('label' in v) return false;
if (CArr._.arity(ctor) !== v.length) return false;
if (ctor.value.arity !== v.length) return false;
for (const [key, pp] of members) {
if (typeof key !== 'number') return false;
if (!walk(pp, v[key])) return false;
}
return true;
case $dict:
case 'CDict':
if (!Dictionary.isDictionary<Assertion, Ref>(v)) return false;
for (const [key, pp] of members) {
const vv = v.get(key as Assertion);
@ -100,40 +73,38 @@ export function match(p: Pattern, v: Assertion): Bindings | null {
export function instantiate(t: Template, b: Bindings): Assertion {
function walk(t: Template): Assertion {
switch (t.label) {
case $ref: {
const n = TRef._.name(t).asPreservesText()
switch (t._variant) {
case 'TRef': {
const n = t.value.name.asPreservesText()
const v = b[n];
if (v === void 0) throw new Error(`Unbound reference: ${n}`);
return v;
}
case $lit:
return Lit._.value(t) as Assertion;
case $compound: {
const ctor = TCompound._.ctor(t);
const members = TCompound._.members(t);
switch (ctor.label) {
case $rec: {
const v = Record(
CRec._.label(ctor) as Assertion,
[] as Assertion[],
);
v.length = CRec._.arity(ctor);
case 'Lit':
return t.value.value as Assertion;
case 'TCompound': {
const ctor = t.value.ctor;
const members = t.value.members;
switch (ctor._variant) {
case 'CRec': {
const v = [] as unknown as Record<Assertion, Assertion[], Ref>;
v.length = ctor.value.arity;
v.label = ctor.value.label;
for (const [key, tt] of members) {
v[key as number] = walk(tt);
}
return v;
}
case $arr: {
case 'CArr': {
const v = [];
v.length = CArr._.arity(ctor);
v.length = ctor.value.arity;
for (const [key, tt] of members) {
v[key as number] = walk(tt);
}
return v;
}
case $dict: {
const v = new Dictionary<Assertion, Ref>();
case 'CDict': {
const v = new Dictionary<Ref, Assertion>();
for (const [key, tt] of members) {
v.set(key as Assertion, walk(tt));
}
@ -148,20 +119,20 @@ export function instantiate(t: Template, b: Bindings): Assertion {
}
export function rewrite(r: Rewrite, v: Assertion): Assertion | null {
const bindings = match(Rewrite._.pattern(r), v);
const bindings = match(r.pattern, v);
if (bindings === null) return null;
return instantiate(Rewrite._.template(r), bindings);
return instantiate(r.template, bindings);
}
export function examineAlternatives(cav: Caveat, v: Assertion): Assertion | null {
if (cav.label === $or) {
for (const r of Alts._.alternatives(cav)) {
if (cav._variant === 'Alts') {
for (const r of cav.value.alternatives) {
const w = rewrite(r, v);
if (w !== null) return w;
}
return null;
} else {
return rewrite(cav, v);
return rewrite(cav.value, v);
}
}
@ -179,8 +150,8 @@ export function runRewrites(a: Attenuation | undefined, v: Assertion): Assertion
const _a = Symbol.for('a');
export function rfilter(... patterns: Pattern[]): Caveat {
const ps = patterns.map(p => Rewrite(PBind(_a, p), TRef(_a)));
return ps.length === 1 ? ps[0] : Alts(ps);
const ps = patterns.map(p => Rewrite(Pattern.PBind(PBind(_a, p)), Template.TRef(TRef(_a))));
return ps.length === 1 ? Caveat.Rewrite(ps[0]) : Caveat.Alts(Alts(ps));
}
export function attenuate(ref: Ref, ... a: Attenuation): Ref {

View File

@ -1,7 +1,7 @@
import { Actor, Ref, Turn } from "./actor";
import { Relay, spawnRelay } from "./relay";
import { sturdyDecode } from "./sturdy";
import { Resolve, asSturdyRef } from "./gen/sturdy";
import { Resolve, asSturdyRef, fromResolve } from "./gen/sturdy";
import * as net from 'net';
import { Bytes } from "@preserves/core";
@ -29,11 +29,11 @@ const socket = net.createConnection({ port: 5999, host: 'localhost' }, () => {
// debug: true,
}).then(gatekeeper => import(moduleName).then(m => t.freshen(t => {
t.assert(shutdownRef, true);
t.assert(gatekeeper, Resolve(asSturdyRef(cap), t.ref({
t.assert(gatekeeper, fromResolve(Resolve(asSturdyRef(cap), t.ref({
assert(t, ds) {
m.default(t, ds);
}
})));
}))));
})));
});
});

View File

@ -3,16 +3,16 @@ import { Dataspace } from './dataspace.js';
import { Relay, spawnRelay } from './relay.js';
import * as net from 'net';
import { mint, sturdyEncode, SturdyRef, validate, Resolve } from './sturdy.js';
import { mint, sturdyEncode, validate } from './sturdy.js';
import { KEY_LENGTH } from './cryptography.js';
import { attenuate } from './rewrite.js';
import { Bytes, IdentityMap } from '@preserves/core';
import { Attenuation, isResolve } from './gen/sturdy.js';
import { Attenuation, fromSturdyRef, toResolve } from './gen/sturdy.js';
const secretKey = new Bytes(KEY_LENGTH);
mint('syndicate', secretKey).then(v => {
console.log(v.asPreservesText());
console.log(sturdyEncode(v).toHex());
console.log(sturdyEncode(fromSturdyRef(v)).toHex());
});
Turn.for(new Actor(), t => {
@ -32,19 +32,20 @@ Turn.for(new Actor(), t => {
},
initialRef: t.ref({
handleMap: new IdentityMap<Handle, Handle>(),
async assert(t, a, h) {
if (!isResolve(a)) return;
const r = Resolve._.sturdyref(a);
async assert(t, a0, h) {
const a = toResolve(a0);
if (a === void 0) return;
const r = a.sturdyref;
if (!await validate(r, secretKey)) {
console.warn(`Invalid SturdyRef: ${r.asPreservesText()}`);
return;
}
const cavs: Attenuation = [];
SturdyRef._.caveatChain(r).forEach(cs => cavs.push(... cs));
r.caveatChain.forEach(cs => cavs.push(... cs));
const attenuated_ds = attenuate(ds, ... cavs);
t.freshen(t => this.handleMap.set(
h,
t.assert(Resolve._.observer(a), attenuated_ds)));
t.assert(a.observer, attenuated_ds)));
},
retract(t, h) {
t.retract(this.handleMap.get(h));

View File

@ -1,32 +1,34 @@
import { newKey } from './cryptography.js';
import { attenuate, KEY_LENGTH, mint, Rewrite, sturdyEncode, validate } from './sturdy.js';
import { attenuate, KEY_LENGTH, mint, Caveat, Rewrite, sturdyEncode, validate } from './sturdy.js';
import * as RW from './rewrite.js';
import { Bytes, Dictionary } from '@preserves/core';
import { Ref } from 'actor.js';
async function main() {
const m1 = await mint('hello world', new Bytes(KEY_LENGTH));
console.log(m1.asPreservesText());
const m2 = await attenuate(m1, Rewrite(
RW.PBind(Symbol.for('a'),
RW.PCompound(RW.CRec(Symbol.for('says'), 2),
new Dictionary<RW.Pattern, Ref>([
[0, RW.Lit('Tony')]]))),
RW.TRef(Symbol.for('a'))));
console.log(m2.asPreservesText());
console.log(m1);
const m2 = await attenuate(m1, Caveat.Rewrite(Rewrite(
RW.Pattern.PBind(RW.PBind(
Symbol.for('a'),
RW.Pattern.PCompound(RW.PCompound(
RW.ConstructorSpec.CRec(RW.CRec(Symbol.for('says'), 2)),
new Dictionary<Ref, RW.Pattern>([
[0, RW.Pattern.Lit(RW.Lit('Tony'))]]))))),
RW.Template.TRef(RW.TRef(Symbol.for('a'))))));
console.log(m2);
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 false:', await validate(m2, Bytes.of(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)));
m2[0] = 'hello world2';
console.log(m2.asPreservesText());
m2.oid = 'hello world2';
console.log(m2);
console.log('should be false:', await validate(m2, new Bytes(KEY_LENGTH)));
m2[0] = 'hello world';
console.log(m2.asPreservesText());
m2.oid = 'hello world';
console.log(m2);
console.log('should be true:', await validate(m2, new Bytes(KEY_LENGTH)));
console.log('should be false:', await validate(m2, await newKey()));
console.log((await newKey()).asPreservesText());
console.log((await newKey()).asPreservesText());
console.log(sturdyEncode(m2).asPreservesText());
console.log(sturdyEncode(RW.fromSturdyRef(m2)).asPreservesText());
}
main();

View File

@ -40,15 +40,15 @@ export async function mint(oid: SturdyValue, secretKey: Bytes): Promise<S.Sturdy
export async function attenuate(r: S.SturdyRef, ... a: S.Attenuation): Promise<S.SturdyRef> {
return S.SturdyRef(
S.SturdyRef._.oid(r),
[... S.SturdyRef._.caveatChain(r), a],
await mac(S.SturdyRef._.sig(r), sturdyEncode(a))
r.oid,
[... r.caveatChain, a],
await mac(r.sig, sturdyEncode(S.fromAttenuation(a)))
);
}
export async function validate(r: S.SturdyRef, secretKey: Bytes): Promise<boolean> {
const sig = await S.SturdyRef._.caveatChain(r).reduce(
async (sig, a) => mac(await sig, sturdyEncode(a)),
mac(secretKey, sturdyEncode(S.SturdyRef._.oid(r))));
return is(sig, S.SturdyRef._.sig(r));
const sig = await r.caveatChain.reduce(
async (sig, a) => mac(await sig, sturdyEncode(S.fromAttenuation(a))),
mac(secretKey, sturdyEncode(r.oid)));
return is(sig, r.sig);
}

View File

@ -1,10 +1,13 @@
import { Bytes, Reader } from '@preserves/core';
import { attenuate, Caveat, sturdyDecode, sturdyEncode, SturdyRef } from '../sturdy.js';
import { fromSturdyRef, toSturdyRef, toCaveat, attenuate, sturdyDecode, sturdyEncode } from '../sturdy.js';
const [ base, pat ] = process.argv.slice(2);
const baseCap = sturdyDecode(Bytes.fromHex(base ?? '')) as SturdyRef;
const cs = new Reader(pat).next() as Array<Caveat>;
const baseCap = toSturdyRef(sturdyDecode(Bytes.fromHex(base ?? '')));
if (baseCap === void 0) throw new Error("Cannot decode sturdyref");
const cs0 = new Reader(pat).next();
if (!Array.isArray(cs0)) throw new Error("Expected array of caveats");
const cs = cs0.map(c => toCaveat(c) ?? (()=>{ throw new Error("Cannot decode caveat"); })());
attenuate(baseCap, ... cs).then(derived => {
console.log(derived.asPreservesText());
console.log(sturdyEncode(derived).toHex());
console.log(sturdyEncode(fromSturdyRef(derived)).toHex());
});