@agoric/marshal
Advanced tools
Comparing version 0.1.2 to 0.1.3
/* global module */ | ||
module.exports = { | ||
extends: ['airbnb', 'plugin:prettier/recommended'], | ||
extends: ['airbnb-base', 'plugin:prettier/recommended'], | ||
env: { | ||
@@ -5,0 +5,0 @@ es6: true, // supports new ES6 globals (e.g., new types such as Set) |
@@ -159,5 +159,16 @@ import harden from '@agoric/harden'; | ||
// This is the equality comparison used by JavaScript's Map and Set | ||
// abstractions, where NaN is the same as NaN and -0 is the same as | ||
// 0. Marshal serializes -0 as zero, so the semantics of our distributed | ||
// object system does not distinguish 0 from -0. | ||
// | ||
// `sameValueZero` is the EcmaScript spec name for this equality comparison, | ||
// but TODO we need a better name for the API. | ||
export function sameValueZero(x, y) { | ||
return x === y || Object.is(x, y); | ||
} | ||
// How would val be passed? For primitive values, the answer is | ||
// * 'null' for null | ||
// * throwing an error for an unregistered symbol | ||
// * throwing an error for a symbol, whether registered or not. | ||
// * that value's typeof string for all other primitive values | ||
@@ -186,3 +197,3 @@ // For frozen objects, the possible answers | ||
throw new Error( | ||
`cannot pass non-frozen objects like ${val}. [Use harden()]`, | ||
`Cannot pass non-frozen objects like ${val}. Use harden()`, | ||
); | ||
@@ -209,3 +220,3 @@ } | ||
case 'function': { | ||
throw new Error(`bare functions like ${val} are disabled for now`); | ||
throw new Error(`Bare functions like ${val} are disabled for now`); | ||
} | ||
@@ -220,9 +231,6 @@ case 'undefined': | ||
case 'symbol': { | ||
if (Symbol.keyFor(val) === undefined) { | ||
throw new TypeError('Cannot pass unregistered symbols'); | ||
} | ||
return typestr; | ||
throw new TypeError('Cannot pass symbols'); | ||
} | ||
default: { | ||
throw new TypeError(`unrecognized typeof ${typestr}`); | ||
throw new TypeError(`Unrecognized typeof ${typestr}`); | ||
} | ||
@@ -303,3 +311,26 @@ } | ||
export function makeMarshal(serializeSlot, unserializeSlot) { | ||
const identityFn = x => x; | ||
export function makeMarshal( | ||
convertValToSlot = identityFn, | ||
convertSlotToVal = identityFn, | ||
) { | ||
function serializeSlot(val, slots, slotMap) { | ||
let slotIndex; | ||
if (slotMap.has(val)) { | ||
slotIndex = slotMap.get(val); | ||
} else { | ||
const slot = convertValToSlot(val); | ||
slotIndex = slots.length; | ||
slots.push(slot); | ||
slotMap.set(val, slotIndex); | ||
} | ||
return harden({ | ||
[QCLASS]: 'slot', | ||
index: slotIndex, | ||
}); | ||
} | ||
function makeReplacer(slots, slotMap) { | ||
@@ -328,3 +359,3 @@ const ibidTable = makeReplacerIbidTable(); | ||
if (Object.is(val, -0)) { | ||
return harden({ [QCLASS]: '-0' }); | ||
return 0; | ||
} | ||
@@ -339,9 +370,2 @@ if (val === Infinity) { | ||
} | ||
case 'symbol': { | ||
const key = Symbol.keyFor(val); | ||
return harden({ | ||
[QCLASS]: 'symbol', | ||
key, | ||
}); | ||
} | ||
case 'bigint': { | ||
@@ -465,5 +489,2 @@ return harden({ | ||
} | ||
case '-0': { | ||
return -0; | ||
} | ||
case 'NaN': { | ||
@@ -478,10 +499,2 @@ return NaN; | ||
} | ||
case 'symbol': { | ||
if (typeof rawTree.key !== 'string') { | ||
throw new TypeError( | ||
`invalid symbol key typeof ${typeof rawTree.key}`, | ||
); | ||
} | ||
return Symbol.for(rawTree.key); | ||
} | ||
case 'bigint': { | ||
@@ -517,3 +530,4 @@ if (typeof rawTree.digits !== 'string') { | ||
case 'slot': { | ||
return ibidTable.register(unserializeSlot(rawTree, slots)); | ||
const slot = slots[Nat(rawTree.index)]; | ||
return ibidTable.register(convertSlotToVal(slot)); | ||
} | ||
@@ -520,0 +534,0 @@ |
{ | ||
"name": "@agoric/marshal", | ||
"version": "0.1.2", | ||
"version": "0.1.3", | ||
"description": "marshal", | ||
@@ -12,6 +12,6 @@ "main": "marshal.js", | ||
"test": "tape -r esm 'test/**/test*.js' | tap-spec", | ||
"pretty-fix": "prettier --write '**/*.{js,jsx}'", | ||
"pretty-check": "prettier --check '**/*.{js,jsx}'", | ||
"lint-fix": "eslint --fix '**/*.{js,jsx}'", | ||
"lint-check": "eslint '**/*.{js,jsx}'" | ||
"pretty-fix": "prettier --write '**/*.js'", | ||
"pretty-check": "prettier --check '**/*.js'", | ||
"lint-fix": "eslint --fix '**/*.js'", | ||
"lint-check": "eslint '**/*.js'" | ||
}, | ||
@@ -32,5 +32,5 @@ "repository": { | ||
"dependencies": { | ||
"@agoric/eventual-send": "^0.6.0", | ||
"@agoric/harden": "0.0.4", | ||
"@agoric/nat": "^2.0.1", | ||
"@agoric/eventual-send": "^0.5.0" | ||
"@agoric/nat": "^2.0.1" | ||
}, | ||
@@ -42,3 +42,4 @@ "devDependencies": { | ||
"tape-promise": "^4.0.0" | ||
} | ||
}, | ||
"gitHead": "c954aea51be34003243e40837e7e579a03a034cc" | ||
} |
@@ -23,6 +23,6 @@ # @agoric/marshal | ||
This module exports a `makeMarshal()` function, which must be called with two | ||
callbacks (`serializeSlot` and `unserializeSlot`), and returns an object with | ||
`serialize` and `unserialize` properties. For ordinary (non-capability) | ||
serialization, you can omit the callbacks: | ||
This module exports a `makeMarshal()` function, which can be called with two | ||
optional callbacks (`convertValToSlot` and `convertSlotToVal`), and returns | ||
an object with `serialize` and `unserialize` properties. If the callback | ||
arguments are omitted, they default to the identity function. | ||
@@ -96,5 +96,5 @@ ```js | ||
Pass-by-presence objects usually have identity (assuming the | ||
serializeSlot/unserializeSlot callbacks behave well), so passing the same | ||
object through multiple calls will result in multiple references to the same | ||
output object. | ||
`convertValToSlot` and `convertSlotToVal` callbacks behave well), so passing | ||
the same object through multiple calls will result in multiple references to | ||
the same output object. | ||
@@ -115,14 +115,12 @@ To qualify as pass-by-copy, the enumerable string-named properties of the | ||
## serializeSlot / unserializeSlot | ||
## `convertValToSlot` / `convertSlotToVal` | ||
When `m.serialize()` encounters a pass-by-presence object, it will invoke the | ||
`serializeSlot` callback. This will be given the value to be serialized, a | ||
mutable array of slot identifiers, and a mutable Map from values to slot | ||
indices. If the value has not been seen before, the callback should allocate | ||
a new slot identifier, append it to the array, and add the new index into the | ||
Map. If it *has* been seen before, it should re-use the old index, and just | ||
update the Map. In both cases, it should return the "marker", a | ||
JSON-serializable data structure that tells the unserializer how to handle | ||
the slot. This should be something like `{ "@qclass": "slot", "index": NNN | ||
}`, where the `index` points into the array of slot identifiers. | ||
When `m.serialize()` encounters a pass-by-presence object, it will call the | ||
`convertValToSlot` callback with the value to be serialized. Its return value | ||
will be used at the slot identifier to be placed into the slots array. In the | ||
serialized body, this will be represented by the record | ||
```js | ||
{ "@qclass": "slot", "index": index } | ||
``` | ||
where `index` is the index in the slots array of that slot. | ||
@@ -132,4 +130,5 @@ The array of slot identifiers is returned as the `slots` portion of the | ||
`m.unserialize()` invokes the `unserializeSlot` callback each time it | ||
encounters a `@qclass: "slot"` in the serialized body. This should create and | ||
return a proxy (or other representative) of the pass-by-presence object. | ||
Each time `m.unserialize()` encounters such a record, it calls | ||
`convertSlotToVal` with that slot from the slots array. `convertSlotToVal` | ||
should create and return a proxy (or other representative) of the | ||
pass-by-presence object. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
38458
11
553
131
1
+ Added@agoric/eventual-send@0.6.0(transitive)
- Removed@agoric/eventual-send@0.5.1(transitive)
Updated@agoric/eventual-send@^0.6.0