-
Notifications
You must be signed in to change notification settings - Fork 110
Notes on number representation for serialization and deserialization
Here's a table that maps the msgpack specification to the different data types in Javascript.
MessagePack Value | JavaScript Value |
---|---|
positive fixint | number |
fixmap | object |
fixarray | array |
fixstr | string |
nil | null |
false | false |
true | true |
bin 8 | not supported |
bin 16 | not supported |
bin 32 | not supported |
float 32 | number |
float 64 | number |
uint 8 | number |
uint 16 | number |
uint 32 | number |
uint 64 | number/bigint |
int 8 | number |
int 16 | number |
int 32 | number |
int 64 | number/bigint |
str 8 | string |
str 16 | string |
str 32 | string |
map 16 | object |
map 32 | object |
negative fixint | number |
Javascript originally didn't support i64/u64 values. In order to support these values, BigInt was added to the specification and is nowadays supported by most JavaScript engines. However BigInt can't naturally interact with other number types, all mathematical operations must be done at the BigInt level. To solve this the developer needs to make sure to check the type of the variable that they belive could be a BigInt, this doesn't apply to all numerical values and will vary on case by case.
For a more complete example, the following script would fail, if the proper checks are not done before comparing a BigInt with a regular JavaScript number:
var Shopify;
Shopify = {
// Let's assume that productId was serialized as BigInt
main: (productId) => {
if (productId === 42)) { // will throw since the equality operation must be applied to two BigInts or Numbers
return "ok";
}
throw new Error("i is not BigInt(42)");
}
}
In order to make the previous script succeed, we need to check the type of productId
and convert it to the corresponding type before doing any operations with it.
var Shopify;
Shopify = {
// Let's assume that productId was serialized as BigInt
main: (productId) => {
var ty = typeof productId;
switch (ty) {
case 'number':
// ...
case 'bigint':
// ...
}
}
}
- Rust's MessagePack crate serializes i64 that are larger than an i32 as a u64.
- Rust's MessagePack crate serializes to i64 only when values are < i32::MIN.
- Rust's MessagePack crate always tries to serialize to the smallest format. See previous section...
- QuickJS optimizes values between
i32::MIN
toi32::MAX
by storing them as Int32 instead of Float64 - During deserialization, BigInts are not clamped to MIN/MAX, they instead return an error when they overflow/underflow.