Skip to content

Commit 305b697

Browse files
committed
wip
1 parent 3b5f1e2 commit 305b697

File tree

3 files changed

+88
-93
lines changed

3 files changed

+88
-93
lines changed

packages/core/src/submodules/cbor/ByteVector.ts

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,85 @@
1+
import { CborMajorType } from "./cbor";
2+
13
export class ByteVector {
2-
public data: Uint8Array = new Uint8Array(100_000);
3-
public cursor: number = 0;
4+
private data: Uint8Array = new Uint8Array();
5+
private dataView: DataView = new DataView(this.data.buffer, 0, 0);
6+
private cursor: number = 0;
7+
8+
public constructor(private initialSize: number = 1_000_000) {
9+
this.resize(initialSize);
10+
}
411

5-
public write(byte: number) {
6-
if (this.data.length - this.cursor < 1) {
7-
this.resize(this.data.length + 1_000_000);
12+
public write(...bytes: number[]) {
13+
for (const byte of bytes) {
14+
if (this.cursor === this.data.length) {
15+
this.resize(this.cursor + this.initialSize);
16+
}
17+
this.data[this.cursor++] = byte;
818
}
9-
this.data[this.cursor++] = byte;
1019
}
1120

1221
public writeSeries(bytes: Uint8Array) {
13-
while ((this.data.length - this.cursor) * 1.1 < bytes.length) {
14-
this.resize(this.data.length + 1_000_000);
22+
if (this.cursor + bytes.length >= this.data.length) {
23+
this.resize(this.cursor + bytes.length + this.initialSize);
1524
}
1625
this.data.set(bytes, this.cursor);
17-
this.cursor += bytes.length;
26+
this.cursor += bytes.byteLength;
27+
}
28+
29+
public writeUnsignedInt(major: CborMajorType, bitSize: 16 | 32 | 64, value: number | bigint) {
30+
if (this.cursor + bitSize / 8 >= this.data.length) {
31+
this.resize(this.cursor + bitSize / 8 + this.initialSize);
32+
}
33+
const dv = byteVector.getDataView();
34+
switch (bitSize) {
35+
case 16:
36+
this.write((major << 5) | 25);
37+
dv.setUint16(byteVector.getCursor(), Number(value) as number);
38+
this.cursor += 2;
39+
break;
40+
case 32:
41+
this.write((major << 5) | 26);
42+
dv.setUint32(byteVector.getCursor(), Number(value) as number);
43+
this.cursor += 4;
44+
break;
45+
case 64:
46+
this.write((major << 5) | 27);
47+
dv.setBigUint64(byteVector.getCursor(), BigInt(value) as bigint);
48+
this.cursor += 8;
49+
break;
50+
}
1851
}
1952

20-
public resize(size: number) {
21-
const old = this.data.subarray(0, this.cursor);
22-
this.data = new Uint8Array(size);
23-
this.data.set(old, 0);
53+
public toUint8Array(): Uint8Array {
54+
const out = new Uint8Array(this.cursor);
55+
out.set(this.data.slice(0, this.cursor), 0);
56+
this.data = new Uint8Array(this.initialSize);
57+
this.cursor = 0;
58+
this.dataView = new DataView(this.data.buffer, 0, this.initialSize);
59+
return out;
60+
}
61+
62+
public getDataView() {
63+
return this.dataView;
64+
}
65+
66+
public getCursor() {
67+
return this.cursor;
68+
}
69+
70+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
71+
private resize(size: number) {
72+
const data = this.data;
73+
this.data = typeof Buffer !== "undefined" ? new Uint8Array(size) : new Uint8Array(size);
74+
if (data) {
75+
this.data.set(data, 0);
76+
}
77+
this.dataView = new DataView(this.data.buffer, 0, size);
2478
}
2579
}
2680

81+
export const byteVector = new ByteVector();
82+
2783
export function join(byteArrays: Uint8Array[]): Uint8Array {
2884
let length = 0;
2985
for (const arr of byteArrays) {

packages/core/src/submodules/cbor/cbor.spec.ts

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as fs from "fs";
22
import JSONbig from "json-bigint";
33
import * as path from "path";
44

5-
import { cbor, setUnsignedInt } from "./cbor";
5+
import { cbor } from "./cbor";
66

77
// syntax is ESM but the test target is CJS.
88
const here = __dirname;
@@ -14,34 +14,6 @@ const successTests = JSONbig({ useNativeBigInt: true, alwaysParseAsBig: false })
1414
fs.readFileSync(path.join(here, "test-data", "success-tests.json"))
1515
);
1616

17-
describe("setUnsignedInt", () => {
18-
for (const [value, bitSize] of [
19-
[1, 16],
20-
[258, 16],
21-
[256256, 16],
22-
[5, 32],
23-
[258, 32],
24-
[125432, 32],
25-
[5, 64],
26-
[258, 64],
27-
[BigInt(42462464262), 64],
28-
] as [number | bigint, number][]) {
29-
it(`should functionally match DataView int${bitSize} value of ${value}`, () => {
30-
expect(setUnsignedInt(bitSize as 16 | 32 | 64, value, new Uint8Array(8))).toEqual(
31-
(() => {
32-
const u = new Uint8Array(8);
33-
if (bitSize < 64) {
34-
new DataView(u.buffer, u.buffer.byteLength - u.length)["setUint" + bitSize](0, value);
35-
} else {
36-
new DataView(u.buffer, u.buffer.byteLength - u.length).setBigUint64(0, BigInt(value));
37-
}
38-
return u;
39-
})()
40-
);
41-
});
42-
}
43-
});
44-
4517
describe("cbor", () => {
4618
const examples = [
4719
{

packages/core/src/submodules/cbor/cbor.ts

Lines changed: 18 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { fromUtf8, toUtf8 } from "@smithy/util-utf8";
22

3-
import { ByteVector, join } from "./ByteVector";
3+
import { byteVector, join } from "./ByteVector";
44

55
/**
66
* This cbor serde implementation is derived from AWS SDK for Go's implementation.
@@ -44,7 +44,7 @@ type Int64 = bigint;
4444
type Float16Binary = number;
4545
type Float32Binary = number;
4646

47-
type CborMajorType =
47+
export type CborMajorType =
4848
| typeof majorUint64
4949
| typeof majorNegativeInt64
5050
| typeof majorUnstructuredByteString
@@ -94,25 +94,6 @@ function demote(bigInteger: bigint): number {
9494
return num;
9595
}
9696

97-
/**
98-
* @internal
99-
* Write unsigned int into uint8 array.
100-
*/
101-
export function setUnsignedInt(bitSize: 16 | 32 | 64, value: number | bigint, byteArray: Uint8Array): Uint8Array {
102-
switch (bitSize) {
103-
case 16:
104-
offsetDataView(byteArray).setUint16(0, Number(value) as number);
105-
break;
106-
case 32:
107-
offsetDataView(byteArray).setUint32(0, Number(value) as number);
108-
break;
109-
case 64:
110-
offsetDataView(byteArray).setBigUint64(0, BigInt(value) as bigint);
111-
break;
112-
}
113-
return byteArray;
114-
}
115-
11697
// decode
11798

11899
function float16ToUint32(float: Float16Binary): Uint32 {
@@ -480,7 +461,7 @@ function decode(payload: Uint8Array, bigIntBehavior: BigIntBehavior): [CborValue
480461

481462
// encode
482463

483-
function encodeHeader(major: CborMajorType, value: Uint64 | number, byteVector: ByteVector): void {
464+
function encodeHeader(major: CborMajorType, value: Uint64 | number): void {
484465
if (value < 24) {
485466
byteVector.write((major << 5) | (value as number));
486467
return;
@@ -489,22 +470,13 @@ function encodeHeader(major: CborMajorType, value: Uint64 | number, byteVector:
489470
byteVector.write(value as number);
490471
return;
491472
} else if (value < TWO.SIXTEEN) {
492-
const float16Container = new Uint8Array(3);
493-
float16Container[0] = (major << 5) | specialFloat16;
494-
setUnsignedInt(16, value, float16Container.subarray(1));
495-
byteVector.writeSeries(float16Container);
473+
byteVector.writeUnsignedInt(major, 16, value);
496474
return;
497475
} else if (value < TWO.THIRTY_TWO) {
498-
const float32Container = new Uint8Array(5);
499-
float32Container[0] = (major << 5) | specialFloat32;
500-
setUnsignedInt(32, value, float32Container.subarray(1));
501-
byteVector.writeSeries(float32Container);
476+
byteVector.writeUnsignedInt(major, 32, value);
502477
return;
503478
}
504-
const float64Container = new Uint8Array(9);
505-
float64Container[0] = (major << 5) | specialFloat64;
506-
setUnsignedInt(64, value, float64Container.subarray(1));
507-
byteVector.writeSeries(float64Container);
479+
byteVector.writeUnsignedInt(major, 64, value);
508480
return;
509481
}
510482

@@ -516,7 +488,7 @@ function compose(major: CborMajorType, minor: Uint8): Uint8 {
516488
* @param input - JS data object.
517489
* @param byteVector - mutated, not returned.
518490
*/
519-
function encode(input: any, byteVector: ByteVector): void {
491+
function encode(input: any): void {
520492
if (input === null) {
521493
byteVector.write(compose(majorSpecial, specialNull));
522494
return;
@@ -534,9 +506,7 @@ function encode(input: any, byteVector: ByteVector): void {
534506
return;
535507
case "number":
536508
if (Number.isInteger(input)) {
537-
input >= 0
538-
? encodeHeader(majorUint64, input, byteVector)
539-
: encodeHeader(majorNegativeInt64, Math.abs(input) - 1, byteVector);
509+
input >= 0 ? encodeHeader(majorUint64, input) : encodeHeader(majorNegativeInt64, Math.abs(input) - 1);
540510
return;
541511
}
542512
const float64Container = new Uint8Array(9);
@@ -545,33 +515,31 @@ function encode(input: any, byteVector: ByteVector): void {
545515
byteVector.writeSeries(float64Container);
546516
return;
547517
case "bigint":
548-
input >= 0
549-
? encodeHeader(majorUint64, input, byteVector)
550-
: encodeHeader(majorNegativeInt64, -input - BigInt(1), byteVector);
518+
input >= 0 ? encodeHeader(majorUint64, input) : encodeHeader(majorNegativeInt64, -input - BigInt(1));
551519
return;
552520
case "string":
553-
encodeHeader(majorUtf8String, input.length, byteVector);
521+
encodeHeader(majorUtf8String, input.length);
554522
byteVector.writeSeries(fromUtf8(input));
555523
return;
556524
}
557525

558526
if (Array.isArray(input)) {
559527
const _input = input.filter(notUndef);
560-
encodeHeader(majorList, _input.length, byteVector);
528+
encodeHeader(majorList, _input.length);
561529
for (const vv of _input) {
562-
encode(vv, byteVector);
530+
encode(vv);
563531
}
564532
return;
565533
} else if (typeof input.byteLength === "number") {
566-
encodeHeader(majorUnstructuredByteString, input.length, byteVector);
534+
encodeHeader(majorUnstructuredByteString, input.length);
567535
byteVector.writeSeries(input);
568536
return;
569537
} else if (typeof input === "object") {
570538
const entries = Object.entries(input).filter(valueNotUndef);
571-
encodeHeader(majorMap, entries.length, byteVector);
539+
encodeHeader(majorMap, entries.length);
572540
for (const [key, value] of entries) {
573-
encode(key, byteVector);
574-
encode(value, byteVector);
541+
encode(key);
542+
encode(value);
575543
}
576544
return;
577545
}
@@ -595,8 +563,7 @@ export const cbor = {
595563
return decode(payload, bigIntBehavior)[0];
596564
},
597565
serialize(input: any) {
598-
const byteVector = new ByteVector();
599-
encode(input, byteVector);
600-
return byteVector.data.subarray(0, byteVector.cursor);
566+
encode(input);
567+
return byteVector.toUint8Array();
601568
},
602569
};

0 commit comments

Comments
 (0)