-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(exo): Extend InterfaceGuard to support symbol-keyed methods #1740
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First quick reaction: Awesome choice to use a CopyMap rather than an array of pairs! In thinking about this issue, that "natural" choice never occurred to me.
(Good you're also fixing CopyMap patterns, just in time for the first production use of CopyMaps!)
Since it arrives late, after an earlier representation shipped, and optional is coherent. I think it should remain optional. But if it does happen to be present with an empty map, that should be fine too. I don't see any reason to insist on a canonical representation for this case. (I think you're already doing that, in which case, no change suggested.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks! For the sake of agoric-sdk, it's great that we can get this into the next endo release.
@@ -10,13 +10,19 @@ When an exo is defined with an InterfaceGuard, the exo is augmented by default w | |||
|
|||
```js | |||
// `GET_INTERFACE_GUARD` holds the name of the meta-method | |||
import { GET_INTERFACE_GUARD } from `@endo/exo`; | |||
import { GET_INTERFACE_GUARD } from '@endo/exo'; | |||
import { getCopyMapKeys } from '@endo/patterns'; | |||
|
|||
... | |||
const interfaceGuard = await E(exo)[GET_INTERFACE_GUARD](); | |||
// `methodNames` omits names of automatically added meta-methods like | |||
// the value of `GET_INTERFACE_GUARD`. | |||
// Others may also be omitted if `interfaceGuard.partial` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Attn @michaelfig
My mistake! In anything that saw the light of day, it was never called interfaceGuard.partial
. It became interfaceGuard.sloppy
, but I forgot to rename this occurrence.
But @michaelfig is in process with a PR that will make changes in this area, so leave that to him. For your PR, no change suggested.
packages/exo/README.md
Outdated
const methodNames = Reflect.ownKeys(interfaceGuard.methodGuards) | ||
.concat( | ||
interfaceGuard.symbolMethodGuards | ||
? getCopyMapKeys(interfaceGuard.symbolMethodGuards) | ||
: [] | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the following style a bit better, but up to you.
const methodNames = Reflect.ownKeys(interfaceGuard.methodGuards) | |
.concat( | |
interfaceGuard.symbolMethodGuards | |
? getCopyMapKeys(interfaceGuard.symbolMethodGuards) | |
: [] | |
); | |
const methodNames = [ | |
...Reflect.ownKeys(interfaceGuard.methodGuards), | |
...interfaceGuard.symbolMethodGuards | |
? getCopyMapKeys(interfaceGuard.symbolMethodGuards) | |
: [], | |
]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
methodGuards = harden({ | ||
...mg, | ||
...(symbolMethodGuards && | ||
fromEntries(getCopyMapEntries(symbolMethodGuards))), | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
Given this, my preference to use [...x, ...y] above is stronger. Now I will request that change ;)
t.is(UpCounterI.symbolMethodGuards, undefined); | ||
|
||
const symbolic = Symbol.for('symbolic'); | ||
const FooI = M.interface('Foo', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also add a test with an exo implementing FooI and then call the symbol-named method to test that the raw method is guarded by the methodGuard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
klass: 'Interface', | ||
interfaceName: M.string(), | ||
methodGuards: M.recordOf(M.string(), MethodGuardShape), | ||
sloppy: M.boolean(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just be aware that as of @michaelfig 's upcoming PR, sloppy
will move into that optional section, and another will appear there as well. No change suggested.
packages/patterns/src/types.js
Outdated
* methodGuards: { [K in keyof T]: K extends symbol ? never : T[K] }, | ||
* symbolMethodGuards?: CopyMap<symbol, MethodGuard>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got it to type the CopyMap K as a symbol-keyed entry of T, but don't know how to establish the pair relationship. It will be open for followup.
...(symbolMethodGuardsEntries.length | ||
? { symbolMethodGuards: makeCopyMap(symbolMethodGuardsEntries) } | ||
: {}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That ... (x ? {y} : {})
is quite cute. No change suggested.
3a2223f
to
72101f9
Compare
Fixes #1728
Description
Extend InterfaceGuard with a
symbolMethodGuards
field whose value is a CopyMap<symbol, MethodGuard> when the interface has symbol-keyed methods such as Symbol.asyncIterator. The current implementation expresses it as completely optional and does not create it when there are no symbol-keyed methods, but we could also set it to an empty CopyMap in that case.Security Considerations
None AFAICT.
Scaling Considerations
None AFAICT, even if we always add the CopyMap.
Documentation Considerations
None.
Testing Considerations
Just unit tests.
Upgrade Considerations
None special; the new functionality should be fully backwards compatible.