@haneullabs/bcs 2.1.0 → 2.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/dist/bcs-type.d.mts +15 -50
- package/dist/bcs-type.d.mts.map +1 -1
- package/dist/bcs-type.mjs +48 -20
- package/dist/bcs-type.mjs.map +1 -1
- package/dist/bcs.d.mts +3 -4
- package/dist/bcs.d.mts.map +1 -1
- package/dist/bcs.mjs +46 -16
- package/dist/bcs.mjs.map +1 -1
- package/dist/reader.d.mts +1 -0
- package/dist/reader.d.mts.map +1 -1
- package/dist/reader.mjs +25 -10
- package/dist/reader.mjs.map +1 -1
- package/dist/types.d.mts +4 -5
- package/dist/types.d.mts.map +1 -1
- package/dist/uleb.d.mts.map +1 -1
- package/dist/uleb.mjs +4 -1
- package/dist/uleb.mjs.map +1 -1
- package/dist/utils.d.mts +0 -1
- package/dist/utils.d.mts.map +1 -1
- package/dist/writer.d.mts +3 -6
- package/dist/writer.d.mts.map +1 -1
- package/dist/writer.mjs +26 -19
- package/dist/writer.mjs.map +1 -1
- package/package.json +7 -7
- package/src/bcs-type.ts +68 -35
- package/src/bcs.ts +64 -25
- package/src/reader.ts +39 -16
- package/src/uleb.ts +4 -0
- package/src/writer.ts +30 -25
package/dist/writer.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writer.mjs","names":[],"sources":["../src/writer.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { Encoding } from './types.js';\nimport { ulebEncode } from './uleb.js';\nimport { encodeStr } from './utils.js';\n\nexport interface BcsWriterOptions {\n\t/** The initial size (in bytes) of the buffer tht will be allocated */\n\tinitialSize?: number;\n\t/** The maximum size (in bytes) that the buffer is allowed to grow to */\n\tmaxSize?: number;\n\t/** The amount of bytes that will be allocated whenever additional memory is required */\n\tallocateSize?: number;\n}\n\n/**\n * Class used to write BCS data into a buffer. Initializer requires\n * some size of a buffer to init; default value for this buffer is 1KB.\n *\n * Most methods are chainable, so it is possible to write them in one go.\n *\n * @example\n * let serialized = new BcsWriter()\n * .write8(10)\n * .write32(1000000)\n * .write64(10000001000000)\n * .hex();\n */\n\n/**\n * Set of methods that allows data encoding/decoding as standalone\n * BCS value or a part of a composed structure/vector.\n */\nexport class BcsWriter {\n\tprivate dataView: DataView<ArrayBuffer>;\n\tprivate bytePosition: number = 0;\n\tprivate size: number;\n\tprivate maxSize: number;\n\tprivate allocateSize: number;\n\n\tconstructor({\n\t\tinitialSize = 1024,\n\t\tmaxSize = Infinity,\n\t\tallocateSize = 1024,\n\t}: BcsWriterOptions = {}) {\n\t\tthis.size = initialSize;\n\t\tthis.maxSize = maxSize;\n\t\tthis.allocateSize = allocateSize;\n\t\tthis.dataView = new DataView(new ArrayBuffer(initialSize));\n\t}\n\n\tprivate ensureSizeOrGrow(bytes: number) {\n\t\tconst requiredSize = this.bytePosition + bytes;\n\t\tif (requiredSize > this.size) {\n\t\t\tconst nextSize = Math.min(\n\t\t\t\tthis.maxSize,\n\t\t\t\tMath.max(this.size + requiredSize, this.size + this.allocateSize),\n\t\t\t);\n\t\t\tif (requiredSize > nextSize) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Attempting to serialize to BCS, but buffer does not have enough size. Allocated size: ${this.size}, Max size: ${this.maxSize}, Required size: ${requiredSize}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.size = nextSize;\n\t\t\tconst nextBuffer = new ArrayBuffer(this.size);\n\t\t\
|
|
1
|
+
{"version":3,"file":"writer.mjs","names":[],"sources":["../src/writer.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { Encoding } from './types.js';\nimport { ulebEncode } from './uleb.js';\nimport { encodeStr } from './utils.js';\n\nexport interface BcsWriterOptions {\n\t/** The initial size (in bytes) of the buffer tht will be allocated */\n\tinitialSize?: number;\n\t/** The maximum size (in bytes) that the buffer is allowed to grow to */\n\tmaxSize?: number;\n\t/** The amount of bytes that will be allocated whenever additional memory is required */\n\tallocateSize?: number;\n}\n\n/**\n * Class used to write BCS data into a buffer. Initializer requires\n * some size of a buffer to init; default value for this buffer is 1KB.\n *\n * Most methods are chainable, so it is possible to write them in one go.\n *\n * @example\n * let serialized = new BcsWriter()\n * .write8(10)\n * .write32(1000000)\n * .write64(10000001000000)\n * .hex();\n */\n\n/**\n * Set of methods that allows data encoding/decoding as standalone\n * BCS value or a part of a composed structure/vector.\n */\nexport class BcsWriter {\n\tprivate dataView: DataView<ArrayBuffer>;\n\tprivate bytes: Uint8Array<ArrayBuffer>;\n\tprivate bytePosition: number = 0;\n\tprivate size: number;\n\tprivate maxSize: number;\n\tprivate allocateSize: number;\n\n\tconstructor({\n\t\tinitialSize = 1024,\n\t\tmaxSize = Infinity,\n\t\tallocateSize = 1024,\n\t}: BcsWriterOptions = {}) {\n\t\tthis.size = initialSize;\n\t\tthis.maxSize = maxSize;\n\t\tthis.allocateSize = allocateSize;\n\t\tthis.dataView = new DataView(new ArrayBuffer(initialSize));\n\t\tthis.bytes = new Uint8Array(this.dataView.buffer);\n\t}\n\n\tprivate ensureSizeOrGrow(bytes: number) {\n\t\tconst requiredSize = this.bytePosition + bytes;\n\t\tif (requiredSize > this.size) {\n\t\t\tconst nextSize = Math.min(\n\t\t\t\tthis.maxSize,\n\t\t\t\tMath.max(this.size + requiredSize, this.size + this.allocateSize),\n\t\t\t);\n\t\t\tif (requiredSize > nextSize) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Attempting to serialize to BCS, but buffer does not have enough size. Allocated size: ${this.size}, Max size: ${this.maxSize}, Required size: ${requiredSize}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.size = nextSize;\n\t\t\tconst nextBuffer = new ArrayBuffer(this.size);\n\t\t\tconst nextBytes = new Uint8Array(nextBuffer);\n\t\t\tnextBytes.set(this.bytes);\n\t\t\tthis.dataView = new DataView(nextBuffer);\n\t\t\tthis.bytes = nextBytes;\n\t\t}\n\t}\n\n\t/**\n\t * Shift current cursor position by `bytes`.\n\t *\n\t * @param {Number} bytes Number of bytes to\n\t * @returns {this} Self for possible chaining.\n\t */\n\tshift(bytes: number): this {\n\t\tthis.bytePosition += bytes;\n\t\treturn this;\n\t}\n\t/**\n\t * Write a U8 value into a buffer and shift cursor position by 1.\n\t * @param {Number} value Value to write.\n\t * @returns {this}\n\t */\n\twrite8(value: number | bigint): this {\n\t\tthis.ensureSizeOrGrow(1);\n\t\tthis.bytes[this.bytePosition] = Number(value);\n\t\treturn this.shift(1);\n\t}\n\n\t/**\n\t * Write a U8 value into a buffer and shift cursor position by 1.\n\t * @param {Number} value Value to write.\n\t * @returns {this}\n\t */\n\twriteBytes(bytes: Uint8Array): this {\n\t\tthis.ensureSizeOrGrow(bytes.length);\n\t\tthis.bytes.set(bytes, this.bytePosition);\n\n\t\treturn this.shift(bytes.length);\n\t}\n\t/**\n\t * Write a U16 value into a buffer and shift cursor position by 2.\n\t * @param {Number} value Value to write.\n\t * @returns {this}\n\t */\n\twrite16(value: number | bigint): this {\n\t\tthis.ensureSizeOrGrow(2);\n\t\tthis.dataView.setUint16(this.bytePosition, Number(value), true);\n\t\treturn this.shift(2);\n\t}\n\t/**\n\t * Write a U32 value into a buffer and shift cursor position by 4.\n\t * @param {Number} value Value to write.\n\t * @returns {this}\n\t */\n\twrite32(value: number | bigint): this {\n\t\tthis.ensureSizeOrGrow(4);\n\t\tthis.dataView.setUint32(this.bytePosition, Number(value), true);\n\t\treturn this.shift(4);\n\t}\n\t/**\n\t * Write a U64 value into a buffer and shift cursor position by 8.\n\t * @param {bigint} value Value to write.\n\t * @returns {this}\n\t */\n\twrite64(value: number | bigint): this {\n\t\treturn this.writeBigLittleEndian(BigInt(value), 8);\n\t}\n\t/**\n\t * Write a U128 value into a buffer and shift cursor position by 16.\n\t *\n\t * @param {bigint} value Value to write.\n\t * @returns {this}\n\t */\n\twrite128(value: number | bigint): this {\n\t\treturn this.writeBigLittleEndian(BigInt(value), 16);\n\t}\n\t/**\n\t * Write a U256 value into a buffer and shift cursor position by 16.\n\t *\n\t * @param {bigint} value Value to write.\n\t * @returns {this}\n\t */\n\twrite256(value: number | bigint): this {\n\t\treturn this.writeBigLittleEndian(BigInt(value), 32);\n\t}\n\n\t// Negative values encode as zero and values that overflow `size` keep their low bytes\n\tprivate writeBigLittleEndian(value: bigint, size: number): this {\n\t\tthis.ensureSizeOrGrow(size);\n\t\tlet remaining = value > 0n ? value : 0n;\n\t\tfor (let offset = 0; offset < size; offset += 8) {\n\t\t\tthis.dataView.setBigUint64(this.bytePosition + offset, BigInt.asUintN(64, remaining), true);\n\t\t\tremaining >>= 64n;\n\t\t}\n\n\t\treturn this.shift(size);\n\t}\n\t/**\n\t * Write a ULEB value into a buffer and shift cursor position by number of bytes\n\t * written.\n\t * @param {Number} value Value to write.\n\t * @returns {this}\n\t */\n\twriteULEB(value: number): this {\n\t\tif (value >= 0 && Number.isSafeInteger(value)) {\n\t\t\tlet remaining = value;\n\t\t\twhile (remaining >= 0x80) {\n\t\t\t\tthis.write8((remaining % 0x80) | 0x80);\n\t\t\t\tremaining = Math.floor(remaining / 0x80);\n\t\t\t}\n\t\t\treturn this.write8(remaining);\n\t\t}\n\n\t\tulebEncode(value).forEach((el) => this.write8(el));\n\t\treturn this;\n\t}\n\t/**\n\t * Write a vector into a buffer by first writing the vector length and then calling\n\t * a callback on each passed value.\n\t *\n\t * @param {Array<Any>} vector Array of elements to write.\n\t * @param {WriteVecCb} cb Callback to call on each element of the vector.\n\t * @returns {this}\n\t */\n\twriteVec(vector: any[], cb: (writer: BcsWriter, el: any, i: number, len: number) => void): this {\n\t\tthis.writeULEB(vector.length);\n\t\tArray.from(vector).forEach((el, i) => cb(this, el, i, vector.length));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds support for iterations over the object.\n\t * @returns {Uint8Array}\n\t */\n\t// oxlint-disable-next-line require-yields\n\t*[Symbol.iterator](): Iterator<number, Iterable<number>> {\n\t\tfor (let i = 0; i < this.bytePosition; i++) {\n\t\t\tyield this.dataView.getUint8(i);\n\t\t}\n\t\treturn this.toBytes();\n\t}\n\n\t/**\n\t * Get underlying buffer taking only value bytes (in case initial buffer size was bigger).\n\t * @returns {Uint8Array} Resulting bcs.\n\t */\n\ttoBytes(): Uint8Array<ArrayBuffer> {\n\t\treturn new Uint8Array(this.dataView.buffer.slice(0, this.bytePosition));\n\t}\n\n\t/**\n\t * Represent data as 'hex' or 'base64'\n\t * @param encoding Encoding to use: 'base64' or 'hex'\n\t */\n\ttoString(encoding: Encoding): string {\n\t\treturn encodeStr(this.toBytes(), encoding);\n\t}\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haneullabs/bcs",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "BCS - Canonical Binary Serialization implementation for JavaScript",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Haneul Labs <build@haneul-labs.com>",
|
|
@@ -44,14 +44,14 @@
|
|
|
44
44
|
],
|
|
45
45
|
"homepage": "https://sdk.haneul-labs.com/bcs",
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@size-limit/preset-small-lib": "^
|
|
48
|
-
"size-limit": "^
|
|
49
|
-
"typescript": "^
|
|
50
|
-
"vitest": "^4.1.
|
|
47
|
+
"@size-limit/preset-small-lib": "^13.0.3",
|
|
48
|
+
"size-limit": "^13.0.3",
|
|
49
|
+
"typescript": "^7.0.2",
|
|
50
|
+
"vitest": "^4.1.11"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@scure/base": "^2.
|
|
54
|
-
"@haneullabs/utils": "^0.4.
|
|
53
|
+
"@scure/base": "^2.3.0",
|
|
54
|
+
"@haneullabs/utils": "^0.4.2"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"clean": "rm -rf tsconfig.tsbuildinfo ./dist",
|
package/src/bcs-type.ts
CHANGED
|
@@ -22,6 +22,12 @@ export class BcsType<T, Input = T, const Name extends string = string> {
|
|
|
22
22
|
validate: (value: Input) => void;
|
|
23
23
|
#write: (value: Input, writer: BcsWriter) => void;
|
|
24
24
|
#serialize: (value: Input, options?: BcsWriterOptions) => Uint8Array<ArrayBuffer>;
|
|
25
|
+
// Set by transform: validates and writes while converting the input only once. Only used
|
|
26
|
+
// while validate is still the one transform created, so a reassigned validate is honoured.
|
|
27
|
+
#validatedWrite: ((value: Input, writer: BcsWriter) => void) | null = null;
|
|
28
|
+
#validatedSerialize:
|
|
29
|
+
((value: Input, options?: BcsWriterOptions) => Uint8Array<ArrayBuffer>) | null = null;
|
|
30
|
+
#transformValidate: ((value: Input) => void) | null = null;
|
|
25
31
|
|
|
26
32
|
constructor(
|
|
27
33
|
options: {
|
|
@@ -52,11 +58,18 @@ export class BcsType<T, Input = T, const Name extends string = string> {
|
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
write(value: Input, writer: BcsWriter) {
|
|
61
|
+
if (this.#validatedWrite && this.validate === this.#transformValidate) {
|
|
62
|
+
this.#validatedWrite(value, writer);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
55
65
|
this.validate(value);
|
|
56
66
|
this.#write(value, writer);
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
serialize(value: Input, options?: BcsWriterOptions) {
|
|
70
|
+
if (this.#validatedSerialize && this.validate === this.#transformValidate) {
|
|
71
|
+
return new SerializedBcs(this, this.#validatedSerialize(value, options));
|
|
72
|
+
}
|
|
60
73
|
this.validate(value);
|
|
61
74
|
return new SerializedBcs(this, this.#serialize(value, options));
|
|
62
75
|
}
|
|
@@ -87,7 +100,7 @@ export class BcsType<T, Input = T, const Name extends string = string> {
|
|
|
87
100
|
input?: (val: Input2) => Input;
|
|
88
101
|
output?: (value: T) => T2;
|
|
89
102
|
} & BcsTypeOptions<T2, Input2, NewName>) {
|
|
90
|
-
|
|
103
|
+
const type = new BcsType<T2, Input2, NewName>({
|
|
91
104
|
name: (name ?? this.name) as NewName,
|
|
92
105
|
read: (reader) => (output ? output(this.read(reader)) : (this.read(reader) as never)),
|
|
93
106
|
write: (value, writer) => this.#write(input ? input(value) : (value as never), writer),
|
|
@@ -99,6 +112,23 @@ export class BcsType<T, Input = T, const Name extends string = string> {
|
|
|
99
112
|
this.validate(input ? input(value) : (value as never));
|
|
100
113
|
},
|
|
101
114
|
});
|
|
115
|
+
|
|
116
|
+
// Equivalent to validate() followed by the write above, but calls input() once instead of twice
|
|
117
|
+
type.#transformValidate = type.validate;
|
|
118
|
+
type.#validatedWrite = (value, writer) => {
|
|
119
|
+
validate?.(value);
|
|
120
|
+
const converted = input ? input(value) : (value as never);
|
|
121
|
+
this.validate(converted);
|
|
122
|
+
this.#write(converted, writer);
|
|
123
|
+
};
|
|
124
|
+
type.#validatedSerialize = (value, options) => {
|
|
125
|
+
validate?.(value);
|
|
126
|
+
const converted = input ? input(value) : (value as never);
|
|
127
|
+
this.validate(converted);
|
|
128
|
+
return this.#serialize(converted, options);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
return type;
|
|
102
132
|
}
|
|
103
133
|
}
|
|
104
134
|
|
|
@@ -253,9 +283,7 @@ export function stringLikeBcsType<const Name extends string = string>({
|
|
|
253
283
|
write: (hex, writer) => {
|
|
254
284
|
const bytes = toBytes(hex);
|
|
255
285
|
writer.writeULEB(bytes.length);
|
|
256
|
-
|
|
257
|
-
writer.write8(bytes[i]);
|
|
258
|
-
}
|
|
286
|
+
writer.writeBytes(bytes);
|
|
259
287
|
},
|
|
260
288
|
serialize: (value) => {
|
|
261
289
|
const bytes = toBytes(value);
|
|
@@ -325,14 +353,16 @@ export class BcsStruct<
|
|
|
325
353
|
Name
|
|
326
354
|
> {
|
|
327
355
|
constructor({ name, fields, ...options }: BcsStructOptions<T, Name>) {
|
|
328
|
-
const
|
|
356
|
+
const fieldNames = Object.keys(fields);
|
|
357
|
+
const fieldTypes = fieldNames.map((field) => fields[field]);
|
|
358
|
+
const fieldCount = fieldNames.length;
|
|
329
359
|
|
|
330
360
|
super({
|
|
331
361
|
name,
|
|
332
362
|
serializedSize: (values) => {
|
|
333
363
|
let total = 0;
|
|
334
|
-
for (
|
|
335
|
-
const size =
|
|
364
|
+
for (let i = 0; i < fieldCount; i++) {
|
|
365
|
+
const size = fieldTypes[i].serializedSize(values[fieldNames[i]]);
|
|
336
366
|
if (size == null) {
|
|
337
367
|
return null;
|
|
338
368
|
}
|
|
@@ -344,15 +374,15 @@ export class BcsStruct<
|
|
|
344
374
|
},
|
|
345
375
|
read: (reader) => {
|
|
346
376
|
const result: Record<string, unknown> = {};
|
|
347
|
-
for (
|
|
348
|
-
result[
|
|
377
|
+
for (let i = 0; i < fieldCount; i++) {
|
|
378
|
+
result[fieldNames[i]] = fieldTypes[i].read(reader);
|
|
349
379
|
}
|
|
350
380
|
|
|
351
381
|
return result as never;
|
|
352
382
|
},
|
|
353
383
|
write: (value, writer) => {
|
|
354
|
-
for (
|
|
355
|
-
|
|
384
|
+
for (let i = 0; i < fieldCount; i++) {
|
|
385
|
+
fieldTypes[i].write(value[fieldNames[i]], writer);
|
|
356
386
|
}
|
|
357
387
|
},
|
|
358
388
|
...options,
|
|
@@ -399,6 +429,7 @@ export class BcsEnum<
|
|
|
399
429
|
> {
|
|
400
430
|
constructor({ fields, ...options }: BcsEnumOptions<T, Name>) {
|
|
401
431
|
const canonicalOrder = Object.entries(fields as object);
|
|
432
|
+
const variantIndex = new Map(canonicalOrder.map(([name], i) => [name, i]));
|
|
402
433
|
super({
|
|
403
434
|
read: (reader) => {
|
|
404
435
|
const index = reader.readULEB();
|
|
@@ -410,21 +441,26 @@ export class BcsEnum<
|
|
|
410
441
|
|
|
411
442
|
const [kind, type] = enumEntry;
|
|
412
443
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
444
|
+
const value = type?.read(reader) ?? true;
|
|
445
|
+
// Assigning to __proto__ would set the prototype rather than add a property
|
|
446
|
+
if (kind === '__proto__') {
|
|
447
|
+
return { [kind]: value, $kind: kind } as never;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Avoid a computed-key object literal, which V8 builds through a slow runtime path
|
|
451
|
+
const result: Record<string, unknown> = {};
|
|
452
|
+
result[kind] = value;
|
|
453
|
+
result.$kind = kind;
|
|
454
|
+
|
|
455
|
+
return result as never;
|
|
417
456
|
},
|
|
418
457
|
write: (value, writer) => {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
if (optionName === name) {
|
|
426
|
-
writer.writeULEB(i);
|
|
427
|
-
optionType?.write(val, writer);
|
|
458
|
+
// The first own key that names a variant selects it
|
|
459
|
+
for (const name of Object.keys(value)) {
|
|
460
|
+
const index = variantIndex.get(name);
|
|
461
|
+
if (index !== undefined) {
|
|
462
|
+
writer.writeULEB(index);
|
|
463
|
+
canonicalOrder[index][1]?.write(value[name], writer);
|
|
428
464
|
return;
|
|
429
465
|
}
|
|
430
466
|
}
|
|
@@ -436,21 +472,18 @@ export class BcsEnum<
|
|
|
436
472
|
throw new TypeError(`Expected object, found ${typeof value}`);
|
|
437
473
|
}
|
|
438
474
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
475
|
+
let variantCount = 0;
|
|
476
|
+
for (const key of Object.keys(value)) {
|
|
477
|
+
if (value[key] !== undefined && variantIndex.has(key)) {
|
|
478
|
+
variantCount++;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
442
481
|
|
|
443
|
-
if (
|
|
482
|
+
if (variantCount !== 1) {
|
|
444
483
|
throw new TypeError(
|
|
445
|
-
`Expected object with one key, but found ${
|
|
484
|
+
`Expected object with one key, but found ${variantCount} for type ${options.name}}`,
|
|
446
485
|
);
|
|
447
486
|
}
|
|
448
|
-
|
|
449
|
-
const [variant] = keys;
|
|
450
|
-
|
|
451
|
-
if (!Object.hasOwn(fields, variant)) {
|
|
452
|
-
throw new TypeError(`Invalid enum variant ${variant}`);
|
|
453
|
-
}
|
|
454
487
|
},
|
|
455
488
|
});
|
|
456
489
|
}
|
package/src/bcs.ts
CHANGED
|
@@ -82,27 +82,34 @@ function option<T, Input, Name extends string = string>(
|
|
|
82
82
|
function option<T extends BcsType<any>>(
|
|
83
83
|
type: T,
|
|
84
84
|
): BcsType<InferBcsType<T> | null, InferBcsInput<T> | null | undefined, `Option<${T['name']}>`> {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
},
|
|
98
|
-
output: (value) => {
|
|
99
|
-
if (value.$kind === 'Some') {
|
|
100
|
-
return value.Some as InferBcsType<T>;
|
|
101
|
-
}
|
|
102
|
-
|
|
85
|
+
// Encoded like enum Option { None, Some(T) }, but read and written directly rather than
|
|
86
|
+
// through an intermediate { None } / { Some } enum object
|
|
87
|
+
const name = `Option<${type.name}>` as const;
|
|
88
|
+
return new BcsType<
|
|
89
|
+
InferBcsType<T> | null,
|
|
90
|
+
InferBcsInput<T> | null | undefined,
|
|
91
|
+
`Option<${T['name']}>`
|
|
92
|
+
>({
|
|
93
|
+
name,
|
|
94
|
+
read: (reader) => {
|
|
95
|
+
const index = reader.readULEB();
|
|
96
|
+
if (index === 0) {
|
|
103
97
|
return null;
|
|
104
|
-
}
|
|
105
|
-
|
|
98
|
+
}
|
|
99
|
+
if (index === 1) {
|
|
100
|
+
return type.read(reader);
|
|
101
|
+
}
|
|
102
|
+
throw new TypeError(`Unknown value ${index} for enum ${name}`);
|
|
103
|
+
},
|
|
104
|
+
write: (value, writer) => {
|
|
105
|
+
if (value == null) {
|
|
106
|
+
writer.write8(0);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
writer.write8(1);
|
|
110
|
+
type.write(value, writer);
|
|
111
|
+
},
|
|
112
|
+
});
|
|
106
113
|
}
|
|
107
114
|
|
|
108
115
|
function vector<T extends BcsType<any>, Name extends string = `vector<${T['name']}>`>(
|
|
@@ -211,6 +218,32 @@ function map<K extends BcsType<any>, V extends BcsType<any>>(
|
|
|
211
218
|
});
|
|
212
219
|
}
|
|
213
220
|
|
|
221
|
+
// Created on first use, so importing the package doesn't require TextEncoder/TextDecoder
|
|
222
|
+
let utf8Encoder: TextEncoder | undefined;
|
|
223
|
+
let utf8Decoder: TextDecoder | undefined;
|
|
224
|
+
function decoder() {
|
|
225
|
+
return (utf8Decoder ??= new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Most strings in Haneul data (module, function and type names) are short ASCII. Decoding those
|
|
229
|
+
// directly avoids the fixed cost of a TextDecoder call; anything else goes through the decoder.
|
|
230
|
+
const ASCII_FAST_PATH_MAX_LENGTH = 64;
|
|
231
|
+
function decodeUtf8(bytes: Uint8Array): string {
|
|
232
|
+
if (bytes.length <= ASCII_FAST_PATH_MAX_LENGTH) {
|
|
233
|
+
let result = '';
|
|
234
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
235
|
+
const byte = bytes[i];
|
|
236
|
+
if (byte >= 0x80) {
|
|
237
|
+
return decoder().decode(bytes);
|
|
238
|
+
}
|
|
239
|
+
result += String.fromCharCode(byte);
|
|
240
|
+
}
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return decoder().decode(bytes);
|
|
245
|
+
}
|
|
246
|
+
|
|
214
247
|
export const bcs = {
|
|
215
248
|
/**
|
|
216
249
|
* Creates a BcsType that can be used to read and write an 8-bit unsigned integer.
|
|
@@ -316,7 +349,13 @@ export const bcs = {
|
|
|
316
349
|
bool(options?: BcsTypeOptions<boolean>) {
|
|
317
350
|
return fixedSizeBcsType({
|
|
318
351
|
size: 1,
|
|
319
|
-
read: (reader) =>
|
|
352
|
+
read: (reader) => {
|
|
353
|
+
const value = reader.read8();
|
|
354
|
+
if (value > 1) {
|
|
355
|
+
throw new TypeError(`Invalid bool value: expected 0 or 1, found ${value}`);
|
|
356
|
+
}
|
|
357
|
+
return value === 1;
|
|
358
|
+
},
|
|
320
359
|
write: (value, writer) => writer.write8(value ? 1 : 0),
|
|
321
360
|
...options,
|
|
322
361
|
name: (options?.name ?? 'bool') as 'bool',
|
|
@@ -356,7 +395,7 @@ export const bcs = {
|
|
|
356
395
|
size,
|
|
357
396
|
read: (reader) => reader.readBytes(size),
|
|
358
397
|
write: (value, writer) => {
|
|
359
|
-
writer.writeBytes(new Uint8Array(value));
|
|
398
|
+
writer.writeBytes(value instanceof Uint8Array ? value : new Uint8Array(value));
|
|
360
399
|
},
|
|
361
400
|
...options,
|
|
362
401
|
name: (options?.name ?? `bytes[${size}]`) as `bytes[${T}]`,
|
|
@@ -386,7 +425,7 @@ export const bcs = {
|
|
|
386
425
|
return reader.readBytes(length);
|
|
387
426
|
},
|
|
388
427
|
write: (value, writer) => {
|
|
389
|
-
const array = new Uint8Array(value);
|
|
428
|
+
const array = value instanceof Uint8Array ? value : new Uint8Array(value);
|
|
390
429
|
writer.writeULEB(array.length);
|
|
391
430
|
writer.writeBytes(array);
|
|
392
431
|
},
|
|
@@ -412,8 +451,8 @@ export const bcs = {
|
|
|
412
451
|
*/
|
|
413
452
|
string(options?: BcsTypeOptions<string>) {
|
|
414
453
|
return stringLikeBcsType({
|
|
415
|
-
toBytes: (value) => new TextEncoder().encode(value),
|
|
416
|
-
fromBytes:
|
|
454
|
+
toBytes: (value) => (utf8Encoder ??= new TextEncoder()).encode(value),
|
|
455
|
+
fromBytes: decodeUtf8,
|
|
417
456
|
...options,
|
|
418
457
|
name: (options?.name ?? 'string') as 'string',
|
|
419
458
|
});
|
package/src/reader.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// Copyright (c) Mysten Labs, Inc.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
import { ulebDecode } from './uleb.js';
|
|
5
|
-
|
|
6
4
|
/**
|
|
7
5
|
* Class used for reading BCS data chunk by chunk. Meant to be used
|
|
8
6
|
* by some wrapper, which will make sure that data is valid and is
|
|
@@ -35,6 +33,7 @@ import { ulebDecode } from './uleb.js';
|
|
|
35
33
|
*/
|
|
36
34
|
export class BcsReader {
|
|
37
35
|
private dataView: DataView;
|
|
36
|
+
private bytes: Uint8Array;
|
|
38
37
|
private bytePosition: number = 0;
|
|
39
38
|
|
|
40
39
|
/**
|
|
@@ -42,6 +41,7 @@ export class BcsReader {
|
|
|
42
41
|
*/
|
|
43
42
|
constructor(data: Uint8Array) {
|
|
44
43
|
this.dataView = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
44
|
+
this.bytes = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
47
|
* Shift current cursor position by `bytes`.
|
|
@@ -58,9 +58,12 @@ export class BcsReader {
|
|
|
58
58
|
* @returns
|
|
59
59
|
*/
|
|
60
60
|
read8(): number {
|
|
61
|
-
const
|
|
62
|
-
this.
|
|
63
|
-
|
|
61
|
+
const position = this.bytePosition;
|
|
62
|
+
if (position >= this.bytes.length) {
|
|
63
|
+
throw new RangeError('Offset is outside the bounds of the DataView');
|
|
64
|
+
}
|
|
65
|
+
this.bytePosition = position + 1;
|
|
66
|
+
return this.bytes[position];
|
|
64
67
|
}
|
|
65
68
|
/**
|
|
66
69
|
* Read U16 value from the buffer and shift cursor by 2.
|
|
@@ -85,12 +88,9 @@ export class BcsReader {
|
|
|
85
88
|
* @returns
|
|
86
89
|
*/
|
|
87
90
|
read64(): string {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const result = value2.toString(16) + value1.toString(16).padStart(8, '0');
|
|
92
|
-
|
|
93
|
-
return BigInt('0x' + result).toString(10);
|
|
91
|
+
const value = this.dataView.getBigUint64(this.bytePosition, true);
|
|
92
|
+
this.shift(8);
|
|
93
|
+
return value.toString(10);
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
96
|
* Read U128 value from the buffer and shift cursor by 16.
|
|
@@ -118,6 +118,10 @@ export class BcsReader {
|
|
|
118
118
|
* @param num Number of bytes to read.
|
|
119
119
|
*/
|
|
120
120
|
readBytes(num: number): Uint8Array {
|
|
121
|
+
// The underlying buffer may extend past this view, so check against the view's own length
|
|
122
|
+
if (this.bytePosition + num > this.bytes.length) {
|
|
123
|
+
throw new RangeError('Offset is outside the bounds of the DataView');
|
|
124
|
+
}
|
|
121
125
|
const start = this.bytePosition + this.dataView.byteOffset;
|
|
122
126
|
const value = new Uint8Array(this.dataView.buffer, start, num);
|
|
123
127
|
|
|
@@ -131,12 +135,31 @@ export class BcsReader {
|
|
|
131
135
|
* @returns {Number} The ULEB value.
|
|
132
136
|
*/
|
|
133
137
|
readULEB(): number {
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
const bytes = this.bytes;
|
|
139
|
+
let position = this.bytePosition;
|
|
140
|
+
let value = 0;
|
|
141
|
+
let multiplier = 1;
|
|
142
|
+
while (true) {
|
|
143
|
+
if (position >= bytes.length) {
|
|
144
|
+
throw new Error('ULEB decode error: buffer overflow');
|
|
145
|
+
}
|
|
146
|
+
const byte = bytes[position++];
|
|
147
|
+
value += (byte & 0x7f) * multiplier;
|
|
148
|
+
if ((byte & 0x80) === 0) {
|
|
149
|
+
// A trailing zero group adds no value, so the encoding is not minimal
|
|
150
|
+
if (byte === 0 && position - this.bytePosition > 1) {
|
|
151
|
+
throw new Error('ULEB decode error: non-canonical encoding');
|
|
152
|
+
}
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
multiplier *= 128;
|
|
156
|
+
}
|
|
139
157
|
|
|
158
|
+
// Also rejects NaN, from very long encodings where multiplier overflows to Infinity
|
|
159
|
+
if (!(value <= Number.MAX_SAFE_INTEGER)) {
|
|
160
|
+
throw new Error('ULEB decode error: value exceeds MAX_SAFE_INTEGER');
|
|
161
|
+
}
|
|
162
|
+
this.bytePosition = position;
|
|
140
163
|
return value;
|
|
141
164
|
}
|
|
142
165
|
/**
|
package/src/uleb.ts
CHANGED
|
@@ -43,6 +43,10 @@ export function ulebDecode(arr: number[] | Uint8Array): {
|
|
|
43
43
|
len += 1;
|
|
44
44
|
total += BigInt(byte & 0x7f) << shift;
|
|
45
45
|
if ((byte & 0x80) === 0) {
|
|
46
|
+
// A trailing zero group adds no value, so the encoding is not minimal
|
|
47
|
+
if (byte === 0 && len > 1) {
|
|
48
|
+
throw new Error('ULEB decode error: non-canonical encoding');
|
|
49
|
+
}
|
|
46
50
|
break;
|
|
47
51
|
}
|
|
48
52
|
shift += 7n;
|
package/src/writer.ts
CHANGED
|
@@ -34,6 +34,7 @@ export interface BcsWriterOptions {
|
|
|
34
34
|
*/
|
|
35
35
|
export class BcsWriter {
|
|
36
36
|
private dataView: DataView<ArrayBuffer>;
|
|
37
|
+
private bytes: Uint8Array<ArrayBuffer>;
|
|
37
38
|
private bytePosition: number = 0;
|
|
38
39
|
private size: number;
|
|
39
40
|
private maxSize: number;
|
|
@@ -48,6 +49,7 @@ export class BcsWriter {
|
|
|
48
49
|
this.maxSize = maxSize;
|
|
49
50
|
this.allocateSize = allocateSize;
|
|
50
51
|
this.dataView = new DataView(new ArrayBuffer(initialSize));
|
|
52
|
+
this.bytes = new Uint8Array(this.dataView.buffer);
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
private ensureSizeOrGrow(bytes: number) {
|
|
@@ -65,8 +67,10 @@ export class BcsWriter {
|
|
|
65
67
|
|
|
66
68
|
this.size = nextSize;
|
|
67
69
|
const nextBuffer = new ArrayBuffer(this.size);
|
|
68
|
-
new Uint8Array(nextBuffer)
|
|
70
|
+
const nextBytes = new Uint8Array(nextBuffer);
|
|
71
|
+
nextBytes.set(this.bytes);
|
|
69
72
|
this.dataView = new DataView(nextBuffer);
|
|
73
|
+
this.bytes = nextBytes;
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
|
|
@@ -87,7 +91,7 @@ export class BcsWriter {
|
|
|
87
91
|
*/
|
|
88
92
|
write8(value: number | bigint): this {
|
|
89
93
|
this.ensureSizeOrGrow(1);
|
|
90
|
-
this.
|
|
94
|
+
this.bytes[this.bytePosition] = Number(value);
|
|
91
95
|
return this.shift(1);
|
|
92
96
|
}
|
|
93
97
|
|
|
@@ -98,10 +102,7 @@ export class BcsWriter {
|
|
|
98
102
|
*/
|
|
99
103
|
writeBytes(bytes: Uint8Array): this {
|
|
100
104
|
this.ensureSizeOrGrow(bytes.length);
|
|
101
|
-
|
|
102
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
103
|
-
this.dataView.setUint8(this.bytePosition + i, bytes[i]);
|
|
104
|
-
}
|
|
105
|
+
this.bytes.set(bytes, this.bytePosition);
|
|
105
106
|
|
|
106
107
|
return this.shift(bytes.length);
|
|
107
108
|
}
|
|
@@ -131,9 +132,7 @@ export class BcsWriter {
|
|
|
131
132
|
* @returns {this}
|
|
132
133
|
*/
|
|
133
134
|
write64(value: number | bigint): this {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
return this;
|
|
135
|
+
return this.writeBigLittleEndian(BigInt(value), 8);
|
|
137
136
|
}
|
|
138
137
|
/**
|
|
139
138
|
* Write a U128 value into a buffer and shift cursor position by 16.
|
|
@@ -142,9 +141,7 @@ export class BcsWriter {
|
|
|
142
141
|
* @returns {this}
|
|
143
142
|
*/
|
|
144
143
|
write128(value: number | bigint): this {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return this;
|
|
144
|
+
return this.writeBigLittleEndian(BigInt(value), 16);
|
|
148
145
|
}
|
|
149
146
|
/**
|
|
150
147
|
* Write a U256 value into a buffer and shift cursor position by 16.
|
|
@@ -153,9 +150,19 @@ export class BcsWriter {
|
|
|
153
150
|
* @returns {this}
|
|
154
151
|
*/
|
|
155
152
|
write256(value: number | bigint): this {
|
|
156
|
-
|
|
153
|
+
return this.writeBigLittleEndian(BigInt(value), 32);
|
|
154
|
+
}
|
|
157
155
|
|
|
158
|
-
|
|
156
|
+
// Negative values encode as zero and values that overflow `size` keep their low bytes
|
|
157
|
+
private writeBigLittleEndian(value: bigint, size: number): this {
|
|
158
|
+
this.ensureSizeOrGrow(size);
|
|
159
|
+
let remaining = value > 0n ? value : 0n;
|
|
160
|
+
for (let offset = 0; offset < size; offset += 8) {
|
|
161
|
+
this.dataView.setBigUint64(this.bytePosition + offset, BigInt.asUintN(64, remaining), true);
|
|
162
|
+
remaining >>= 64n;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return this.shift(size);
|
|
159
166
|
}
|
|
160
167
|
/**
|
|
161
168
|
* Write a ULEB value into a buffer and shift cursor position by number of bytes
|
|
@@ -164,6 +171,15 @@ export class BcsWriter {
|
|
|
164
171
|
* @returns {this}
|
|
165
172
|
*/
|
|
166
173
|
writeULEB(value: number): this {
|
|
174
|
+
if (value >= 0 && Number.isSafeInteger(value)) {
|
|
175
|
+
let remaining = value;
|
|
176
|
+
while (remaining >= 0x80) {
|
|
177
|
+
this.write8((remaining % 0x80) | 0x80);
|
|
178
|
+
remaining = Math.floor(remaining / 0x80);
|
|
179
|
+
}
|
|
180
|
+
return this.write8(remaining);
|
|
181
|
+
}
|
|
182
|
+
|
|
167
183
|
ulebEncode(value).forEach((el) => this.write8(el));
|
|
168
184
|
return this;
|
|
169
185
|
}
|
|
@@ -209,14 +225,3 @@ export class BcsWriter {
|
|
|
209
225
|
return encodeStr(this.toBytes(), encoding);
|
|
210
226
|
}
|
|
211
227
|
}
|
|
212
|
-
|
|
213
|
-
function toLittleEndian(bigint: bigint, size: number) {
|
|
214
|
-
const result = new Uint8Array(size);
|
|
215
|
-
let i = 0;
|
|
216
|
-
while (bigint > 0) {
|
|
217
|
-
result[i] = Number(bigint % BigInt(256));
|
|
218
|
-
bigint = bigint / BigInt(256);
|
|
219
|
-
i += 1;
|
|
220
|
-
}
|
|
221
|
-
return result;
|
|
222
|
-
}
|