Avoid hand-written WireRef (un)marshalling, taking advantage of the new Pointer representation from preserves

This commit is contained in:
Tony Garnock-Jones 2021-04-25 00:15:15 +02:00
parent fa47fa3e5e
commit 4af4219cc7
28 changed files with 262 additions and 188 deletions

View File

@ -6,8 +6,8 @@
"typescript": "^4.2.3"
},
"dependencies": {
"@preserves/core": "^0.11.0",
"@preserves/schema": "^0.4.0"
"@preserves/core": "^0.12.0",
"@preserves/schema": "^0.5.1"
},
"scripts": {
"regenerate": "rm -rf ./src/gen && preserves-schema-ts --module Actor=./src/runtime/actor.ts --module Protocol=./src/transport/protocol.ts --output ./src/gen './schemas/**/*.prs'",

5
schemas/gatekeeper.prs Normal file
View File

@ -0,0 +1,5 @@
version 1 .
pointer Actor.Ref .
Resolve = <resolve @sturdyref sturdy.SturdyRef @observer ref>.
Bind = <bind @oid any @key bytes @target ref>.

View File

@ -1,5 +1,5 @@
version 1 .
pointer Protocol.WireRef .
pointer sturdy.WireRef .
Assertion = any .
Handle = int .

View File

@ -1,5 +1,4 @@
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.
@ -15,8 +14,8 @@ Caveat = Rewrite / Alts .
Rewrite = <rewrite @pattern Pattern @template Template>.
Alts = <or [@alternatives Rewrite ...]>.
Resolve = <resolve @sturdyref SturdyRef @observer ref>.
Bind = <bind @oid any @key bytes @target ref>.
Oid = int .
WireRef = @mine [0 @oid Oid] / @yours [1 @oid Oid @attenuation Caveat ...].
;---------------------------------------------------------------------------

View File

@ -1,7 +1,8 @@
import { Actor, Ref, Turn } from "../runtime/actor";
import { Relay, spawnRelay } from "../transport/relay";
import { sturdyDecode } from "../transport/sturdy";
import { Resolve, asSturdyRef, fromResolve } from "../gen/sturdy";
import { asSturdyRef } from "../gen/sturdy";
import { Resolve, fromResolve } from "../gen/gatekeeper";
import { during } from "../runtime/dataspace";
import * as net from 'net';

View File

@ -6,8 +6,9 @@ import * as net from 'net';
import { mint, sturdyEncode, validate } from '../transport/sturdy.js';
import { KEY_LENGTH } from '../transport/cryptography.js';
import { attenuate } from '../runtime/rewrite.js';
import { Bytes, is } from '@preserves/core';
import { $bind, Attenuation, Bind, fromBind, fromSturdyRef, toBind, toResolve, _val } from '../gen/sturdy.js';
import { Bytes, embed, is } from '@preserves/core';
import { Attenuation, fromSturdyRef, _val } from '../gen/sturdy.js';
import { $bind, Bind, fromBind, toBind, toResolve } from '../gen/gatekeeper.js';
new Actor(t => {
t.activeFacet.preventInertCheck();
@ -52,7 +53,7 @@ new Actor(t => {
r.caveatChain.forEach(cs => cavs.push(... cs));
const attenuated_ds = attenuate(b.target, ... cavs);
let replyHandle: Handle | undefined;
t.freshen(t => replyHandle = t.assert(a.observer, attenuated_ds));
t.freshen(t => replyHandle = t.assert(a.observer, embed(attenuated_ds)));
return t => t.retract(replyHandle);
}));
});

View File

@ -1,3 +1,4 @@
import { Pointer } from "@preserves/core";
import { BoxState, $SetBox, fromBoxState } from "../gen/box-protocol.js";
import { fromObserve, Observe } from "../gen/dataspace.js";
import { Assertion, Handle, Ref, Turn } from "../runtime/actor.js";
@ -6,9 +7,10 @@ let startTime = Date.now();
let prevValue = 0;
export default function (t: Turn, arg: Assertion) {
const [ds, LIMIT, REPORT_EVERY]: [Ref, number, number] = Array.isArray(arg) && arg.length === 3
const [ds_p, LIMIT, REPORT_EVERY]: [Pointer<Ref>, number, number] = Array.isArray(arg) && arg.length === 3
? arg as any
: [arg, 50000, 2500];
const ds = ds_p.embeddedValue;
console.log('Spawning Box', LIMIT, REPORT_EVERY);
let valueHandle: Handle | undefined;
function setValue(t: Turn, value: number) {

View File

@ -1,8 +1,10 @@
import { Pointer } from "@preserves/core";
import { $BoxState, fromSetBox, SetBox } from "../gen/box-protocol.js";
import { fromObserve, Observe } from "../gen/dataspace.js";
import { Assertion, Ref, Turn } from "../runtime/actor.js";
export default function (t: Turn, ds: Ref) {
export default function (t: Turn, ds_p: Pointer<Ref>) {
const ds = ds_p.embeddedValue;
console.log('Spawning Client');
let count = 0;
t.assert(ds, fromObserve(Observe({

View File

@ -1,7 +1,7 @@
import { Actor, Assertion, Ref, Turn } from '../runtime/actor.js';
import { Dictionary } from '@preserves/core';
import { Actor, Assertion, Turn } from '../runtime/actor.js';
import { Dictionary, embed } from '@preserves/core';
import { Dataspace } from '../runtime/dataspace.js';
import { attenuate, CRec, Lit, Pattern, PCompound, rfilter, ConstructorSpec } from '../runtime/rewrite.js';
import { _ptr, attenuate, CRec, Lit, Pattern, PCompound, rfilter, ConstructorSpec } from '../runtime/rewrite.js';
import { $BoxState, $SetBox } from '../gen/box-protocol.js';
import { $Observe } from '../gen/dataspace.js';
import { spawnWorker } from '../worker/index.js';
@ -38,7 +38,7 @@ new Actor(async (t: Turn) => {
})),
Pattern.PCompound(PCompound({
ctor: ConstructorSpec.CRec(CRec({ label: $Observe, arity: 2 })),
members: new Dictionary<Ref, Pattern>([
members: new Dictionary<_ptr, Pattern>([
[0, Pattern.Lit(Lit($SetBox))]])
}))));
@ -51,16 +51,16 @@ new Actor(async (t: Turn) => {
})),
Pattern.PCompound(PCompound({
ctor: ConstructorSpec.CRec(CRec({ label: $Observe, arity: 2 })),
members: new Dictionary<Ref, Pattern>([
members: new Dictionary<_ptr, 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, [embed(ds_for_box), 500000, 25000]);
spawnWorker(t, boxpath, [embed(ds_for_box), 50000, 2500]);
spawnModule(t, clientpath, ds_for_client);
// spawnWorker(t, clientpath, ds_for_client);
spawnModule(t, clientpath, embed(ds_for_client));
// spawnWorker(t, clientpath, embed(ds_for_client));
});

View File

@ -2,8 +2,10 @@ import { $joinedUser, $says, $user, asJoin, asSays, asUserInfo, fromNickClaim, f
import { during, observe } from "../runtime/dataspace.js";
import { Assertion, Ref, Turn } from "../runtime/actor.js";
import { attachReadline } from './readline.js';
import { Pointer } from "@preserves/core";
export default function (t: Turn, ds: Ref) {
export default function (t: Turn, ds_ptr: Pointer<Ref>) {
const ds = ds_ptr.embeddedValue;
observe(t, ds, $joinedUser, during(async (t, j0) => {
const j = asJoin(j0);
const facet = t.facet(t => runSession(t, j.uid, j.handle));

View File

@ -15,11 +15,12 @@ import {
import { Assertion, Handle, Ref, Turn } from "../runtime/actor.js";
import { observe, during, $Observe, asObserve, Dataspace } from "../runtime/dataspace.js";
import { attenuate, rfilter, pRec, pPointer, pString, pLit } from "../runtime/rewrite.js";
import { attenuate as sturdyAttenuate, fromBind, Bind, KEY_LENGTH, sturdyEncode, fromSturdyRef, mint } from "../transport/sturdy.js";
import { Bytes } from "@preserves/core";
import { attenuate as sturdyAttenuate, KEY_LENGTH, sturdyEncode, fromSturdyRef, mint } from "../transport/sturdy.js";
import { Bind, fromBind } from "../gen/gatekeeper.js";
import { Bytes, Pointer } from "@preserves/core";
export default function (t: Turn, gatekeeperDs: Ref) {
let nextUserId: UserId = 0;
export default function (t: Turn, gatekeeperDs_ptr: Pointer<Ref>) {
const gatekeeperDs = gatekeeperDs_ptr.embeddedValue;
const ds = t.ref(new Dataspace());
@ -34,6 +35,7 @@ export default function (t: Turn, gatekeeperDs: Ref) {
const nicks = new Map<string, UserId>();
let nextUserId: UserId = 0;
observe(t, ds, $Observe, during(async (t, o0) => {
const o = asObserve(o0);
if (o.label !== $joinedUser) return null;

View File

@ -2,8 +2,11 @@ import { $Present, $Says, asPresent, asSays, fromPresent, fromSays, Present, Say
import { during, observe } from "../runtime/dataspace.js";
import { Assertion, Handle, Ref, Turn } from "../runtime/actor.js";
import { attachReadline } from './readline.js';
import { Pointer } from "@preserves/core";
export default function (t: Turn, ds_ptr: Pointer<Ref>) {
const ds = ds_ptr.embeddedValue;
export default function (t: Turn, ds: Ref) {
let username = '';
let usernameHandle: Handle | undefined;

View File

@ -2,7 +2,6 @@ import { newKey } from '../transport/cryptography.js';
import { attenuate, KEY_LENGTH, mint, Caveat, Rewrite, sturdyEncode, validate } from '../transport/sturdy.js';
import * as RW from '../runtime/rewrite.js';
import { Bytes, Dictionary } from '@preserves/core';
import { Ref } from '../runtime/actor.js';
async function main() {
const m1 = await mint('hello world', new Bytes(KEY_LENGTH));
@ -15,7 +14,7 @@ async function main() {
label: Symbol.for('says'),
arity: 2
})),
members: new Dictionary<Ref, RW.Pattern>([
members: new Dictionary<RW._ptr, RW.Pattern>([
[0, RW.Pattern.Lit(RW.Lit('Tony'))]])
}))
})),

View File

@ -13,8 +13,6 @@ export type BoxState = {"value": 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": value};}
export function SetBox(value: number): SetBox {return {"value": value};}

View File

@ -10,8 +10,6 @@ export type _val = _.Value<_ptr>;
export type Observe = {"label": symbol, "observer": _ptr};
export const _toPtr = (v: _val) => {let result: undefined | _ptr; result = _i_Actor.toRef(v); return result;};
export function Observe({label, observer}: {label: symbol, observer: _ptr}): Observe {return {"label": label, "observer": observer};}
export function asObserve(v: _val): Observe {
@ -30,7 +28,7 @@ export function toObserve(v: _val): undefined | Observe {
_tmp1 = typeof v[0] === 'symbol' ? v[0] : void 0;
if (_tmp1 !== void 0) {
let _tmp2: (_ptr) | undefined;
_tmp2 = _toPtr(v[1]);
_tmp2 = _.isPointer<_ptr>(v[1]) ? v[1].embeddedValue : void 0;
if (_tmp2 !== void 0) {result = {"label": _tmp1, "observer": _tmp2};};
};
};
@ -38,5 +36,5 @@ export function toObserve(v: _val): undefined | Observe {
return result;
}
export function fromObserve(_v: Observe): _val {return _.Record($Observe, [_v["label"], _v["observer"]]);}
export function fromObserve(_v: Observe): _val {return _.Record($Observe, [_v["label"], _.embed(_v["observer"])]);}

78
src/gen/gatekeeper.ts Normal file
View File

@ -0,0 +1,78 @@
import * as _ from "@preserves/core";
import * as _i_Actor from "../runtime/actor";
import * as _i_sturdy from "./sturdy";
export const $bind = Symbol.for("bind");
export const $resolve = Symbol.for("resolve");
export type _ptr = _i_Actor.Ref;
export type _val = _.Value<_ptr>;
export type Resolve = {"sturdyref": _i_sturdy.SturdyRef, "observer": _ptr};
export type Bind = {"oid": _val, "key": _.Bytes, "target": _ptr};
export function Resolve({sturdyref, observer}: {sturdyref: _i_sturdy.SturdyRef, observer: _ptr}): Resolve {return {"sturdyref": sturdyref, "observer": observer};}
export function Bind({oid, key, target}: {oid: _val, key: _.Bytes, target: _ptr}): Bind {return {"oid": oid, "key": key, "target": target};}
export function asResolve(v: _val): Resolve {
let result = toResolve(v);
if (result === void 0) throw new TypeError(`Invalid Resolve: ${_.stringify(v)}`);
return result;
}
export function toResolve(v: _val): undefined | Resolve {
let result: undefined | Resolve;
if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v)) {
let _tmp0: (null) | undefined;
_tmp0 = _.is(v.label, $resolve) ? null : void 0;
if (_tmp0 !== void 0) {
let _tmp1: (_i_sturdy.SturdyRef) | undefined;
_tmp1 = _i_sturdy.toSturdyRef(v[0]);
if (_tmp1 !== void 0) {
let _tmp2: (_ptr) | undefined;
_tmp2 = _.isPointer<_ptr>(v[1]) ? v[1].embeddedValue : void 0;
if (_tmp2 !== void 0) {result = {"sturdyref": _tmp1, "observer": _tmp2};};
};
};
};
return result;
}
export function fromResolve(_v: Resolve): _val {
return _.Record($resolve, [_i_sturdy.fromSturdyRef(_v["sturdyref"]), _.embed(_v["observer"])]);
}
export function asBind(v: _val): Bind {
let result = toBind(v);
if (result === void 0) throw new TypeError(`Invalid Bind: ${_.stringify(v)}`);
return result;
}
export function toBind(v: _val): undefined | Bind {
let result: undefined | Bind;
if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v)) {
let _tmp0: (null) | undefined;
_tmp0 = _.is(v.label, $bind) ? null : void 0;
if (_tmp0 !== void 0) {
let _tmp1: (_val) | undefined;
_tmp1 = v[0];
if (_tmp1 !== void 0) {
let _tmp2: (_.Bytes) | undefined;
_tmp2 = _.Bytes.isBytes(v[1]) ? v[1] : void 0;
if (_tmp2 !== void 0) {
let _tmp3: (_ptr) | undefined;
_tmp3 = _.isPointer<_ptr>(v[2]) ? v[2].embeddedValue : void 0;
if (_tmp3 !== void 0) {result = {"oid": _tmp1, "key": _tmp2, "target": _tmp3};};
};
};
};
};
return result;
}
export function fromBind(_v: Bind): _val {return _.Record($bind, [_v["oid"], _v["key"], _.embed(_v["target"])]);}

View File

@ -1,12 +1,12 @@
import * as _ from "@preserves/core";
import * as _i_Protocol from "../transport/protocol";
import * as _i_sturdy from "./sturdy";
export const $assert = Symbol.for("assert");
export const $message = Symbol.for("message");
export const $retract = Symbol.for("retract");
export const $sync = Symbol.for("sync");
export type _ptr = _i_Protocol.WireRef;
export type _ptr = _i_sturdy.WireRef;
export type _val = _.Value<_ptr>;
@ -36,12 +36,6 @@ 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;}
@ -285,12 +279,12 @@ export function toSync(v: _val): undefined | Sync {
_tmp0 = _.is(v.label, $sync) ? null : void 0;
if (_tmp0 !== void 0) {
let _tmp1: (_ptr) | undefined;
_tmp1 = _toPtr(v[0]);
_tmp1 = _.isPointer<_ptr>(v[0]) ? v[0].embeddedValue : void 0;
if (_tmp1 !== void 0) {result = {"peer": _tmp1};};
};
};
return result;
}
export function fromSync(_v: Sync): _val {return _.Record($sync, [_v["peer"]]);}
export function fromSync(_v: Sync): _val {return _.Record($sync, [_.embed(_v["peer"])]);}

View File

@ -24,8 +24,6 @@ export type Says = {"who": UserId, "what": string};
export type NickConflict = null;
export const _toPtr = (v: _val) => {let result: undefined | _ptr; result = _i_Actor.toRef(v); return result;};
export function UserId(value: number): UserId {return value;}
export function Join({uid, handle}: {uid: UserId, handle: _ptr}): Join {return {"uid": uid, "handle": handle};}
@ -70,7 +68,7 @@ export function toJoin(v: _val): undefined | Join {
_tmp1 = toUserId(v[0]);
if (_tmp1 !== void 0) {
let _tmp2: (_ptr) | undefined;
_tmp2 = _toPtr(v[1]);
_tmp2 = _.isPointer<_ptr>(v[1]) ? v[1].embeddedValue : void 0;
if (_tmp2 !== void 0) {result = {"uid": _tmp1, "handle": _tmp2};};
};
};
@ -78,7 +76,7 @@ export function toJoin(v: _val): undefined | Join {
return result;
}
export function fromJoin(_v: Join): _val {return _.Record($joinedUser, [fromUserId(_v["uid"]), _v["handle"]]);}
export function fromJoin(_v: Join): _val {return _.Record($joinedUser, [fromUserId(_v["uid"]), _.embed(_v["handle"])]);}
export function asNickClaim(v: _val): NickClaim {
let result = toNickClaim(v);
@ -99,7 +97,7 @@ export function toNickClaim(v: _val): undefined | NickClaim {
_tmp2 = typeof v[1] === 'string' ? v[1] : void 0;
if (_tmp2 !== void 0) {
let _tmp3: (_ptr) | undefined;
_tmp3 = _toPtr(v[2]);
_tmp3 = _.isPointer<_ptr>(v[2]) ? v[2].embeddedValue : void 0;
if (_tmp3 !== void 0) {result = {"uid": _tmp1, "name": _tmp2, "k": _tmp3};};
};
};
@ -108,7 +106,9 @@ export function toNickClaim(v: _val): undefined | NickClaim {
return result;
}
export function fromNickClaim(_v: NickClaim): _val {return _.Record($claimNick, [fromUserId(_v["uid"]), _v["name"], _v["k"]]);}
export function fromNickClaim(_v: NickClaim): _val {
return _.Record($claimNick, [fromUserId(_v["uid"]), _v["name"], _.embed(_v["k"])]);
}
export function asUserInfo(v: _val): UserInfo {
let result = toUserInfo(v);

View File

@ -13,8 +13,6 @@ export type Present = {"username": string};
export type Says = {"who": string, "what": string};
export const _toPtr = (v: _val) => {let result: undefined | _ptr; result = _i_Actor.toRef(v); return result;};
export function Present(username: string): Present {return {"username": username};}
export function Says({who, what}: {who: string, what: string}): Says {return {"who": who, "what": what};}

View File

@ -1,6 +1,7 @@
import * as _ from "@preserves/core";
import * as _i_Actor from "../runtime/actor";
export const $0 = 0;
export const $1 = 1;
export const $Boolean = Symbol.for("Boolean");
export const $ByteString = Symbol.for("ByteString");
export const $Double = Symbol.for("Double");
@ -20,10 +21,9 @@ 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 type _ptr = _i_Actor.Ref;
export type _ptr = any;
export type _val = _.Value<_ptr>;
@ -40,9 +40,12 @@ export type Rewrite = {"pattern": Pattern, "template": Template};
export type Alts = {"alternatives": Array<Rewrite>};
export type Resolve = {"sturdyref": SturdyRef, "observer": _ptr};
export type Oid = number;
export type Bind = {"oid": _val, "key": _.Bytes, "target": _ptr};
export type WireRef = (
{"_variant": "mine", "oid": Oid} |
{"_variant": "yours", "oid": Oid, "attenuation": Array<Caveat>}
);
export type ConstructorSpec = (
{"_variant": "CRec", "value": CRec} |
@ -106,8 +109,6 @@ export type TCompound = {"ctor": ConstructorSpec, "members": TCompoundMembers};
export type TCompoundMembers = _.KeyedDictionary<_val, Template, _ptr>;
export const _toPtr = (v: _val) => {let result: undefined | _ptr; result = _i_Actor.toRef(v); return result;};
export function SturdyRef(
{oid, caveatChain, sig}: {oid: _val, caveatChain: Array<Attenuation>, sig: _.Bytes}
): SturdyRef {return {"oid": oid, "caveatChain": caveatChain, "sig": sig};}
@ -123,9 +124,12 @@ export function Rewrite({pattern, template}: {pattern: Pattern, template: Templa
export function Alts(alternatives: Array<Rewrite>): Alts {return {"alternatives": alternatives};}
export function Resolve({sturdyref, observer}: {sturdyref: SturdyRef, observer: _ptr}): Resolve {return {"sturdyref": sturdyref, "observer": observer};}
export function Oid(value: number): Oid {return value;}
export function Bind({oid, key, target}: {oid: _val, key: _.Bytes, target: _ptr}): Bind {return {"oid": oid, "key": key, "target": target};}
export namespace WireRef {
export function mine(oid: Oid): WireRef {return {"_variant": "mine", "oid": oid};};
export function yours({oid, attenuation}: {oid: Oid, attenuation: Array<Caveat>}): WireRef {return {"_variant": "yours", "oid": oid, "attenuation": attenuation};};
}
export namespace ConstructorSpec {
export function CRec(value: CRec): ConstructorSpec {return {"_variant": "CRec", "value": value};};
@ -347,53 +351,61 @@ export function toAlts(v: _val): undefined | Alts {
export function fromAlts(_v: Alts): _val {return _.Record($or, [_v["alternatives"].map(v => fromRewrite(v))]);}
export function asResolve(v: _val): Resolve {
let result = toResolve(v);
if (result === void 0) throw new TypeError(`Invalid Resolve: ${_.stringify(v)}`);
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 toResolve(v: _val): undefined | Resolve {
let result: undefined | Resolve;
if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(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 fromOid(_v: Oid): _val {return _v;}
export function asWireRef(v: _val): WireRef {
let result = toWireRef(v);
if (result === void 0) throw new TypeError(`Invalid WireRef: ${_.stringify(v)}`);
return result;
}
export function toWireRef(v: _val): undefined | WireRef {
let result: undefined | WireRef;
if (_.Array.isArray(v) && v.length === 2) {
let _tmp0: (null) | undefined;
_tmp0 = _.is(v.label, $resolve) ? null : void 0;
_tmp0 = _.is(v[0], $0) ? null : void 0;
if (_tmp0 !== void 0) {
let _tmp1: (SturdyRef) | undefined;
_tmp1 = toSturdyRef(v[0]);
if (_tmp1 !== void 0) {
let _tmp2: (_ptr) | undefined;
_tmp2 = _toPtr(v[1]);
if (_tmp2 !== void 0) {result = {"sturdyref": _tmp1, "observer": _tmp2};};
};
let _tmp1: (Oid) | undefined;
_tmp1 = toOid(v[1]);
if (_tmp1 !== void 0) {result = {"_variant": "mine", "oid": _tmp1};};
};
};
return result;
}
export function fromResolve(_v: Resolve): _val {return _.Record($resolve, [fromSturdyRef(_v["sturdyref"]), _v["observer"]]);}
export function asBind(v: _val): Bind {
let result = toBind(v);
if (result === void 0) throw new TypeError(`Invalid Bind: ${_.stringify(v)}`);
return result;
}
export function toBind(v: _val): undefined | Bind {
let result: undefined | Bind;
if (_.Record.isRecord<_val, _.Tuple<_val>, _ptr>(v)) {
let _tmp0: (null) | undefined;
_tmp0 = _.is(v.label, $bind) ? null : void 0;
if (_tmp0 !== void 0) {
let _tmp1: (_val) | undefined;
_tmp1 = v[0];
if (_tmp1 !== void 0) {
let _tmp2: (_.Bytes) | undefined;
_tmp2 = _.Bytes.isBytes(v[1]) ? v[1] : void 0;
if (_tmp2 !== void 0) {
let _tmp3: (_ptr) | undefined;
_tmp3 = _toPtr(v[2]);
if (_tmp3 !== void 0) {result = {"oid": _tmp1, "key": _tmp2, "target": _tmp3};};
if (result === void 0) {
if (_.Array.isArray(v) && v.length >= 2) {
let _tmp2: (null) | undefined;
_tmp2 = _.is(v[0], $1) ? null : void 0;
if (_tmp2 !== void 0) {
let _tmp3: (Oid) | undefined;
_tmp3 = toOid(v[1]);
if (_tmp3 !== void 0) {
let _tmp4: (Array<_val>) | undefined;
let _tmp5: (Array<Caveat>) | undefined;
_tmp4 = v.slice(2);
{
_tmp5 = [];
for (const _tmp6 of _tmp4) {
let _tmp7: (Caveat) | undefined;
_tmp7 = toCaveat(_tmp6);
if (_tmp7 !== void 0) {_tmp5.push(_tmp7); continue;};
_tmp5 = void 0;
break;
};
if (_tmp5 !== void 0) {result = {"_variant": "yours", "oid": _tmp3, "attenuation": _tmp5};};
};
};
};
};
@ -401,7 +413,14 @@ export function toBind(v: _val): undefined | Bind {
return result;
}
export function fromBind(_v: Bind): _val {return _.Record($bind, [_v["oid"], _v["key"], _v["target"]]);}
export function fromWireRef(_v: WireRef): _val {
switch (_v._variant) {
case "mine": {return [$0, fromOid(_v["oid"])];};
case "yours": {
return [$1, fromOid(_v["oid"]), ... _v["attenuation"].map(v => fromCaveat(v))];
};
};
}
export function asConstructorSpec(v: _val): ConstructorSpec {
let result = toConstructorSpec(v);

View File

@ -10,8 +10,6 @@ export type _val = _.Value<_ptr>;
export type Instance = {"name": string, "argument": _val};
export const _toPtr = (v: _val) => {let result: undefined | _ptr; result = _i_Actor.toRef(v); return result;};
export function Instance({name, argument}: {name: string, argument: _val}): Instance {return {"name": name, "argument": argument};}
export function asInstance(v: _val): Instance {

View File

@ -1,6 +1,6 @@
// Bags and Deltas (which are Bags where item-counts can be negative).
import { Value, Set, Dictionary, DefaultPointer } from '@preserves/core';
import { Value, Set, Dictionary, GenericPointer } from '@preserves/core';
export enum ChangeDescription {
PRESENT_TO_ABSENT = -1,
@ -9,7 +9,7 @@ export enum ChangeDescription {
PRESENT_TO_PRESENT = 2,
}
export class Bag<T extends object = DefaultPointer> {
export class Bag<T extends object = GenericPointer> {
_items: Dictionary<T, number>;
constructor(s?: Set<T>) {

View File

@ -23,6 +23,7 @@ import {
TRef,
Template,
_val,
_ptr,
} from '../gen/sturdy.js';
export * from '../gen/sturdy.js';
@ -90,9 +91,9 @@ export function match(p: Pattern, v: Assertion): Bindings | null {
}
return true;
case 'CDict':
if (!Dictionary.isDictionary<Assertion, Ref>(v)) return false;
if (!Dictionary.isDictionary<Ref, Assertion>(v)) return false;
for (const [key, pp] of members) {
const vv = v.get(key as Assertion);
const vv = v.get(key);
if (vv === void 0) return false;
if (!walk(pp, vv)) return false;
}
@ -118,7 +119,7 @@ export function instantiate(t: Template, b: Bindings): Assertion {
return v;
}
case 'Lit':
return t.value.value as Assertion;
return t.value.value;
case 'TCompound': {
const ctor = t.value.ctor;
const members = t.value.members;
@ -143,7 +144,7 @@ export function instantiate(t: Template, b: Bindings): Assertion {
case 'CDict': {
const v = new Dictionary<Ref, Assertion>();
for (const [key, tt] of members) {
v.set(key as Assertion, walk(tt));
v.set(key, walk(tt));
}
return v;
}
@ -233,21 +234,21 @@ export function forwarder(t: Turn, ref: Ref): { proxy: Ref, revoker: Ref } {
export function pRec(label: _val, ... members: Array<Pattern>): Pattern {
return Pattern.PCompound(PCompound({
ctor: ConstructorSpec.CRec(CRec({ label: label, arity: members.length })),
members: PCompoundMembers(new Dictionary<Ref, Pattern>(
members: PCompoundMembers(new Dictionary<_ptr, Pattern>(
members.map((p, i) => [i, p] as const).filter(e => e[1]._variant !== 'PDiscard')))}));
}
export function pArr(... members: Array<Pattern>): Pattern {
return Pattern.PCompound(PCompound({
ctor: ConstructorSpec.CArr(CArr(members.length)),
members: PCompoundMembers(new Dictionary<Ref, Pattern>(
members: PCompoundMembers(new Dictionary<_ptr, Pattern>(
members.map((p, i) => [i, p] as const).filter(e => e[1]._variant !== 'PDiscard')))}));
}
export function pDict(... entries: [_val, Pattern][]): Pattern {
return Pattern.PCompound(PCompound({
ctor: ConstructorSpec.CDict(CDict()),
members: PCompoundMembers(new Dictionary<Ref, Pattern>(entries))}));
members: PCompoundMembers(new Dictionary<_ptr, Pattern>(entries))}));
}
export function pLit(value: _val): Pattern {

View File

@ -1,10 +1,10 @@
import { Bytes, Reader } from '@preserves/core';
import { fromSturdyRef, toSturdyRef, toCaveat, attenuate, sturdyDecode, sturdyEncode } from '../transport/sturdy.js';
import { fromSturdyRef, toSturdyRef, toCaveat, attenuate, sturdyDecode, sturdyEncode, _ptr } from '../transport/sturdy.js';
const [ base, pat ] = process.argv.slice(2);
const baseCap = toSturdyRef(sturdyDecode(Bytes.fromHex(base ?? '')));
if (baseCap === void 0) throw new Error("Cannot decode sturdyref");
const cs0 = new Reader(pat).next();
const cs0 = new Reader<_ptr>(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 => {

View File

@ -1,42 +1,24 @@
import { Attenuation, toAttenuation } from '../gen/sturdy.js';
import * as S from '../gen/sturdy.js';
import * as IO from '../gen/protocol.js';
import { Assertion, Ref } from '../runtime/actor.js';
import { mapPointers } from '@preserves/core';
import { pointerNotAllowed } from './sturdy.js';
import { Ref } from '../runtime/actor.js';
import { Decoder, DecoderState, Encoder, EncoderState, GenericPointer, neverPointerType, PointerType, Value } from '@preserves/core';
export type WireSymbol = { oid: IO.Oid, ref: Ref, count: number };
export type WireRef =
| { loc: "mine", oid: IO.Oid }
| { loc: "your", oid: IO.Oid, attenuation: Attenuation };
export const wireRefPointerType: PointerType<S.WireRef> = {
decode(s: DecoderState): S.WireRef {
return S.asWireRef(new Decoder<any>(s).next());
},
export function myRef(oid: IO.Oid): WireRef & { loc: "mine" } {
return { loc: 'mine', oid };
}
encode(s: EncoderState, v: S.WireRef): void {
new Encoder<any>(s, neverPointerType).push(S.fromWireRef(v));
},
export function yourRef(oid: IO.Oid, attenuation: Attenuation): WireRef & { loc: "your" } {
return { loc: 'your', oid, attenuation };
}
fromValue(v: Value<GenericPointer>): S.WireRef {
return S.asWireRef(v as S._val);
},
export function toWireRef(v: IO._val): WireRef | undefined {
if (Array.isArray(v) && v.length >= 2) {
switch (v[0]) {
case 0: {
const oid = v[1];
if (typeof oid === 'number') return myRef(oid);
break;
}
case 1: {
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;
}
default:
break;
}
toValue(v: S.WireRef): Value<GenericPointer> {
return S.fromWireRef(v) as Value<GenericPointer>;
}
return void 0;
}
};

View File

@ -1,11 +1,10 @@
import { Actor, Assertion, Entity, Facet, Handle, Ref, Turn } from '../runtime/actor.js';
import { BytesLike, canonicalString, Decoder, encode, FlexMap, IdentityMap, mapPointers, underlying, Value } from '@preserves/core';
import { BytesLike, Decoder, Dictionary, embed, encode, IdentityMap, mapPointers, underlying, Value } from '@preserves/core';
import * as IO from '../gen/protocol.js';
import { myRef, toWireRef, WireRef, WireSymbol, yourRef } from './protocol.js';
import { wireRefPointerType, WireSymbol } from './protocol.js';
import { queueTask } from '../runtime/task.js';
import { attenuate } from '../runtime/rewrite.js';
import { Attenuation, fromAttenuation } from '../gen/sturdy.js';
import { pointerNotAllowed } from './sturdy.js';
import { fromAttenuation, WireRef } from '../gen/sturdy.js';
export class SyncPeerEntity implements Entity {
readonly relay: Relay;
@ -136,8 +135,10 @@ export class Relay {
debug: boolean;
trustPeer: boolean;
readonly decoder = new Decoder(void 0, { includeAnnotations: false })
.replacePointerDecoder<WireRef>(d => toWireRef(d.next()));
readonly decoder = new Decoder(void 0, {
includeAnnotations: false,
pointerType: wireRefPointerType,
});
constructor(t: Turn, options: RelayOptions) {
this.facet = t.activeFacet;
@ -152,14 +153,14 @@ export class Relay {
rewriteOut(assertion: Assertion, transient: boolean): [Value<WireRef>, Array<WireSymbol>]
{
const exported: Array<WireSymbol> = [];
const rewritten = mapPointers(assertion, r => this.rewriteRefOut(r, transient, exported));
const rewritten = mapPointers(assertion, r => embed(this.rewriteRefOut(r, transient, exported)));
return [rewritten, exported];
}
rewriteIn(t: Turn, a: Value<WireRef>): [Assertion, Array<WireSymbol>]
{
const imported: Array<WireSymbol> = [];
const rewritten = mapPointers(a, r => this.rewriteRefIn(t, r, imported));
const rewritten = mapPointers(a, r => embed(this.rewriteRefIn(t, r, imported)));
return [rewritten, imported];
}
@ -177,12 +178,12 @@ export class Relay {
if (r.target instanceof RelayEntity && r.target.relay === this) {
if (r.attenuation === void 0 || r.attenuation.length === 0) {
// No extra conditions on this reference since it was sent to us.
return yourRef(r.target.oid, []);
return WireRef.yours({ oid: r.target.oid, attenuation: [] });
} else {
// This reference has been attenuated since it was sent to us.
// Do we trust the peer to enforce such attenuation on our behalf?
if (this.trustPeer) {
return yourRef(r.target.oid, r.attenuation);
return WireRef.yours({ oid: r.target.oid, attenuation: r.attenuation });
} else {
// fall through: treat the attenuated ref as a local ref, and re-export it.
}
@ -195,7 +196,7 @@ export class Relay {
return { oid: this.nextLocalOid++, ref: r, count: 0 };
});
exported.push(e);
return myRef(e.oid);
return WireRef.mine(e.oid);
}
releaseRefOut(e: WireSymbol) {
@ -203,18 +204,18 @@ export class Relay {
}
rewriteRefIn(t: Turn, n: WireRef, imported: Array<WireSymbol>): Ref {
switch (n.loc) {
case 'your': {
switch (n._variant) {
case 'yours': {
const r = this.lookupLocal(n.oid);
if (n.attenuation.length === 0 || r === INERT_REF) {
return r;
} else {
type AttenuatedRef = Ref & { __attenuations?: FlexMap<Attenuation, Ref> };
type AttenuatedRef = Ref & { __attenuations?: Dictionary<any, Ref> };
const ar = r as AttenuatedRef;
if (ar.__attenuations === void 0) {
ar.__attenuations = new FlexMap(canonicalString);
ar.__attenuations = new Dictionary();
}
return ar.__attenuations.getOrSet(n.attenuation, () =>
return ar.__attenuations.getOrSet(fromAttenuation(n.attenuation), () =>
attenuate(r, ... n.attenuation));
}
}
@ -231,15 +232,9 @@ export class Relay {
if (this.pendingTurn.length === 0) {
queueTask(() => {
if (this.debug) console.log('OUT', IO.fromTurn(this.pendingTurn).asPreservesText());
this.w(underlying(encode<WireRef>(IO.fromTurn(this.pendingTurn), {
this.w(underlying(encode(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>(
fromAttenuation(n.attenuation), pointerNotAllowed) as Array<IO._val>]);
}
},
pointerType: wireRefPointerType,
})));
this.pendingTurn = [];
});
@ -323,7 +318,7 @@ export function spawnRelay(t: Turn, options: RelayActorOptions): Promise<Ref | n
relay.rewriteRefOut(options.initialRef, false, []);
}
if (options.initialOid !== void 0) {
resolve(relay.rewriteRefIn(t, myRef(options.initialOid), []));
resolve(relay.rewriteRefIn(t, WireRef.mine(options.initialOid), []));
} else {
resolve(null);
}

View File

@ -7,7 +7,7 @@
// California: Internet Society, 2014.
import { mac } from './cryptography.js';
import { Bytes, decode, encode, is } from '@preserves/core';
import { Bytes, decode, encode, is, neverPointerType } from '@preserves/core';
import * as S from '../gen/sturdy.js';
export * from '../gen/sturdy.js';
@ -23,14 +23,14 @@ export function sturdyEncode(v: SturdyValue): Bytes {
return encode<S._ptr>(v, {
canonical: true,
includeAnnotations: false,
encodePointer: pointerNotAllowed,
pointerType: neverPointerType,
});
}
export function sturdyDecode(bs: Bytes): SturdyValue {
return decode<S._ptr>(bs, {
includeAnnotations: false,
decodePointer: pointerNotAllowed,
pointerType: neverPointerType,
});
}

View File

@ -1,13 +1,9 @@
// Web Worker loader
import { Actor, Turn, Assertion, Ref, __setNextActorId } from '../runtime/actor.js';
import { Record } from '@preserves/core';
import { Actor, Turn, Ref, __setNextActorId } from '../runtime/actor.js';
import { parentPort, threadId } from 'worker_threads';
import { Relay, spawnRelay } from '../transport/relay.js';
const _Instance = Symbol.for('Instance');
const Instance = Record.makeConstructor<{moduleName: string, arg: Assertion}>()(
_Instance, ['moduleName', 'arg']);
import { toInstance } from '../gen/worker.js';
const STARTING_ACTOR_ID = (threadId & (2 ** 20 - 1)) * 1000000000;
__setNextActorId(STARTING_ACTOR_ID);
@ -30,13 +26,14 @@ new Actor(t => {
p.on('close', () => Turn.for(t.activeFacet, t => t.stopActor()));
},
initialRef: t.ref({
async assert(t, inst) {
if (!Instance.isClassOf(inst)) return;
async assert(t, inst0) {
const inst = toInstance(inst0);
if (inst === void 0) return;
if (taskState.state !== "start_pending") return;
taskState = { state: "starting" };
const m = await import(Instance._.moduleName(inst));
const m = await import(inst.name);
t.freshen(t => t.spawn(t => {
t.activeFacet.actor.atExit(() => {
console.log('Worker terminating');
@ -49,7 +46,7 @@ new Actor(t => {
state: "running",
shutdownRef: t.ref({ message(t) { t.stopActor(); } }),
};
m.default(t, Instance._.arg(inst));
m.default(t, inst.argument);
}
}));
},