Switch to directly-represented embedded values
This commit is contained in:
parent
f5ed511c4e
commit
9521fc3dcc
|
@ -1,7 +1,7 @@
|
||||||
/// SPDX-License-Identifier: GPL-3.0-or-later
|
/// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||||
|
|
||||||
import { IdentitySet, Value, embeddedId, is, fromJS, stringify, Dictionary, KeyedSet, Tuple } from '@preserves/core';
|
import { IdentitySet, Value, embeddedId, is, fromJS, stringify, Dictionary, KeyedSet, Tuple, Embeddable } from '@preserves/core';
|
||||||
import { Cell, Field, Graph } from './dataflow.js';
|
import { Cell, Field, Graph } from './dataflow.js';
|
||||||
import { Caveat, runRewrites } from './rewrite.js';
|
import { Caveat, runRewrites } from './rewrite.js';
|
||||||
import { ActorSpace } from './space.js';
|
import { ActorSpace } from './space.js';
|
||||||
|
@ -23,7 +23,11 @@ export type ExitReason = null | { ok: true } | { ok: false, err: unknown };
|
||||||
export type LocalAction = () => void;
|
export type LocalAction = () => void;
|
||||||
export type DetailedAction<T = AnyValue> = LocalAction & { detail: T };
|
export type DetailedAction<T = AnyValue> = LocalAction & { detail: T };
|
||||||
|
|
||||||
export type Assertable = Assertion | { __as_preserve__: <T>() => Value<T> } | { __as_preserve__: () => Assertion };
|
export type Assertable =
|
||||||
|
| Assertion
|
||||||
|
| { __as_preserve__: <T extends Embeddable>() => Value<T> }
|
||||||
|
| { __as_preserve__: () => Assertion }
|
||||||
|
;
|
||||||
|
|
||||||
export interface Entity {
|
export interface Entity {
|
||||||
assert(assertion: Assertion, handle: Handle): void;
|
assert(assertion: Assertion, handle: Handle): void;
|
||||||
|
@ -35,13 +39,7 @@ export interface Entity {
|
||||||
|
|
||||||
export type Cap = Ref;
|
export type Cap = Ref;
|
||||||
|
|
||||||
export interface Ref {
|
export class Ref {
|
||||||
readonly relay: Facet;
|
|
||||||
readonly target: Partial<Entity>;
|
|
||||||
readonly attenuation?: Caveat[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class RefImpl implements Ref {
|
|
||||||
readonly relay: Facet;
|
readonly relay: Facet;
|
||||||
readonly target: Partial<Entity>;
|
readonly target: Partial<Entity>;
|
||||||
readonly attenuation?: Caveat[];
|
readonly attenuation?: Caveat[];
|
||||||
|
@ -64,6 +62,10 @@ export class RefImpl implements Ref {
|
||||||
if ('sync' in this.target) sig = sig + 'S';
|
if ('sync' in this.target) sig = sig + 'S';
|
||||||
return `⌜${this.relay.idChain()}<${sig}>${entityRepr}⌝`;
|
return `⌜${this.relay.idChain()}<${sig}>${entityRepr}⌝`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __from_preserve__(v: AnyValue): undefined | Ref {
|
||||||
|
return typeof v === 'object' && 'relay' in v ? v : void 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -351,7 +353,7 @@ export class Turn {
|
||||||
}
|
}
|
||||||
|
|
||||||
ref<T extends Partial<Entity>>(e: T): Ref {
|
ref<T extends Partial<Entity>>(e: T): Ref {
|
||||||
return new RefImpl(this.activeFacet, e);
|
return new Ref(this.activeFacet, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
facet(bootProc: LocalAction): Facet {
|
facet(bootProc: LocalAction): Facet {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
// Bags and Deltas (which are Bags where item-counts can be negative).
|
// Bags and Deltas (which are Bags where item-counts can be negative).
|
||||||
|
|
||||||
import { Value, KeyedDictionary, KeyedSet } from '@preserves/core';
|
import { Value, KeyedDictionary, KeyedSet, Embeddable } from '@preserves/core';
|
||||||
|
|
||||||
export enum ChangeDescription {
|
export enum ChangeDescription {
|
||||||
PRESENT_TO_ABSENT = -1,
|
PRESENT_TO_ABSENT = -1,
|
||||||
|
@ -12,7 +12,7 @@ export enum ChangeDescription {
|
||||||
PRESENT_TO_PRESENT = 2,
|
PRESENT_TO_PRESENT = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Bag<T, V extends Value<T> = Value<T>> {
|
export class Bag<T extends Embeddable, V extends Value<T> = Value<T>> {
|
||||||
_items: KeyedDictionary<V, number, T>;
|
_items: KeyedDictionary<V, number, T>;
|
||||||
|
|
||||||
constructor(s?: KeyedSet<V, T>) {
|
constructor(s?: KeyedSet<V, T>) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||||
|
|
||||||
import { Turn } from "./actor.js";
|
import { Turn } from "./actor.js";
|
||||||
import { Bytes, Dictionary, DoubleFloat, embed, IdentityMap, is, isEmbedded, Record, Tuple, stringify } from "@preserves/core";
|
import { Bytes, Dictionary, DoubleFloat, IdentityMap, is, isEmbedded, Record, Tuple, stringify } from "@preserves/core";
|
||||||
import type { Assertion, Handle, Ref } from "./actor.js";
|
import type { Assertion, Handle, Ref } from "./actor.js";
|
||||||
import type { SturdyValue } from "../transport/sturdy.js";
|
import type { SturdyValue } from "../transport/sturdy.js";
|
||||||
|
|
||||||
|
@ -113,8 +113,7 @@ export function instantiate(t: Template, b: Bindings): Assertion {
|
||||||
if (!isEmbedded(v)) {
|
if (!isEmbedded(v)) {
|
||||||
throw new Error(`Attempt to attenuate non-capability: ${stringify(v)}`);
|
throw new Error(`Attempt to attenuate non-capability: ${stringify(v)}`);
|
||||||
}
|
}
|
||||||
const r = v.embeddedValue;
|
return attenuate(v, ... t.value.attenuation);
|
||||||
return embed(attenuate(r, ... t.value.attenuation));
|
|
||||||
}
|
}
|
||||||
case 'TRef': {
|
case 'TRef': {
|
||||||
const n = t.value.binding;
|
const n = t.value.binding;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/// SPDX-License-Identifier: GPL-3.0-or-later
|
/// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||||
|
|
||||||
import { Set, Dictionary, KeyedDictionary, IdentitySet, stringify, Value } from '@preserves/core';
|
import { Set, Dictionary, KeyedDictionary, IdentitySet, stringify, Value, Embeddable } from '@preserves/core';
|
||||||
import { AnyValue, Assertion, Ref } from './actor.js';
|
import { AnyValue, Assertion, Ref } from './actor.js';
|
||||||
import { Bag, ChangeDescription } from './bag.js';
|
import { Bag, ChangeDescription } from './bag.js';
|
||||||
import * as Stack from './stack.js';
|
import * as Stack from './stack.js';
|
||||||
|
@ -142,13 +142,13 @@ export class Index<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dumpBag<T, V extends Value<T>>(b: Bag<T, V>, indent: string) {
|
function dumpBag<T extends Embeddable, V extends Value<T>>(b: Bag<T, V>, indent: string) {
|
||||||
for (const [v, count] of b.entries()) {
|
for (const [v, count] of b.entries()) {
|
||||||
console.log(indent + stringify(v) + ' = ' + count);
|
console.log(indent + stringify(v) + ' = ' + count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dumpSet<V>(s: Set<V>, indent: string) {
|
function dumpSet<V extends Embeddable>(s: Set<V>, indent: string) {
|
||||||
s.forEach(v => console.log(indent + stringify(v)));
|
s.forEach(v => console.log(indent + stringify(v)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||||
|
|
||||||
import { Actor, Assertion, Entity, Facet, Handle, Ref, Turn } from '../runtime/actor.js';
|
import { Actor, Assertion, Entity, Facet, Handle, Ref, Turn } from '../runtime/actor.js';
|
||||||
import { BytesLike, Decoder, Dictionary, embed, encode, IdentityMap, mapEmbeddeds, stringify, underlying, Value } from '@preserves/core';
|
import { BytesLike, Decoder, Dictionary, encode, IdentityMap, mapEmbeddeds, stringify, underlying, Value } from '@preserves/core';
|
||||||
import * as IO from '../gen/protocol.js';
|
import * as IO from '../gen/protocol.js';
|
||||||
import { wireRefEmbeddedType } from './protocol.js';
|
import { wireRefEmbeddedType } from './protocol.js';
|
||||||
import { attenuate } from '../runtime/rewrite.js';
|
import { attenuate } from '../runtime/rewrite.js';
|
||||||
|
@ -193,7 +193,7 @@ export class Relay {
|
||||||
register(targetRemoteOid: IO.Oid | null, assertion: Assertion, handle: Handle | null): Value<WireRef> {
|
register(targetRemoteOid: IO.Oid | null, assertion: Assertion, handle: Handle | null): Value<WireRef> {
|
||||||
const transient = (handle === null);
|
const transient = (handle === null);
|
||||||
const pins: Array<WireSymbol> = [];
|
const pins: Array<WireSymbol> = [];
|
||||||
const rewritten = mapEmbeddeds(assertion, r => embed(this.rewriteRefOut(r, transient, pins)));
|
const rewritten = mapEmbeddeds(assertion, r => this.rewriteRefOut(r, transient, pins));
|
||||||
if (handle !== null) {
|
if (handle !== null) {
|
||||||
if (targetRemoteOid !== null /* belt and suspenders */) {
|
if (targetRemoteOid !== null /* belt and suspenders */) {
|
||||||
this.grabImportedOid(targetRemoteOid, pins);
|
this.grabImportedOid(targetRemoteOid, pins);
|
||||||
|
@ -316,7 +316,7 @@ export class Relay {
|
||||||
rewriteIn(a: Value<WireRef>): [Assertion, Array<WireSymbol>]
|
rewriteIn(a: Value<WireRef>): [Assertion, Array<WireSymbol>]
|
||||||
{
|
{
|
||||||
const pins: Array<WireSymbol> = [];
|
const pins: Array<WireSymbol> = [];
|
||||||
const rewritten = mapEmbeddeds(a, r => embed(this.rewriteRefIn(r, pins)));
|
const rewritten = mapEmbeddeds(a, r => this.rewriteRefIn(r, pins));
|
||||||
return [rewritten, pins];
|
return [rewritten, pins];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/// SPDX-License-Identifier: GPL-3.0-or-later
|
/// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||||
|
|
||||||
import { randomId, Observe, FlexMap, embed, Embedded, Ref, Turn, AnyValue, Dataspace } from "@syndicate-lang/core";
|
import { randomId, Observe, FlexMap, Ref, Turn, AnyValue, Dataspace } from "@syndicate-lang/core";
|
||||||
import { QuasiValue as Q } from "@syndicate-lang/core";
|
import { QuasiValue as Q } from "@syndicate-lang/core";
|
||||||
|
|
||||||
import * as P from "./protocol";
|
import * as P from "./protocol";
|
||||||
|
@ -46,7 +46,7 @@ export function spawnGlobalEventFactory(ds: Ref) {
|
||||||
|
|
||||||
function handler(event: Event) {
|
function handler(event: Event) {
|
||||||
facet.turn(() => {
|
facet.turn(() => {
|
||||||
send message P.GlobalEvent(selector, eventType, embed(create ({ data: event })));
|
send message P.GlobalEvent(selector, eventType, create ({ data: event }));
|
||||||
});
|
});
|
||||||
return dealWithPreventDefault(eventType, event);
|
return dealWithPreventDefault(eventType, event);
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ export function spawnWindowEventFactory(ds: Ref) {
|
||||||
|
|
||||||
let handler = (event: Event) => {
|
let handler = (event: Event) => {
|
||||||
facet.turn(() => {
|
facet.turn(() => {
|
||||||
send message P.WindowEvent(eventType, embed(create ({ data: event })));
|
send message P.WindowEvent(eventType, create ({ data: event }));
|
||||||
});
|
});
|
||||||
return dealWithPreventDefault(eventType, event);
|
return dealWithPreventDefault(eventType, event);
|
||||||
};
|
};
|
||||||
|
@ -149,7 +149,7 @@ function spawnUIFragmentFactory(ds: Ref) {
|
||||||
removeNodes();
|
removeNodes();
|
||||||
|
|
||||||
selector = newSelector;
|
selector = newSelector;
|
||||||
html = (newHtml as Embedded<Ref>).embeddedValue.target.data as ChildNode[];
|
html = (newHtml as Ref).target.data as ChildNode[];
|
||||||
orderBy = newOrderBy;
|
orderBy = newOrderBy;
|
||||||
anchorNodes = (selector !== null) ? selectorMatch(document.body, selector) : [];
|
anchorNodes = (selector !== null) ? selectorMatch(document.body, selector) : [];
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ function spawnUIFragmentFactory(ds: Ref) {
|
||||||
const facet = Turn.activeFacet;
|
const facet = Turn.activeFacet;
|
||||||
function handler(event: Event) {
|
function handler(event: Event) {
|
||||||
facet.turn(() => {
|
facet.turn(() => {
|
||||||
send message P.UIEvent(fragmentId, selector, eventType, embed(create ({ data: event })));
|
send message P.UIEvent(fragmentId, selector, eventType, create ({ data: event }));
|
||||||
});
|
});
|
||||||
return dealWithPreventDefault(eventType, event);
|
return dealWithPreventDefault(eventType, event);
|
||||||
}
|
}
|
||||||
|
@ -507,7 +507,7 @@ export class Anchor {
|
||||||
if (!Array.isArray(html)) {
|
if (!Array.isArray(html)) {
|
||||||
html = html.nodes();
|
html = html.nodes();
|
||||||
}
|
}
|
||||||
return P.UIFragment(this.fragmentId, selector, embed(create ({ data: html })), orderBy);
|
return P.UIFragment(this.fragmentId, selector, create ({ data: html }), orderBy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import {
|
||||||
Assertion,
|
Assertion,
|
||||||
Bytes,
|
Bytes,
|
||||||
Dataspace,
|
Dataspace,
|
||||||
Embedded,
|
|
||||||
IdentitySet,
|
IdentitySet,
|
||||||
Observe,
|
Observe,
|
||||||
QuasiValue as Q,
|
QuasiValue as Q,
|
||||||
|
@ -23,6 +22,7 @@ import {
|
||||||
isEmbedded,
|
isEmbedded,
|
||||||
stringify,
|
stringify,
|
||||||
underlying,
|
underlying,
|
||||||
|
Embeddable,
|
||||||
} from "@syndicate-lang/core";
|
} from "@syndicate-lang/core";
|
||||||
import G = Schemas.gatekeeper;
|
import G = Schemas.gatekeeper;
|
||||||
import S = Schemas.sturdy;
|
import S = Schemas.sturdy;
|
||||||
|
@ -140,14 +140,10 @@ export function boot(ds = Dataspace.global, debug: boolean = false, WebSocketCon
|
||||||
console.log('tracking', addr.url);
|
console.log('tracking', addr.url);
|
||||||
during G.TransportConnection({
|
during G.TransportConnection({
|
||||||
"addr": addr,
|
"addr": addr,
|
||||||
"control": $control_e: Embedded,
|
"control": $control: Ref,
|
||||||
"resolved": G.Resolved.accepted($peer_e: Embedded),
|
"resolved": G.Resolved.accepted($peer: Ref),
|
||||||
}) => {
|
}) => {
|
||||||
const entry = {
|
const entry = { addr, control, peer };
|
||||||
addr,
|
|
||||||
control: control_e.embeddedValue,
|
|
||||||
peer: peer_e.embeddedValue,
|
|
||||||
};
|
|
||||||
candidates.value.add(entry);
|
candidates.value.add(entry);
|
||||||
candidates.changed();
|
candidates.changed();
|
||||||
on stop {
|
on stop {
|
||||||
|
@ -237,11 +233,10 @@ export function boot(ds = Dataspace.global, debug: boolean = false, WebSocketCon
|
||||||
}) }) => {
|
}) }) => {
|
||||||
const origin0 = Q.drop_lit(originPatValue);
|
const origin0 = Q.drop_lit(originPatValue);
|
||||||
if (!origin0 || !isEmbedded(origin0)) return;
|
if (!origin0 || !isEmbedded(origin0)) return;
|
||||||
const origin = origin0.embeddedValue;
|
const origin = origin0;
|
||||||
|
|
||||||
const detail0 = Q.drop_lit(detailPatValue, N.toNoisePathStepDetail);
|
const spec = Q.drop_lit(detailPatValue, N.toNoisePathStepDetail);
|
||||||
if (!detail0) return;
|
if (!spec) return;
|
||||||
const spec: N.NoiseSpec<Ref> = detail0;
|
|
||||||
|
|
||||||
const algorithms = SaltyCrypto.Noise_25519_ChaChaPoly_BLAKE2s;
|
const algorithms = SaltyCrypto.Noise_25519_ChaChaPoly_BLAKE2s;
|
||||||
const protocol =
|
const protocol =
|
||||||
|
@ -378,11 +373,10 @@ export function boot(ds = Dataspace.global, debug: boolean = false, WebSocketCon
|
||||||
}) }) => {
|
}) }) => {
|
||||||
const origin0 = Q.drop_lit(originPatValue);
|
const origin0 = Q.drop_lit(originPatValue);
|
||||||
if (!origin0 || !isEmbedded(origin0)) return;
|
if (!origin0 || !isEmbedded(origin0)) return;
|
||||||
const origin = origin0.embeddedValue;
|
const origin = origin0;
|
||||||
|
|
||||||
const detail0 = Q.drop_lit(detailPatValue, S.toSturdyPathStepDetail);
|
const parameters = Q.drop_lit(detailPatValue, S.toSturdyPathStepDetail);
|
||||||
if (!detail0) return;
|
if (!parameters) return;
|
||||||
const parameters: S.Parameters = detail0;
|
|
||||||
|
|
||||||
at origin {
|
at origin {
|
||||||
assert G.Resolve({
|
assert G.Resolve({
|
||||||
|
@ -411,7 +405,7 @@ export function boot(ds = Dataspace.global, debug: boolean = false, WebSocketCon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function unpackStandardRoute<R>(route: E.StandardRoute<R>): G.Route<R> {
|
export function unpackStandardRoute<R extends Embeddable>(route: E.StandardRoute<R>): G.Route<R> {
|
||||||
if (route._variant === 'general') return route.value;
|
if (route._variant === 'general') return route.value;
|
||||||
|
|
||||||
const { transports, key, service, sig, oid } = route;
|
const { transports, key, service, sig, oid } = route;
|
||||||
|
@ -465,15 +459,15 @@ export function contactRemote(
|
||||||
) => void,
|
) => void,
|
||||||
ds = Dataspace.global,
|
ds = Dataspace.global,
|
||||||
) {
|
) {
|
||||||
const routeValue = Record.isRecord(route) ? route : G.fromRoute(G.Route(route));
|
const routeValue = 'pathSteps' in route ? G.fromRoute(G.Route(route)) : route;
|
||||||
at ds {
|
at ds {
|
||||||
during G.ResolvePath({
|
during G.ResolvePath({
|
||||||
"route": routeValue,
|
"route": routeValue,
|
||||||
"addr": $addr,
|
"addr": $addr,
|
||||||
"control": $control_e: Embedded,
|
"control": $control: Ref,
|
||||||
"resolved": G.Resolved.accepted($resolved_e: Embedded),
|
"resolved": G.Resolved.accepted($resolved: Ref),
|
||||||
}) => {
|
}) => {
|
||||||
connectedFacet(resolved_e.embeddedValue, control_e.embeddedValue, addr);
|
connectedFacet(resolved, control, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue