Skip to content

Commit

Permalink
Proxy support added to resolveWithPresence in HandledPromise (#1881)
Browse files Browse the repository at this point in the history
feat(eventual-send): add proxy support to HandledPromise resolveWithPresence.

per [this comment](tc39/proposal-eventual-send#8 (comment)) with changes requested by @erights 

Co-authored-by: Mark S. Miller <erights@users.noreply.github.com>
  • Loading branch information
zarutian and erights authored May 29, 2021
1 parent c55ee46 commit fbe665b
Show file tree
Hide file tree
Showing 4 changed files with 673 additions and 3 deletions.
10 changes: 9 additions & 1 deletion packages/eventual-send/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,17 @@ interface EHandler<T> {
type HandledExecutor<R> = (
resolveHandled: (value?: R) => void,
rejectHandled: (reason?: unknown) => void,
resolveWithPresence: (presenceHandler: EHandler<{}>) => object,
resolveWithPresence: (presenceHandler: EHandler<{}>, options?: ResolveWithPresenceOptionsBag<{}>) => object,
) => void;

type ResolveWithPresenceOptionsBag<T> = {
proxy?: {
handler: ProxyHandler<T>,
target: unknown,
revokerCallback?: (revoker: () => void) => void,
},
};

declare interface HandledPromiseConstructor extends PromiseConstructor {
new <R>(
executor: HandledExecutor<R>,
Expand Down
28 changes: 26 additions & 2 deletions packages/eventual-send/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export function makeHandledPromise() {
handledReject(reason);
};

const resolveWithPresence = presenceHandler => {
const resolveWithPresence = (presenceHandler, options = {}) => {
if (resolved) {
return resolvedTarget;
}
Expand All @@ -233,8 +233,32 @@ export function makeHandledPromise() {
// Sanity checks.
validateHandler(presenceHandler);

const { proxy: proxyOpts } = options;
let presence;
if (proxyOpts) {
const {
handler: proxyHandler,
target: proxyTarget,
revokerCallback,
} = proxyOpts;
if (revokerCallback) {
// Create a proxy and its revoke function.
const { proxy, revoke } = Proxy.revocable(
proxyTarget,
proxyHandler,
);
presence = proxy;
revokerCallback(revoke);
} else {
presence = new Proxy(proxyTarget, proxyHandler);
}
} else {
// Default presence.
presence = Object.create(null);
}

// Validate and install our mapped target (i.e. presence).
resolvedTarget = Object.create(null);
resolvedTarget = presence;

// Create table entries for the presence mapped to the
// fulfilledHandler.
Expand Down
70 changes: 70 additions & 0 deletions packages/eventual-send/test/test-hp.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,73 @@ test('no local stalls', async t => {
'log is golden',
);
});

test('simple resolveWithPresence', async t => {
const log = [];
const presenceHandler = {
applyMethod(target, verb, args) {
log.push(['applyMethod', target, verb, args]);
return undefined;
},
};
let presence;
const pr = new HandledPromise((_res, _rej, rWp) => {
presence = rWp(presenceHandler);
return presence;
});
HandledPromise.applyMethod(pr, 'aðferð', [1]);
await Promise.resolve();
t.deepEqual(log, [['applyMethod', presence, 'aðferð', [1]]], 'log a-ok');
});

test('resolveWithPresence pipelining', async t => {
const logA = [];
const unresolvedHandler = {
applyMethod(target, verb, args) {
logA.push(['applyMethod', target, verb, args]);
return undefined;
},
};
const logB = [];
const presenceHandler = {
applyMethod(target, verb, args) {
logB.push(['applyMethod', target, verb, args]);
return undefined;
},
};
const p0 = {};
p0.promise = new HandledPromise((resolve, reject, resolveWithPresence) => {
p0.resolve = resolve;
p0.reject = reject;
p0.resolveWithPresence = resolveWithPresence;
}, unresolvedHandler);
HandledPromise.applyMethod(p0.promise, 'óðaÖnn', [1]);
await Promise.resolve();
const p1 = p0.resolveWithPresence(presenceHandler);
HandledPromise.applyMethod(p0.promise, 'aðferð', [2]);
await Promise.resolve();
// t.log('logA:', logA);
// t.log('logB:', logB);
// t.log('p1:', p1);
t.deepEqual(logA, [['applyMethod', p0.promise, 'óðaÖnn', [1]]], 'logA ok');
t.deepEqual(logB, [['applyMethod', p1, 'aðferð', [2]]], 'logB ok');
// t.fail('stöðva hér');
});

test('resolveWithPresence return value is resolution', async t => {
const presenceHandler = {
applyMethod(target, verb, args) {
const muffler = [];
muffler.push(target);
muffler.push(verb);
muffler.push(args);
return undefined;
},
};
let presence;
const vow = new HandledPromise((_resolve, _reject, resolveWithPresence) => {
presence = resolveWithPresence(presenceHandler);
});
const p = await vow;
t.is(presence, p);
});
Loading

0 comments on commit fbe665b

Please sign in to comment.