diff --git a/common/config/rush/command-line.json b/common/config/rush/command-line.json
index 48fd39c4..c803cd7e 100644
--- a/common/config/rush/command-line.json
+++ b/common/config/rush/command-line.json
@@ -191,7 +191,7 @@
"ignoreMissingScript": true,
"allowWarningsInSuccessfulBuild": true,
"enableParallelism": true,
- "incremental": true,
+ // "incremental": true,
"safeForSimultaneousRushProcesses": true
},
{
diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml
index 59b6ff9b..9dc3fd31 100644
--- a/common/config/rush/pnpm-lock.yaml
+++ b/common/config/rush/pnpm-lock.yaml
@@ -62,15 +62,15 @@ importers:
'@yume-chan/event':
specifier: workspace:^0.0.23
version: link:../event
+ '@yume-chan/no-data-view':
+ specifier: workspace:^0.0.23
+ version: link:../no-data-view
'@yume-chan/stream-extra':
specifier: workspace:^0.0.23
version: link:../stream-extra
'@yume-chan/struct':
specifier: workspace:^0.0.23
version: link:../struct
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
devDependencies:
'@jest/globals':
specifier: ^30.0.0-alpha.3
@@ -105,9 +105,6 @@ importers:
'@yume-chan/adb':
specifier: workspace:^0.0.23
version: link:../adb
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
devDependencies:
'@yume-chan/eslint-config':
specifier: workspace:^1.0.0
@@ -136,9 +133,6 @@ importers:
'@yume-chan/struct':
specifier: workspace:^0.0.23
version: link:../struct
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
devDependencies:
'@yume-chan/eslint-config':
specifier: workspace:^1.0.0
@@ -173,9 +167,6 @@ importers:
'@yume-chan/struct':
specifier: workspace:^0.0.23
version: link:../struct
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
devDependencies:
'@jest/globals':
specifier: ^30.0.0-alpha.3
@@ -213,9 +204,6 @@ importers:
'@yume-chan/struct':
specifier: workspace:^0.0.23
version: link:../struct
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
devDependencies:
'@types/node':
specifier: ^20.12.7
@@ -247,9 +235,6 @@ importers:
'@yume-chan/struct':
specifier: workspace:^0.0.23
version: link:../struct
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
devDependencies:
'@jest/globals':
specifier: ^30.0.0-alpha.3
@@ -281,9 +266,6 @@ importers:
'@types/w3c-web-usb':
specifier: ^1.0.10
version: 1.0.10
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
devDependencies:
'@yume-chan/eslint-config':
specifier: workspace:^1.0.0
@@ -296,10 +278,6 @@ importers:
version: 5.4.5
../../libraries/dataview-bigint-polyfill:
- dependencies:
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
devDependencies:
'@yume-chan/eslint-config':
specifier: workspace:^1.0.0
@@ -322,9 +300,6 @@ importers:
'@yume-chan/async':
specifier: ^2.2.0
version: 2.2.0
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
devDependencies:
'@jest/globals':
specifier: ^30.0.0-alpha.3
@@ -361,11 +336,40 @@ importers:
specifier: ^20.12.7
version: 20.12.7
+ ../../libraries/no-data-view:
+ devDependencies:
+ '@jest/globals':
+ specifier: ^30.0.0-alpha.3
+ version: 30.0.0-alpha.3
+ '@types/node':
+ specifier: ^20.12.7
+ version: 20.12.7
+ '@yume-chan/eslint-config':
+ specifier: workspace:^1.0.0
+ version: link:../../toolchain/eslint-config
+ '@yume-chan/tsconfig':
+ specifier: workspace:^1.0.0
+ version: link:../../toolchain/tsconfig
+ cross-env:
+ specifier: ^7.0.3
+ version: 7.0.3
+ jest:
+ specifier: ^30.0.0-alpha.3
+ version: 30.0.0-alpha.3(@types/node@20.12.7)
+ prettier:
+ specifier: ^3.2.5
+ version: 3.2.5
+ tinybench:
+ specifier: ^2.7.0
+ version: 2.7.0
+ ts-jest:
+ specifier: ^29.1.2
+ version: 29.1.2(jest@30.0.0-alpha.3)(typescript@5.4.5)
+ typescript:
+ specifier: ^5.4.5
+ version: 5.4.5
+
../../libraries/pcm-player:
- dependencies:
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
devDependencies:
'@jest/globals':
specifier: ^30.0.0-alpha.3
@@ -397,6 +401,9 @@ importers:
../../libraries/scrcpy:
dependencies:
+ '@yume-chan/no-data-view':
+ specifier: workspace:^0.0.23
+ version: link:../no-data-view
'@yume-chan/stream-extra':
specifier: workspace:^0.0.23
version: link:../stream-extra
@@ -449,9 +456,6 @@ importers:
tinyh264:
specifier: ^0.0.7
version: 0.0.7
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
yuv-buffer:
specifier: ^1.0.0
version: 1.0.0
@@ -489,6 +493,9 @@ importers:
'@yume-chan/event':
specifier: workspace:^0.0.23
version: link:../event
+ '@yume-chan/no-data-view':
+ specifier: workspace:^0.0.23
+ version: link:../no-data-view
'@yume-chan/scrcpy':
specifier: workspace:^0.0.23
version: link:../scrcpy
@@ -498,9 +505,6 @@ importers:
'@yume-chan/stream-extra':
specifier: workspace:^0.0.23
version: link:../stream-extra
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
devDependencies:
'@jest/globals':
specifier: ^30.0.0-alpha.3
@@ -535,9 +539,6 @@ importers:
'@yume-chan/struct':
specifier: workspace:^0.0.23
version: link:../struct
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
devDependencies:
'@jest/globals':
specifier: ^30.0.0-alpha.3
@@ -566,12 +567,9 @@ importers:
../../libraries/struct:
dependencies:
- '@yume-chan/dataview-bigint-polyfill':
+ '@yume-chan/no-data-view':
specifier: workspace:^0.0.23
- version: link:../dataview-bigint-polyfill
- tslib:
- specifier: ^2.6.2
- version: 2.6.2
+ version: link:../no-data-view
devDependencies:
'@jest/globals':
specifier: ^30.0.0-alpha.3
@@ -4571,6 +4569,10 @@ packages:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
dev: false
+ /tinybench@2.7.0:
+ resolution: {integrity: sha512-Qgayeb106x2o4hNzNjsZEfFziw8IbKqtbXBjVh7VIZfBxfD5M4gWtpyx5+YTae2gJ6Y6Dz/KLepiv16RFeQWNA==}
+ dev: true
+
/tinyh264@0.0.7:
resolution: {integrity: sha512-etkBRgYkSFBdAi2Cqk4sZgi+xWs/vhzNgvjO3z2i4WILeEmORiNqxuQ4URJatrWQ9LPNV3WPWAtzsh/LA/XL/g==}
dev: false
diff --git a/common/config/rush/repo-state.json b/common/config/rush/repo-state.json
index 8020e38d..2c629671 100644
--- a/common/config/rush/repo-state.json
+++ b/common/config/rush/repo-state.json
@@ -1,5 +1,5 @@
// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush.
{
- "pnpmShrinkwrapHash": "5dfb0a8a0ad6b0505870eeb38140a9ba82571aee",
+ "pnpmShrinkwrapHash": "0fb46a0dd9d3d20531a5eb59ce8ba9cacfe15a30",
"preferredVersionsHash": "bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f"
}
diff --git a/libraries/adb-credential-web/package.json b/libraries/adb-credential-web/package.json
index 6d13ed0f..afd20e78 100644
--- a/libraries/adb-credential-web/package.json
+++ b/libraries/adb-credential-web/package.json
@@ -30,8 +30,7 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
- "@yume-chan/adb": "workspace:^0.0.23",
- "tslib": "^2.6.2"
+ "@yume-chan/adb": "workspace:^0.0.23"
},
"devDependencies": {
"@yume-chan/eslint-config": "workspace:^1.0.0",
diff --git a/libraries/adb-daemon-webusb/package.json b/libraries/adb-daemon-webusb/package.json
index 6b0bed00..5052b6a2 100644
--- a/libraries/adb-daemon-webusb/package.json
+++ b/libraries/adb-daemon-webusb/package.json
@@ -34,8 +34,7 @@
"@types/w3c-web-usb": "^1.0.10",
"@yume-chan/adb": "workspace:^0.0.23",
"@yume-chan/stream-extra": "workspace:^0.0.23",
- "@yume-chan/struct": "workspace:^0.0.23",
- "tslib": "^2.6.2"
+ "@yume-chan/struct": "workspace:^0.0.23"
},
"devDependencies": {
"@yume-chan/eslint-config": "workspace:^1.0.0",
diff --git a/libraries/adb-scrcpy/package.json b/libraries/adb-scrcpy/package.json
index dece14bd..fb8ee4dc 100644
--- a/libraries/adb-scrcpy/package.json
+++ b/libraries/adb-scrcpy/package.json
@@ -37,8 +37,7 @@
"@yume-chan/event": "workspace:^0.0.23",
"@yume-chan/scrcpy": "workspace:^0.0.23",
"@yume-chan/stream-extra": "workspace:^0.0.23",
- "@yume-chan/struct": "workspace:^0.0.23",
- "tslib": "^2.6.2"
+ "@yume-chan/struct": "workspace:^0.0.23"
},
"devDependencies": {
"@jest/globals": "^30.0.0-alpha.3",
diff --git a/libraries/adb-server-node-tcp/package.json b/libraries/adb-server-node-tcp/package.json
index 60fb19f7..eb337210 100644
--- a/libraries/adb-server-node-tcp/package.json
+++ b/libraries/adb-server-node-tcp/package.json
@@ -34,8 +34,7 @@
"dependencies": {
"@yume-chan/adb": "workspace:^0.0.23",
"@yume-chan/stream-extra": "workspace:^0.0.23",
- "@yume-chan/struct": "workspace:^0.0.23",
- "tslib": "^2.6.2"
+ "@yume-chan/struct": "workspace:^0.0.23"
},
"devDependencies": {
"@types/node": "^20.12.7",
diff --git a/libraries/adb/package.json b/libraries/adb/package.json
index 1429faa9..97914140 100644
--- a/libraries/adb/package.json
+++ b/libraries/adb/package.json
@@ -35,9 +35,9 @@
"@yume-chan/async": "^2.2.0",
"@yume-chan/dataview-bigint-polyfill": "workspace:^0.0.23",
"@yume-chan/event": "workspace:^0.0.23",
+ "@yume-chan/no-data-view": "workspace:^0.0.23",
"@yume-chan/stream-extra": "workspace:^0.0.23",
- "@yume-chan/struct": "workspace:^0.0.23",
- "tslib": "^2.6.2"
+ "@yume-chan/struct": "workspace:^0.0.23"
},
"devDependencies": {
"@jest/globals": "^30.0.0-alpha.3",
diff --git a/libraries/adb/src/commands/sync/push.ts b/libraries/adb/src/commands/sync/push.ts
index ff0e0a99..2c5b437c 100644
--- a/libraries/adb/src/commands/sync/push.ts
+++ b/libraries/adb/src/commands/sync/push.ts
@@ -97,10 +97,7 @@ export enum AdbSyncSendV2Flags {
* 4
*/
Zstd = 1 << 2,
- /**
- * 0x80000000
- */
- DryRun = (1 << 31) >>> 0,
+ DryRun = 0x80000000,
}
export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
diff --git a/libraries/adb/src/daemon/crypto.ts b/libraries/adb/src/daemon/crypto.ts
index b6148b1d..4655892b 100644
--- a/libraries/adb/src/daemon/crypto.ts
+++ b/libraries/adb/src/daemon/crypto.ts
@@ -1,7 +1,8 @@
import {
- getBigUint64,
- setBigUint64,
-} from "@yume-chan/dataview-bigint-polyfill/esm/fallback.js";
+ getUint64BigEndian,
+ setInt64BigEndian,
+ setInt64LittleEndian,
+} from "@yume-chan/no-data-view";
/**
* Gets the `BigInt` value at the specified byte offset and length from the start of the view. There is
@@ -11,7 +12,7 @@ import {
* @param byteOffset The place in the buffer at which the value should be retrieved.
*/
export function getBigUint(
- dataView: DataView,
+ array: Uint8Array,
byteOffset: number,
length: number,
): bigint {
@@ -22,8 +23,8 @@ export function getBigUint(
for (let i = byteOffset; i < byteOffset + length; i += 8) {
result <<= 64n;
- const value = getBigUint64(dataView, i, false);
- result += value;
+ const value = getUint64BigEndian(array, i);
+ result |= value;
}
return result;
@@ -37,7 +38,7 @@ export function getBigUint(
* otherwise a little-endian value should be written.
*/
export function setBigUint(
- dataView: DataView,
+ array: Uint8Array,
byteOffset: number,
value: bigint,
littleEndian?: boolean,
@@ -46,7 +47,7 @@ export function setBigUint(
if (littleEndian) {
while (value > 0n) {
- setBigUint64(dataView, byteOffset, value, true);
+ setInt64LittleEndian(array, byteOffset, value);
byteOffset += 8;
value >>= 64n;
}
@@ -60,7 +61,7 @@ export function setBigUint(
}
for (let i = uint64Array.length - 1; i >= 0; i -= 1) {
- setBigUint64(dataView, byteOffset, uint64Array[i]!, false);
+ setInt64BigEndian(array, byteOffset, uint64Array[i]!);
byteOffset += 8;
}
}
@@ -95,9 +96,8 @@ const RsaPrivateKeyDOffset = 303;
const RsaPrivateKeyDLength = 2048 / 8;
export function rsaParsePrivateKey(key: Uint8Array): [n: bigint, d: bigint] {
- const view = new DataView(key.buffer, key.byteOffset, key.byteLength);
- const n = getBigUint(view, RsaPrivateKeyNOffset, RsaPrivateKeyNLength);
- const d = getBigUint(view, RsaPrivateKeyDOffset, RsaPrivateKeyDLength);
+ const n = getBigUint(key, RsaPrivateKeyNOffset, RsaPrivateKeyNLength);
+ const d = getBigUint(key, RsaPrivateKeyDOffset, RsaPrivateKeyDLength);
return [n, d];
}
@@ -193,12 +193,12 @@ export function adbGeneratePublicKey(
outputOffset += 4;
// Write n
- setBigUint(outputView, outputOffset, n, true);
+ setBigUint(output, outputOffset, n, true);
outputOffset += 256;
// Calculate rr = (2^(rsa_size)) ^ 2 mod n
const rr = 2n ** 4096n % n;
- outputOffset += setBigUint(outputView, outputOffset, rr, true);
+ outputOffset += setBigUint(output, outputOffset, rr, true);
// exponent
outputView.setUint32(outputOffset, 65537, true);
@@ -305,12 +305,11 @@ export function rsaSign(privateKey: Uint8Array, data: Uint8Array): Uint8Array {
// Encryption
// signature = padded ** d % n
- const view = new DataView(padded.buffer);
- const signature = powMod(getBigUint(view, 0, view.byteLength), d, n);
+ const signature = powMod(getBigUint(padded, 0, padded.length), d, n);
// `padded` is not used anymore,
// re-use the buffer to store the result
- setBigUint(view, 0, signature, false);
+ setBigUint(padded, 0, signature, false);
return padded;
}
diff --git a/libraries/adb/src/daemon/dispatcher.ts b/libraries/adb/src/daemon/dispatcher.ts
index dd0fb308..9b60be3d 100644
--- a/libraries/adb/src/daemon/dispatcher.ts
+++ b/libraries/adb/src/daemon/dispatcher.ts
@@ -3,6 +3,10 @@ import {
PromiseResolver,
delay,
} from "@yume-chan/async";
+import {
+ getUint32BigEndian,
+ setUint32LittleEndian,
+} from "@yume-chan/no-data-view";
import {
AbortController,
Consumable,
@@ -10,7 +14,7 @@ import {
type ReadableWritablePair,
type WritableStreamDefaultWriter,
} from "@yume-chan/stream-extra";
-import { EMPTY_UINT8_ARRAY, NumberFieldType } from "@yume-chan/struct";
+import { EMPTY_UINT8_ARRAY } from "@yume-chan/struct";
import type { AdbIncomingSocketHandler, AdbSocket, Closeable } from "../adb.js";
import { decodeUtf8, encodeUtf8 } from "../utils/index.js";
@@ -189,7 +193,7 @@ export class AdbPacketDispatcher implements Closeable {
"Invalid OKAY packet. Payload size should be 4",
);
}
- ackBytes = NumberFieldType.Uint32.deserialize(packet.payload, true);
+ ackBytes = getUint32BigEndian(packet.payload, 0);
} else {
if (packet.payload.byteLength !== 0) {
throw new Error(
@@ -228,10 +232,7 @@ export class AdbPacketDispatcher implements Closeable {
let payload: Uint8Array;
if (this.options.initialDelayedAckBytes !== 0) {
payload = new Uint8Array(4);
- payload[0] = ackBytes & 0xff;
- payload[1] = (ackBytes >> 8) & 0xff;
- payload[2] = (ackBytes >> 16) & 0xff;
- payload[3] = (ackBytes >> 24) & 0xff;
+ setUint32LittleEndian(payload, 0, ackBytes);
} else {
payload = EMPTY_UINT8_ARRAY;
}
diff --git a/libraries/adb/src/server/client.ts b/libraries/adb/src/server/client.ts
index 68ea3c99..5aad69f4 100644
--- a/libraries/adb/src/server/client.ts
+++ b/libraries/adb/src/server/client.ts
@@ -17,7 +17,6 @@ import type {
ValueOrPromise,
} from "@yume-chan/struct";
import {
- BigIntFieldType,
EMPTY_UINT8_ARRAY,
SyncPromise,
decodeUtf8,
@@ -29,6 +28,7 @@ import { AdbBanner } from "../banner.js";
import type { AdbFeature } from "../features.js";
import { NOOP, hexToNumber, numberToHex, unreachable } from "../utils/index.js";
+import { getUint64LittleEndian } from "@yume-chan/no-data-view";
import { AdbServerTransport } from "./transport.js";
export interface AdbServerConnectionOptions {
@@ -391,13 +391,7 @@ export class AdbServerClient {
try {
if (transportId === undefined) {
const array = await readable.readExactly(8);
- // TODO: switch to a more performant algorithm.
- const dataView = new DataView(
- array.buffer,
- array.byteOffset,
- array.byteLength,
- );
- transportId = BigIntFieldType.Uint64.getter(dataView, 0, true);
+ transportId = getUint64LittleEndian(array, 0);
}
await AdbServerClient.readOkay(readable);
diff --git a/libraries/android-bin/package.json b/libraries/android-bin/package.json
index e5a765f5..c43b87a9 100644
--- a/libraries/android-bin/package.json
+++ b/libraries/android-bin/package.json
@@ -34,8 +34,7 @@
"dependencies": {
"@yume-chan/adb": "workspace:^0.0.23",
"@yume-chan/stream-extra": "workspace:^0.0.23",
- "@yume-chan/struct": "workspace:^0.0.23",
- "tslib": "^2.6.2"
+ "@yume-chan/struct": "workspace:^0.0.23"
},
"devDependencies": {
"@jest/globals": "^30.0.0-alpha.3",
diff --git a/libraries/aoa/package.json b/libraries/aoa/package.json
index 8e1b3dd6..bac3815a 100644
--- a/libraries/aoa/package.json
+++ b/libraries/aoa/package.json
@@ -31,8 +31,7 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
- "@types/w3c-web-usb": "^1.0.10",
- "tslib": "^2.6.2"
+ "@types/w3c-web-usb": "^1.0.10"
},
"devDependencies": {
"@yume-chan/eslint-config": "workspace:^1.0.0",
diff --git a/libraries/dataview-bigint-polyfill/package.json b/libraries/dataview-bigint-polyfill/package.json
index 4b6fc0ce..7ecc2465 100644
--- a/libraries/dataview-bigint-polyfill/package.json
+++ b/libraries/dataview-bigint-polyfill/package.json
@@ -35,9 +35,7 @@
"lint": "run-eslint && prettier src/**/*.ts --write --tab-width 4",
"prepublishOnly": "npm run build"
},
- "dependencies": {
- "tslib": "^2.6.2"
- },
+ "dependencies": {},
"devDependencies": {
"@yume-chan/eslint-config": "workspace:^1.0.0",
"@yume-chan/tsconfig": "workspace:^1.0.0",
diff --git a/libraries/event/package.json b/libraries/event/package.json
index 45f4231e..511ef49d 100644
--- a/libraries/event/package.json
+++ b/libraries/event/package.json
@@ -33,8 +33,7 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
- "@yume-chan/async": "^2.2.0",
- "tslib": "^2.6.2"
+ "@yume-chan/async": "^2.2.0"
},
"devDependencies": {
"@jest/globals": "^30.0.0-alpha.3",
diff --git a/libraries/no-data-view/.npmignore b/libraries/no-data-view/.npmignore
new file mode 100644
index 00000000..96b1a6a3
--- /dev/null
+++ b/libraries/no-data-view/.npmignore
@@ -0,0 +1,19 @@
+.rush
+
+# Test
+coverage
+**/*.spec.ts
+**/*.spec.js
+**/*.spec.js.map
+**/__helpers__
+jest.config.js
+
+.eslintrc.cjs
+tsconfig.json
+tsconfig.test.json
+
+# Logs
+*.log
+
+benchmark.js
+benchmark.md
diff --git a/libraries/no-data-view/LICENSE b/libraries/no-data-view/LICENSE
new file mode 100644
index 00000000..9bd36e79
--- /dev/null
+++ b/libraries/no-data-view/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020-2023 Simon Chan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/libraries/no-data-view/README.md b/libraries/no-data-view/README.md
new file mode 100644
index 00000000..d8b58ef2
--- /dev/null
+++ b/libraries/no-data-view/README.md
@@ -0,0 +1,21 @@
+# @yume-chan/no-data-view
+
+Plain methods to avoid creating `DataView`s.
+
+## Why?
+
+If you have many short `Uint8Array`s and you want to read numbers from them, creating `DataView`s for each of them is not a good idea:
+
+Each `DataView` needs to allocate some memory, it impacts the performance, increases the memory usage, and adds GC pressure.
+
+(If you are using `DataView`s for large `ArrayBuffer`s, it's fine)
+
+## How does it work?
+
+This package provides a set of methods to read/write numbers from `Uint8Array`s without creating `DataView`s.
+
+Because they are very basic number operations, the performance between a JavaScript implementation and the native `DataView` is nearly identical.
+
+(Except for `getBigUint64` and `setBigUint64`, Chrome uses an inefficient implementation, so this JavaScript implementation is even faster than the native one).
+
+Check the [benchmark](./benchmark.md) for more details.
diff --git a/libraries/no-data-view/benchmark.js b/libraries/no-data-view/benchmark.js
new file mode 100644
index 00000000..241e1b25
--- /dev/null
+++ b/libraries/no-data-view/benchmark.js
@@ -0,0 +1,243 @@
+///
+
+import { once } from "events";
+import { createWriteStream } from "fs";
+import { Bench } from "tinybench";
+
+import {
+ getInt16LittleEndian,
+ getInt32LittleEndian,
+ getInt64LittleEndian,
+ getUint16,
+ getUint16BigEndian,
+ getUint16LittleEndian,
+ getUint32LittleEndian,
+ getUint64BigEndian,
+ getUint64LittleEndian,
+} from "./esm/index.js";
+
+console.log(
+ "Adjust priority for process",
+ process.pid,
+ ", then press Enter to start...",
+);
+await once(process.stdin, "data");
+console.log("Starting benchmark");
+
+const data = new Uint8Array([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
+const buffer = data.buffer;
+const dataView = new DataView(data.buffer);
+
+const output = createWriteStream("benchmark.md");
+
+/**
+ *
+ * @param {string} name
+ * @param {Bench} bench
+ */
+function print(name, bench) {
+ console.log();
+ console.log(name);
+ console.table(bench.table());
+
+ output.write("## " + name + "\n\n");
+ output.write(
+ "| " +
+ ["Name", "Ops/s", "Avg Time", "Compare"].join(" | ") +
+ " |\n" +
+ "|---|---|---|---|\n",
+ );
+ let firstResultHz;
+ for (const task of bench.tasks) {
+ const result = task.result;
+ if (!result) {
+ return;
+ }
+ let compare = 1;
+ if (firstResultHz) {
+ compare = result.hz / firstResultHz;
+ } else {
+ firstResultHz = result.hz;
+ }
+ output.write(
+ "| " +
+ [
+ task.name,
+ (result.hz | 0).toLocaleString("en-US"),
+ (result.mean * 1_000_000).toLocaleString("en-US") + " ns",
+ (compare * 100).toFixed(2) + "%",
+ ].join(" | ") +
+ " |\n",
+ );
+ }
+ output.write("\n");
+}
+
+const only = process.argv[2];
+
+/**
+ *
+ * @param {string} name
+ * @param {(bench:Bench)=>void} callback
+ * @returns
+ */
+async function runBenchmark(name, callback) {
+ if (only && only !== name) {
+ return;
+ }
+
+ const bench = new Bench();
+ callback(bench);
+
+ await bench.warmup();
+ await bench.run();
+
+ print(name, bench);
+}
+
+await runBenchmark("getUint16LittleEndian", (bench) => {
+ bench
+ .add("getUint16LittleEndian", () => {
+ getUint16LittleEndian(data, 0);
+ })
+ .add("cached DataView", () => {
+ dataView.getUint16(0, true);
+ })
+ .add("new DataView", () => {
+ new DataView(buffer).getUint16(0, true);
+ });
+});
+
+await runBenchmark("getUint16BigEndian", (bench) => {
+ bench
+ .add("getUint16BigEndian", () => {
+ getUint16BigEndian(data, 0);
+ })
+ .add("cached DataView", () => {
+ dataView.getUint16(0, true);
+ })
+ .add("new DataView", () => {
+ new DataView(buffer).getUint16(0, true);
+ });
+});
+
+await runBenchmark("getUint16", (bench) => {
+ let littleEndian = true;
+
+ bench
+ .add(
+ "getUint16",
+ () => {
+ getUint16(data, 0, littleEndian);
+ },
+ {
+ beforeEach: () => {
+ littleEndian = Math.random() > 0.5;
+ },
+ },
+ )
+ .add(
+ "cached DataView",
+ () => {
+ dataView.getUint16(0, true);
+ },
+ {
+ beforeEach: () => {
+ littleEndian = Math.random() > 0.5;
+ },
+ },
+ )
+ .add(
+ "new DataView",
+ () => {
+ new DataView(buffer).getUint16(0, true);
+ },
+ {
+ beforeEach: () => {
+ littleEndian = Math.random() > 0.5;
+ },
+ },
+ );
+});
+
+await runBenchmark("getInt16LittleEndian", (bench) => {
+ bench
+ .add("getInt16LittleEndian", () => {
+ getInt16LittleEndian(data, 0);
+ })
+ .add("cached DataView", () => {
+ dataView.getInt16(0, true);
+ })
+ .add("new DataView", () => {
+ new DataView(buffer).getInt16(0, true);
+ });
+});
+
+await runBenchmark("getUint32LittleEndian", (bench) => {
+ bench
+ .add("getUint32LittleEndian", () => {
+ getUint32LittleEndian(data, 0);
+ })
+ .add("cached DataView", () => {
+ dataView.getUint32(0, true);
+ })
+ .add("new DataView", () => {
+ new DataView(buffer).getUint32(0, true);
+ });
+});
+
+await runBenchmark("getInt32LittleEndian", (bench) => {
+ bench
+ .add("getInt32LittleEndian", () => {
+ getInt32LittleEndian(data, 0);
+ })
+ .add("cached DataView", () => {
+ dataView.getInt32(0, true);
+ })
+ .add("new DataView", () => {
+ new DataView(buffer).getInt32(0, true);
+ });
+});
+
+await runBenchmark("getUint64LittleEndian", (bench) => {
+ bench
+ .add("getUint64LittleEndian", () => {
+ getUint64LittleEndian(data, 0);
+ })
+ .add("cached DataView", () => {
+ dataView.getBigUint64(0, true);
+ })
+ .add("new DataView", () => {
+ new DataView(buffer).getBigUint64(0, true);
+ });
+});
+
+await runBenchmark("getUint64BigEndian", (bench) => {
+ bench
+ .add("getUint64BigEndian", () => {
+ getUint64BigEndian(data, 0);
+ })
+ .add("cached DataView", () => {
+ dataView.getBigUint64(0, true);
+ })
+ .add("new DataView", () => {
+ new DataView(buffer).getBigUint64(0, true);
+ });
+});
+
+await runBenchmark("getInt64LittleEndian", (bench) => {
+ bench
+ .add("getInt64LittleEndian", () => {
+ getInt64LittleEndian(data, 0);
+ })
+ .add("cached DataView", () => {
+ dataView.getBigInt64(0, true);
+ })
+ .add("new DataView", () => {
+ new DataView(buffer).getBigInt64(0, true);
+ });
+});
+
+output.close(() => {
+ process.exit(0);
+});
diff --git a/libraries/no-data-view/benchmark.md b/libraries/no-data-view/benchmark.md
new file mode 100644
index 00000000..1bf0df4a
--- /dev/null
+++ b/libraries/no-data-view/benchmark.md
@@ -0,0 +1,71 @@
+## getUint16LittleEndian
+
+| Name | Ops/s | Avg Time | Compare |
+| --------------------- | ---------- | ---------- | ------- |
+| getUint16LittleEndian | 19,892,072 | 50.271 ns | 100.00% |
+| cached DataView | 18,810,767 | 53.161 ns | 94.56% |
+| new DataView | 7,585,290 | 131.834 ns | 38.13% |
+
+## getUint16BigEndian
+
+| Name | Ops/s | Avg Time | Compare |
+| ------------------ | ---------- | ---------- | ------- |
+| getUint16BigEndian | 19,553,782 | 51.141 ns | 100.00% |
+| cached DataView | 19,919,910 | 50.201 ns | 101.87% |
+| new DataView | 7,843,575 | 127.493 ns | 40.11% |
+
+## getUint16
+
+| Name | Ops/s | Avg Time | Compare |
+| --------------- | ---------- | ---------- | ------- |
+| getUint16 | 18,571,186 | 53.847 ns | 100.00% |
+| cached DataView | 19,434,597 | 51.455 ns | 104.65% |
+| new DataView | 7,480,502 | 133.681 ns | 40.28% |
+
+## getInt16LittleEndian
+
+| Name | Ops/s | Avg Time | Compare |
+| -------------------- | ---------- | --------- | ------- |
+| getInt16LittleEndian | 19,719,781 | 50.71 ns | 100.00% |
+| cached DataView | 20,285,727 | 49.296 ns | 102.87% |
+| new DataView | 7,963,668 | 125.57 ns | 40.38% |
+
+## getUint32LittleEndian
+
+| Name | Ops/s | Avg Time | Compare |
+| --------------------- | ---------- | ---------- | ------- |
+| getUint32LittleEndian | 20,037,121 | 49.907 ns | 100.00% |
+| cached DataView | 19,750,168 | 50.632 ns | 98.57% |
+| new DataView | 8,127,370 | 123.041 ns | 40.56% |
+
+## getInt32LittleEndian
+
+| Name | Ops/s | Avg Time | Compare |
+| -------------------- | ---------- | ---------- | ------- |
+| getInt32LittleEndian | 19,955,247 | 50.112 ns | 100.00% |
+| cached DataView | 19,721,023 | 50.707 ns | 98.83% |
+| new DataView | 7,888,401 | 126.768 ns | 39.53% |
+
+## getUint64LittleEndian
+
+| Name | Ops/s | Avg Time | Compare |
+| --------------------- | ---------- | ---------- | ------- |
+| getUint64LittleEndian | 19,438,620 | 51.444 ns | 100.00% |
+| cached DataView | 16,597,547 | 60.25 ns | 85.38% |
+| new DataView | 6,957,942 | 143.721 ns | 35.79% |
+
+## getUint64BigEndian
+
+| Name | Ops/s | Avg Time | Compare |
+| ------------------ | ---------- | ---------- | ------- |
+| getUint64BigEndian | 20,075,843 | 49.811 ns | 100.00% |
+| cached DataView | 16,787,123 | 59.569 ns | 83.62% |
+| new DataView | 7,469,821 | 133.872 ns | 37.21% |
+
+## getInt64LittleEndian
+
+| Name | Ops/s | Avg Time | Compare |
+| -------------------- | ---------- | --------- | ------- |
+| getInt64LittleEndian | 20,167,285 | 49.585 ns | 100.00% |
+| cached DataView | 17,129,268 | 58.38 ns | 84.94% |
+| new DataView | 7,605,130 | 131.49 ns | 37.71% |
diff --git a/libraries/no-data-view/jest.config.js b/libraries/no-data-view/jest.config.js
new file mode 100644
index 00000000..ff68d1cb
--- /dev/null
+++ b/libraries/no-data-view/jest.config.js
@@ -0,0 +1,14 @@
+/** @type {import('ts-jest').JestConfigWithTsJest} */
+export default {
+ preset: "ts-jest/presets/default-esm",
+ extensionsToTreatAsEsm: [".ts"],
+ transform: {
+ "^.+\\.tsx?$": [
+ "ts-jest",
+ { tsconfig: "tsconfig.test.json", useESM: true },
+ ],
+ },
+ moduleNameMapper: {
+ "^(\\.{1,2}/.*)\\.js$": "$1",
+ },
+};
diff --git a/libraries/no-data-view/package.json b/libraries/no-data-view/package.json
new file mode 100644
index 00000000..3eb2afeb
--- /dev/null
+++ b/libraries/no-data-view/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "@yume-chan/no-data-view",
+ "version": "0.0.23",
+ "description": "Plain methods to avoid creating `DataView`s",
+ "keywords": [],
+ "license": "MIT",
+ "author": {
+ "name": "Simon Chan",
+ "email": "cnsimonchan@live.com",
+ "url": "https://chensi.moe/blog"
+ },
+ "homepage": "https://github.com/yume-chan/ya-webadb/tree/main/packages/no-data-view#readme",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/yume-chan/ya-webadb.git",
+ "directory": "packages/no-data-view"
+ },
+ "bugs": {
+ "url": "https://github.com/yume-chan/ya-webadb/issues"
+ },
+ "type": "module",
+ "main": "esm/index.js",
+ "types": "esm/index.d.ts",
+ "scripts": {
+ "benchmark": "node benchmark.js",
+ "build": "tsc -b tsconfig.build.json",
+ "build:watch": "tsc -b tsconfig.build.json",
+ "test": "cross-env NODE_OPTIONS=\"--experimental-vm-modules --no-warnings\" TS_JEST_DISABLE_VER_CHECKER=true jest --coverage",
+ "lint": "run-eslint && prettier src/**/*.ts --write --tab-width 4",
+ "prepublishOnly": "npm run build"
+ },
+ "dependencies": {},
+ "devDependencies": {
+ "@types/node": "^20.12.7",
+ "@jest/globals": "^30.0.0-alpha.3",
+ "@yume-chan/eslint-config": "workspace:^1.0.0",
+ "@yume-chan/tsconfig": "workspace:^1.0.0",
+ "cross-env": "^7.0.3",
+ "jest": "^30.0.0-alpha.3",
+ "prettier": "^3.2.5",
+ "ts-jest": "^29.1.2",
+ "tinybench": "^2.7.0",
+ "typescript": "^5.4.5"
+ }
+}
diff --git a/libraries/no-data-view/src/index.ts b/libraries/no-data-view/src/index.ts
new file mode 100644
index 00000000..3378e919
--- /dev/null
+++ b/libraries/no-data-view/src/index.ts
@@ -0,0 +1,7 @@
+export * from "./int16.js";
+export * from "./int32.js";
+export * from "./int64.js";
+export * from "./int8.js";
+export * from "./uint16.js";
+export * from "./uint32.js";
+export * from "./uint64.js";
diff --git a/libraries/no-data-view/src/int16.spec.ts b/libraries/no-data-view/src/int16.spec.ts
new file mode 100644
index 00000000..d67e1343
--- /dev/null
+++ b/libraries/no-data-view/src/int16.spec.ts
@@ -0,0 +1,149 @@
+import { describe, expect, it } from "@jest/globals";
+
+import {
+ getInt16,
+ getInt16BigEndian,
+ getInt16LittleEndian,
+ setInt16,
+ setInt16BigEndian,
+ setInt16LittleEndian,
+} from "./int16.js";
+
+describe("getInt16", () => {
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const array = new Uint8Array([0, 128]);
+ expect(getInt16LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt16(0, true),
+ );
+ });
+
+ it("should work for maximal value", () => {
+ const array = new Uint8Array([255, 127]);
+ expect(getInt16LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt16(0, true),
+ );
+ });
+
+ it("should work for middle value", () => {
+ const array = new Uint8Array([0, 0]);
+ expect(getInt16LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt16(0, true),
+ );
+ });
+
+ it("should work for random value", () => {
+ const array = new Uint8Array([1, 2]);
+ expect(getInt16LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint16(0, true),
+ );
+ });
+ });
+
+ describe("big endian", () => {
+ it("should work for minimal value", () => {
+ const array = new Uint8Array([128, 0]);
+ expect(getInt16BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt16(0, false),
+ );
+ });
+
+ it("should work for maximal value", () => {
+ const array = new Uint8Array([127, 255]);
+ expect(getInt16BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt16(0, false),
+ );
+ });
+
+ it("should work for middle value", () => {
+ const array = new Uint8Array([0, 0]);
+ expect(getInt16BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt16(0, false),
+ );
+ });
+
+ it("should work for random value", () => {
+ const array = new Uint8Array([1, 2]);
+ expect(getInt16BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint16(0, false),
+ );
+ });
+ });
+
+ it("should work for selected endianness", () => {
+ const array = new Uint8Array([1, 2]);
+ expect(getInt16(array, 0, false)).toBe(
+ new DataView(array.buffer).getInt16(0, false),
+ );
+ expect(getInt16(array, 0, true)).toBe(
+ new DataView(array.buffer).getInt16(0, true),
+ );
+ });
+});
+
+describe("setInt16", () => {
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const expected = new Uint8Array(2);
+ new DataView(expected.buffer).setInt16(0, -0x8000, true);
+ const actual = new Uint8Array(2);
+ setInt16LittleEndian(actual, 0, -0x8000);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for maximal value", () => {
+ const expected = new Uint8Array(2);
+ new DataView(expected.buffer).setInt16(0, 0x7fff, true);
+ const actual = new Uint8Array(2);
+ setInt16LittleEndian(actual, 0, 0x7fff);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for middle value", () => {
+ const expected = new Uint8Array(2);
+ new DataView(expected.buffer).setInt16(0, 0, true);
+ const actual = new Uint8Array(2);
+ setInt16LittleEndian(actual, 0, 0);
+ expect(actual).toEqual(expected);
+ });
+ });
+
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const expected = new Uint8Array(2);
+ new DataView(expected.buffer).setInt16(0, -0x8000, false);
+ const actual = new Uint8Array(2);
+ setInt16BigEndian(actual, 0, -0x8000);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for maximal value", () => {
+ const expected = new Uint8Array(2);
+ new DataView(expected.buffer).setInt16(0, 0x7fff, false);
+ const actual = new Uint8Array(2);
+ setInt16BigEndian(actual, 0, 0x7fff);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for middle value", () => {
+ const expected = new Uint8Array(2);
+ new DataView(expected.buffer).setInt16(0, 0, false);
+ const actual = new Uint8Array(2);
+ setInt16BigEndian(actual, 0, 0);
+ expect(actual).toEqual(expected);
+ });
+ });
+
+ it("should work for selected endianness", () => {
+ const expected = new Uint8Array(2);
+ const actual = new Uint8Array(2);
+
+ new DataView(expected.buffer).setInt16(0, 0x7fff, false);
+ setInt16(actual, 0, 0x7fff, false);
+ expect(actual).toEqual(expected);
+
+ new DataView(expected.buffer).setInt16(0, 0x7fff, true);
+ setInt16(actual, 0, 0x7fff, true);
+ expect(actual).toEqual(expected);
+ });
+});
diff --git a/libraries/no-data-view/src/int16.ts b/libraries/no-data-view/src/int16.ts
new file mode 100644
index 00000000..905e79cc
--- /dev/null
+++ b/libraries/no-data-view/src/int16.ts
@@ -0,0 +1,53 @@
+export function getInt16LittleEndian(
+ buffer: Uint8Array,
+ offset: number,
+): number {
+ return ((buffer[offset]! | (buffer[offset + 1]! << 8)) << 16) >> 16;
+}
+
+export function getInt16BigEndian(buffer: Uint8Array, offset: number): number {
+ return (((buffer[offset]! << 8) | buffer[offset + 1]!) << 16) >> 16;
+}
+
+export function getInt16(
+ buffer: Uint8Array,
+ offset: number,
+ littleEndian: boolean,
+) {
+ return littleEndian
+ ? ((buffer[offset]! | (buffer[offset + 1]! << 8)) << 16) >> 16
+ : (((buffer[offset]! << 8) | buffer[offset + 1]!) << 16) >> 16;
+}
+
+export function setInt16LittleEndian(
+ buffer: Uint8Array,
+ offset: number,
+ value: number,
+): void {
+ buffer[offset] = value & 0xff;
+ buffer[offset + 1] = (value >> 8) & 0xff;
+}
+
+export function setInt16BigEndian(
+ buffer: Uint8Array,
+ offset: number,
+ value: number,
+): void {
+ buffer[offset] = (value >> 8) & 0xff;
+ buffer[offset + 1] = value & 0xff;
+}
+
+export function setInt16(
+ buffer: Uint8Array,
+ offset: number,
+ value: number,
+ littleEndian: boolean,
+): void {
+ if (littleEndian) {
+ buffer[offset] = value & 0xff;
+ buffer[offset + 1] = (value >> 8) & 0xff;
+ } else {
+ buffer[offset] = (value >> 8) & 0xff;
+ buffer[offset + 1] = value & 0xff;
+ }
+}
diff --git a/libraries/no-data-view/src/int32.spec.ts b/libraries/no-data-view/src/int32.spec.ts
new file mode 100644
index 00000000..a5889974
--- /dev/null
+++ b/libraries/no-data-view/src/int32.spec.ts
@@ -0,0 +1,75 @@
+import { describe, expect, it } from "@jest/globals";
+
+import { getInt32, getInt32BigEndian, getInt32LittleEndian } from "./int32.js";
+
+describe("getInt32", () => {
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const array = new Uint8Array([0, 0, 0, 128]);
+ expect(getInt32LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt32(0, true),
+ );
+ });
+
+ it("should work for maximal value", () => {
+ const array = new Uint8Array([255, 255, 255, 127]);
+ expect(getInt32LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt32(0, true),
+ );
+ });
+
+ it("should work for middle value", () => {
+ const array = new Uint8Array([0, 0, 0, 0]);
+ expect(getInt32LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt32(0, true),
+ );
+ });
+
+ it("should work for random value", () => {
+ const array = new Uint8Array([1, 2, 3, 4]);
+ expect(getInt32LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt32(0, true),
+ );
+ });
+ });
+
+ describe("big endian", () => {
+ it("should work for minimal value", () => {
+ const array = new Uint8Array([128, 0, 0, 0]);
+ expect(getInt32BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt32(0, false),
+ );
+ });
+
+ it("should work for maximal value", () => {
+ const array = new Uint8Array([127, 255, 255, 255]);
+ expect(getInt32BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt32(0, false),
+ );
+ });
+
+ it("should work for middle value", () => {
+ const array = new Uint8Array([0, 0, 0, 0]);
+ expect(getInt32BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt32(0, false),
+ );
+ });
+
+ it("should work for random value", () => {
+ const array = new Uint8Array([1, 2, 3, 4]);
+ expect(getInt32BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getInt32(0, false),
+ );
+ });
+ });
+
+ it("should work for selected endianness", () => {
+ const array = new Uint8Array([1, 2, 3, 4]);
+ expect(getInt32(array, 0, false)).toBe(
+ new DataView(array.buffer).getInt32(0, false),
+ );
+ expect(getInt32(array, 0, true)).toBe(
+ new DataView(array.buffer).getInt32(0, true),
+ );
+ });
+});
diff --git a/libraries/no-data-view/src/int32.ts b/libraries/no-data-view/src/int32.ts
new file mode 100644
index 00000000..89e6e867
--- /dev/null
+++ b/libraries/no-data-view/src/int32.ts
@@ -0,0 +1,36 @@
+export function getInt32LittleEndian(
+ buffer: Uint8Array,
+ offset: number,
+): number {
+ return (
+ buffer[offset]! |
+ (buffer[offset + 1]! << 8) |
+ (buffer[offset + 2]! << 16) |
+ (buffer[offset + 3]! << 24)
+ );
+}
+
+export function getInt32BigEndian(buffer: Uint8Array, offset: number): number {
+ return (
+ (buffer[offset]! << 24) |
+ (buffer[offset + 1]! << 16) |
+ (buffer[offset + 2]! << 8) |
+ buffer[offset + 3]!
+ );
+}
+
+export function getInt32(
+ buffer: Uint8Array,
+ offset: number,
+ littleEndian: boolean,
+) {
+ return littleEndian
+ ? buffer[offset]! |
+ (buffer[offset + 1]! << 8) |
+ (buffer[offset + 2]! << 16) |
+ (buffer[offset + 3]! << 24)
+ : (buffer[offset]! << 24) |
+ (buffer[offset + 1]! << 16) |
+ (buffer[offset + 2]! << 8) |
+ buffer[offset + 3]!;
+}
diff --git a/libraries/no-data-view/src/int64.spec.ts b/libraries/no-data-view/src/int64.spec.ts
new file mode 100644
index 00000000..c06e997a
--- /dev/null
+++ b/libraries/no-data-view/src/int64.spec.ts
@@ -0,0 +1,181 @@
+import { describe, expect, it } from "@jest/globals";
+
+import {
+ getInt64,
+ getInt64BigEndian,
+ getInt64LittleEndian,
+ setInt64,
+ setInt64BigEndian,
+ setInt64LittleEndian,
+} from "./int64.js";
+
+describe("getInt64", () => {
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const array = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0x80]);
+ expect(getInt64LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigInt64(0, true),
+ );
+ });
+
+ it("should work for maximal value", () => {
+ const array = new Uint8Array([
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ ]);
+ expect(getInt64LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigInt64(0, true),
+ );
+ });
+
+ it("should work for middle value", () => {
+ const array = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]);
+ expect(getInt64LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigInt64(0, true),
+ );
+ });
+
+ it("should work for random value", () => {
+ const array = new Uint8Array([
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ ]);
+ expect(getInt64LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigInt64(0, true),
+ );
+ });
+ });
+
+ describe("big endian", () => {
+ it("should work for minimal value", () => {
+ const array = new Uint8Array([0x80, 0, 0, 0, 0, 0, 0, 0]);
+ expect(getInt64BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigInt64(0, false),
+ );
+ });
+
+ it("should work for maximal value", () => {
+ const array = new Uint8Array([
+ 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ ]);
+ expect(getInt64BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigInt64(0, false),
+ );
+ });
+
+ it("should work for middle value", () => {
+ const array = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]);
+ expect(getInt64BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigInt64(0, false),
+ );
+ });
+
+ it("should work for random value", () => {
+ const array = new Uint8Array([
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ ]);
+ expect(getInt64BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigInt64(0, false),
+ );
+ });
+ });
+
+ it("should work for selected endianness", () => {
+ const array = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
+ expect(getInt64(array, 0, false)).toBe(
+ new DataView(array.buffer).getBigInt64(0, false),
+ );
+ expect(getInt64(array, 0, true)).toBe(
+ new DataView(array.buffer).getBigInt64(0, true),
+ );
+ });
+});
+
+describe("setInt64", () => {
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const expected = new Uint8Array(8);
+ new DataView(expected.buffer).setBigInt64(
+ 0,
+ -0x8000_0000_0000_0000n,
+ true,
+ );
+ const actual = new Uint8Array(8);
+ setInt64LittleEndian(actual, 0, -0x8000_0000_0000_0000n);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for maximal value", () => {
+ const expected = new Uint8Array(8);
+ new DataView(expected.buffer).setBigInt64(
+ 0,
+ 0x7fff_ffff_ffff_ffffn,
+ true,
+ );
+ const actual = new Uint8Array(8);
+ setInt64LittleEndian(actual, 0, 0x7fff_ffff_ffff_ffffn);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for middle value", () => {
+ const expected = new Uint8Array(8);
+ new DataView(expected.buffer).setBigInt64(0, 0n, true);
+ const actual = new Uint8Array(8);
+ setInt64LittleEndian(actual, 0, 0n);
+ expect(actual).toEqual(expected);
+ });
+ });
+
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const expected = new Uint8Array(8);
+ new DataView(expected.buffer).setBigInt64(
+ 0,
+ -0x8000_0000_0000_0000n,
+ false,
+ );
+ const actual = new Uint8Array(8);
+ setInt64BigEndian(actual, 0, -0x8000_0000_0000_0000n);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for maximal value", () => {
+ const expected = new Uint8Array(8);
+ new DataView(expected.buffer).setBigInt64(
+ 0,
+ 0x7fff_ffff_ffff_ffffn,
+ false,
+ );
+ const actual = new Uint8Array(8);
+ setInt64BigEndian(actual, 0, 0x7fff_ffff_ffff_ffffn);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for middle value", () => {
+ const expected = new Uint8Array(8);
+ new DataView(expected.buffer).setBigInt64(0, 0n, false);
+ const actual = new Uint8Array(8);
+ setInt64BigEndian(actual, 0, 0n);
+ expect(actual).toEqual(expected);
+ });
+ });
+
+ it("should work for selected endianness", () => {
+ const expected = new Uint8Array(8);
+ const actual = new Uint8Array(8);
+
+ new DataView(expected.buffer).setBigInt64(
+ 0,
+ 0x7fff_ffff_ffff_ffffn,
+ false,
+ );
+ setInt64(actual, 0, 0x7fff_ffff_ffff_ffffn, false);
+ expect(actual).toEqual(expected);
+
+ new DataView(expected.buffer).setBigInt64(
+ 0,
+ 0x7fff_ffff_ffff_ffffn,
+ true,
+ );
+ setInt64(actual, 0, 0x7fff_ffff_ffff_ffffn, true);
+ expect(actual).toEqual(expected);
+ });
+});
diff --git a/libraries/no-data-view/src/int64.ts b/libraries/no-data-view/src/int64.ts
new file mode 100644
index 00000000..209f8843
--- /dev/null
+++ b/libraries/no-data-view/src/int64.ts
@@ -0,0 +1,109 @@
+export function getInt64LittleEndian(
+ buffer: Uint8Array,
+ offset: number,
+): bigint {
+ return (
+ BigInt(buffer[offset]!) |
+ (BigInt(buffer[offset + 1]!) << 8n) |
+ (BigInt(buffer[offset + 2]!) << 16n) |
+ (BigInt(buffer[offset + 3]!) << 24n) |
+ (BigInt(buffer[offset + 4]!) << 32n) |
+ (BigInt(buffer[offset + 5]!) << 40n) |
+ (BigInt(buffer[offset + 6]!) << 48n) |
+ (BigInt(buffer[offset + 7]! << 24) << 32n)
+ );
+}
+
+export function getInt64BigEndian(buffer: Uint8Array, offset: number): bigint {
+ return (
+ (BigInt(buffer[offset]! << 24) << 32n) |
+ (BigInt(buffer[offset + 1]!) << 48n) |
+ (BigInt(buffer[offset + 2]!) << 40n) |
+ (BigInt(buffer[offset + 3]!) << 32n) |
+ (BigInt(buffer[offset + 4]!) << 24n) |
+ (BigInt(buffer[offset + 5]!) << 16n) |
+ (BigInt(buffer[offset + 6]!) << 8n) |
+ BigInt(buffer[offset + 7]!)
+ );
+}
+
+export function getInt64(
+ buffer: Uint8Array,
+ offset: number,
+ littleEndian: boolean,
+): bigint {
+ return littleEndian
+ ? BigInt(buffer[offset]!) |
+ (BigInt(buffer[offset + 1]!) << 8n) |
+ (BigInt(buffer[offset + 2]!) << 16n) |
+ (BigInt(buffer[offset + 3]!) << 24n) |
+ (BigInt(buffer[offset + 4]!) << 32n) |
+ (BigInt(buffer[offset + 5]!) << 40n) |
+ (BigInt(buffer[offset + 6]!) << 48n) |
+ (BigInt(buffer[offset + 7]! << 24) << 32n)
+ : (BigInt(buffer[offset]! << 24) << 32n) |
+ (BigInt(buffer[offset + 1]!) << 48n) |
+ (BigInt(buffer[offset + 2]!) << 40n) |
+ (BigInt(buffer[offset + 3]!) << 32n) |
+ (BigInt(buffer[offset + 4]!) << 24n) |
+ (BigInt(buffer[offset + 5]!) << 16n) |
+ (BigInt(buffer[offset + 6]!) << 8n) |
+ BigInt(buffer[offset + 7]!);
+}
+
+export function setInt64LittleEndian(
+ buffer: Uint8Array,
+ offset: number,
+ value: bigint,
+): void {
+ buffer[offset] = Number(value & 0xffn);
+ buffer[offset + 1] = Number((value >> 8n) & 0xffn);
+ buffer[offset + 2] = Number((value >> 16n) & 0xffn);
+ buffer[offset + 3] = Number((value >> 24n) & 0xffn);
+ buffer[offset + 4] = Number((value >> 32n) & 0xffn);
+ buffer[offset + 5] = Number((value >> 40n) & 0xffn);
+ buffer[offset + 6] = Number((value >> 48n) & 0xffn);
+ buffer[offset + 7] = Number((value >> 56n) & 0xffn);
+}
+
+export function setInt64BigEndian(
+ buffer: Uint8Array,
+ offset: number,
+ value: bigint,
+): void {
+ buffer[offset] = Number((value >> 56n) & 0xffn);
+ buffer[offset + 1] = Number((value >> 48n) & 0xffn);
+ buffer[offset + 2] = Number((value >> 40n) & 0xffn);
+ buffer[offset + 3] = Number((value >> 32n) & 0xffn);
+ buffer[offset + 4] = Number((value >> 24n) & 0xffn);
+ buffer[offset + 5] = Number((value >> 16n) & 0xffn);
+ buffer[offset + 6] = Number((value >> 8n) & 0xffn);
+ buffer[offset + 7] = Number(value & 0xffn);
+}
+
+export function setInt64(
+ buffer: Uint8Array,
+ offset: number,
+ value: bigint,
+ littleEndian: boolean,
+): void {
+ if (littleEndian) {
+ buffer[offset] = Number(value & 0xffn);
+ buffer[offset + 1] = Number((value >> 8n) & 0xffn);
+ buffer[offset + 2] = Number((value >> 16n) & 0xffn);
+ buffer[offset + 3] = Number((value >> 24n) & 0xffn);
+ buffer[offset + 4] = Number((value >> 32n) & 0xffn);
+ buffer[offset + 5] = Number((value >> 40n) & 0xffn);
+ buffer[offset + 6] = Number((value >> 48n) & 0xffn);
+ buffer[offset + 7] = Number((value >> 56n) & 0xffn);
+ } else {
+ buffer[offset] = Number((value >> 56n) & 0xffn);
+ buffer[offset + 1] = Number((value >> 48n) & 0xffn);
+ buffer[offset + 2] = Number((value >> 40n) & 0xffn);
+ buffer[offset + 3] = Number((value >> 32n) & 0xffn);
+ buffer[offset + 4] = Number((value >> 24n) & 0xffn);
+ buffer[offset + 5] = Number((value >> 16n) & 0xffn);
+ buffer[offset + 6] = Number((value >> 8n) & 0xffn);
+ buffer[offset + 7] = Number(value & 0xffn);
+ }
+}
diff --git a/libraries/no-data-view/src/int8.spec.ts b/libraries/no-data-view/src/int8.spec.ts
new file mode 100644
index 00000000..1e60ca00
--- /dev/null
+++ b/libraries/no-data-view/src/int8.spec.ts
@@ -0,0 +1,45 @@
+import { describe, expect, it } from "@jest/globals";
+import { getInt8, setInt8 } from "./int8.js";
+
+describe("getInt8", () => {
+ it("should work for minimal value", () => {
+ const array = new Uint8Array([0x80]);
+ expect(getInt8(array, 0)).toBe(new DataView(array.buffer).getInt8(0));
+ });
+
+ it("should work for maximal value", () => {
+ const array = new Uint8Array([0x7f]);
+ expect(getInt8(array, 0)).toBe(new DataView(array.buffer).getInt8(0));
+ });
+
+ it("should work for middle value", () => {
+ const array = new Uint8Array([0]);
+ expect(getInt8(array, 0)).toBe(new DataView(array.buffer).getInt8(0));
+ });
+});
+
+describe("setInt8", () => {
+ it("should work for minimal value", () => {
+ const expected = new Uint8Array(1);
+ new DataView(expected.buffer).setInt8(0, -0x80);
+ const actual = new Uint8Array(1);
+ setInt8(actual, 0, -0x80);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for maximal value", () => {
+ const expected = new Uint8Array(1);
+ new DataView(expected.buffer).setInt8(0, 0x7f);
+ const actual = new Uint8Array(1);
+ setInt8(actual, 0, 0x7f);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for middle value", () => {
+ const expected = new Uint8Array(1);
+ new DataView(expected.buffer).setInt8(0, 0);
+ const actual = new Uint8Array(1);
+ setInt8(actual, 0, 0);
+ expect(actual).toEqual(expected);
+ });
+});
diff --git a/libraries/no-data-view/src/int8.ts b/libraries/no-data-view/src/int8.ts
new file mode 100644
index 00000000..191d6b6c
--- /dev/null
+++ b/libraries/no-data-view/src/int8.ts
@@ -0,0 +1,11 @@
+export function getInt8(buffer: Uint8Array, offset: number): number {
+ return (buffer[offset]! << 24) >> 24;
+}
+
+export function setInt8(
+ buffer: Uint8Array,
+ offset: number,
+ value: number,
+): void {
+ buffer[offset] = value >>> 0;
+}
diff --git a/libraries/no-data-view/src/uint16.spec.ts b/libraries/no-data-view/src/uint16.spec.ts
new file mode 100644
index 00000000..c86b33bc
--- /dev/null
+++ b/libraries/no-data-view/src/uint16.spec.ts
@@ -0,0 +1,79 @@
+import { describe, expect, it } from "@jest/globals";
+
+import {
+ getUint16,
+ getUint16BigEndian,
+ getUint16LittleEndian,
+} from "./uint16.js";
+
+describe("getUint16", () => {
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const array = new Uint8Array([0, 0]);
+ expect(getUint16LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint16(0, true),
+ );
+ });
+
+ it("should work for maximal value", () => {
+ const array = new Uint8Array([255, 255]);
+ expect(getUint16LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint16(0, true),
+ );
+ });
+
+ it("should work for middle value", () => {
+ const array = new Uint8Array([0, 128]);
+ expect(getUint16LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint16(0, true),
+ );
+ });
+
+ it("should work for random value", () => {
+ const array = new Uint8Array([1, 2]);
+ expect(getUint16LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint16(0, true),
+ );
+ });
+ });
+
+ describe("big endian", () => {
+ it("should work for minimal value", () => {
+ const array = new Uint8Array([0, 0]);
+ expect(getUint16BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint16(0, false),
+ );
+ });
+
+ it("should work for maximal value", () => {
+ const array = new Uint8Array([255, 255]);
+ expect(getUint16BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint16(0, false),
+ );
+ });
+
+ it("should work for middle value", () => {
+ const array = new Uint8Array([128, 255]);
+ expect(getUint16BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint16(0, false),
+ );
+ });
+
+ it("should work for random value", () => {
+ const array = new Uint8Array([1, 2]);
+ expect(getUint16BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint16(0, false),
+ );
+ });
+ });
+
+ it("should work for selected endianness", () => {
+ const array = new Uint8Array([1, 2]);
+ expect(getUint16(array, 0, false)).toBe(
+ new DataView(array.buffer).getUint16(0, false),
+ );
+ expect(getUint16(array, 0, true)).toBe(
+ new DataView(array.buffer).getUint16(0, true),
+ );
+ });
+});
diff --git a/libraries/no-data-view/src/uint16.ts b/libraries/no-data-view/src/uint16.ts
new file mode 100644
index 00000000..7422a109
--- /dev/null
+++ b/libraries/no-data-view/src/uint16.ts
@@ -0,0 +1,20 @@
+export function getUint16LittleEndian(
+ buffer: Uint8Array,
+ offset: number,
+): number {
+ return buffer[offset]! | (buffer[offset + 1]! << 8);
+}
+
+export function getUint16BigEndian(buffer: Uint8Array, offset: number): number {
+ return (buffer[offset]! << 8) | buffer[offset + 1]!;
+}
+
+export function getUint16(
+ buffer: Uint8Array,
+ offset: number,
+ littleEndian: boolean,
+) {
+ return littleEndian
+ ? buffer[offset]! | (buffer[offset + 1]! << 8)
+ : buffer[offset + 1]! | (buffer[offset]! << 8);
+}
diff --git a/libraries/no-data-view/src/uint32.spec.ts b/libraries/no-data-view/src/uint32.spec.ts
new file mode 100644
index 00000000..b4afdb5c
--- /dev/null
+++ b/libraries/no-data-view/src/uint32.spec.ts
@@ -0,0 +1,149 @@
+import { describe, expect, it } from "@jest/globals";
+
+import {
+ getUint32,
+ getUint32BigEndian,
+ getUint32LittleEndian,
+ setUint32,
+ setUint32BigEndian,
+ setUint32LittleEndian,
+} from "./uint32.js";
+
+describe("getUint32", () => {
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const array = new Uint8Array([0, 0, 0, 0]);
+ expect(getUint32LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint32(0, true),
+ );
+ });
+
+ it("should work for maximal value", () => {
+ const array = new Uint8Array([255, 255, 255, 255]);
+ expect(getUint32LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint32(0, true),
+ );
+ });
+
+ it("should work for middle value", () => {
+ const array = new Uint8Array([0, 0, 0, 128]);
+ expect(getUint32LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint32(0, true),
+ );
+ });
+
+ it("should work for random value", () => {
+ const array = new Uint8Array([1, 2, 3, 4]);
+ expect(getUint32LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint32(0, true),
+ );
+ });
+ });
+
+ describe("big endian", () => {
+ it("should work for minimal value", () => {
+ const array = new Uint8Array([0, 0, 0, 0]);
+ expect(getUint32BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint32(0, false),
+ );
+ });
+
+ it("should work for maximal value", () => {
+ const array = new Uint8Array([255, 255, 255, 255]);
+ expect(getUint32BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint32(0, false),
+ );
+ });
+
+ it("should work for middle value", () => {
+ const array = new Uint8Array([128, 0, 0, 0]);
+ expect(getUint32BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint32(0, false),
+ );
+ });
+
+ it("should work for random value", () => {
+ const array = new Uint8Array([1, 2, 3, 4]);
+ expect(getUint32BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getUint32(0, false),
+ );
+ });
+ });
+
+ it("should work for selected endianness", () => {
+ const array = new Uint8Array([1, 2, 3, 4]);
+ expect(getUint32(array, 0, false)).toBe(
+ new DataView(array.buffer).getUint32(0, false),
+ );
+ expect(getUint32(array, 0, true)).toBe(
+ new DataView(array.buffer).getUint32(0, true),
+ );
+ });
+});
+
+describe("setUint32", () => {
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const expected = new Uint8Array(4);
+ new DataView(expected.buffer).setUint32(0, 0, true);
+ const actual = new Uint8Array(4);
+ setUint32LittleEndian(actual, 0, 0);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for maximal value", () => {
+ const expected = new Uint8Array(4);
+ new DataView(expected.buffer).setUint32(0, 0xffff_ffff, true);
+ const actual = new Uint8Array(4);
+ setUint32LittleEndian(actual, 0, 0xffff_ffff);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for middle value", () => {
+ const expected = new Uint8Array(4);
+ new DataView(expected.buffer).setUint32(0, 0x8000_0000, true);
+ const actual = new Uint8Array(4);
+ setUint32LittleEndian(actual, 0, 0x8000_0000);
+ expect(actual).toEqual(expected);
+ });
+ });
+
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const expected = new Uint8Array(4);
+ new DataView(expected.buffer).setUint32(0, 0, false);
+ const actual = new Uint8Array(4);
+ setUint32BigEndian(actual, 0, 0);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for maximal value", () => {
+ const expected = new Uint8Array(4);
+ new DataView(expected.buffer).setUint32(0, 0xffff_ffff, false);
+ const actual = new Uint8Array(4);
+ setUint32BigEndian(actual, 0, 0xffff_ffff);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for middle value", () => {
+ const expected = new Uint8Array(4);
+ new DataView(expected.buffer).setUint32(0, 0x8000_0000, false);
+ const actual = new Uint8Array(4);
+ setUint32BigEndian(actual, 0, 0x8000_0000);
+ expect(actual).toEqual(expected);
+ });
+ });
+
+ it("should work for selected endianness", () => {
+ const expected = new Uint8Array(4);
+ const actual = new Uint8Array(4);
+
+ new DataView(expected.buffer).setUint32(0, 0xffff_ffff, false);
+ setUint32(actual, 0, 0xffff_ffff, false);
+ expect(actual).toEqual(expected);
+
+ new DataView(expected.buffer).setUint32(0, 0xffff_ffff, true);
+ setUint32(actual, 0, 0xffff_ffff, true);
+ expect(actual).toEqual(expected);
+ });
+});
diff --git a/libraries/no-data-view/src/uint32.ts b/libraries/no-data-view/src/uint32.ts
new file mode 100644
index 00000000..287aaef2
--- /dev/null
+++ b/libraries/no-data-view/src/uint32.ts
@@ -0,0 +1,81 @@
+export function getUint32LittleEndian(
+ buffer: Uint8Array,
+ offset: number,
+): number {
+ return (
+ (buffer[offset]! |
+ (buffer[offset + 1]! << 8) |
+ (buffer[offset + 2]! << 16) |
+ (buffer[offset + 3]! << 24)) >>>
+ 0
+ );
+}
+
+export function getUint32BigEndian(buffer: Uint8Array, offset: number): number {
+ return (
+ ((buffer[offset]! << 24) |
+ (buffer[offset + 1]! << 16) |
+ (buffer[offset + 2]! << 8) |
+ buffer[offset + 3]!) >>>
+ 0
+ );
+}
+
+export function getUint32(
+ buffer: Uint8Array,
+ offset: number,
+ littleEndian: boolean,
+) {
+ return littleEndian
+ ? (buffer[offset]! |
+ (buffer[offset + 1]! << 8) |
+ (buffer[offset + 2]! << 16) |
+ (buffer[offset + 3]! << 24)) >>>
+ 0
+ : ((buffer[offset]! << 24) |
+ (buffer[offset + 1]! << 16) |
+ (buffer[offset + 2]! << 8) |
+ buffer[offset + 3]!) >>>
+ 0;
+}
+
+export function setUint32LittleEndian(
+ buffer: Uint8Array,
+ offset: number,
+ value: number,
+): void {
+ buffer[offset] = value & 0xff;
+ buffer[offset + 1] = (value >> 8) & 0xff;
+ buffer[offset + 2] = (value >> 16) & 0xff;
+ buffer[offset + 3] = (value >> 24) & 0xff;
+}
+
+export function setUint32BigEndian(
+ buffer: Uint8Array,
+ offset: number,
+ value: number,
+): void {
+ buffer[offset] = (value >> 24) & 0xff;
+ buffer[offset + 1] = (value >> 16) & 0xff;
+ buffer[offset + 2] = (value >> 8) & 0xff;
+ buffer[offset + 3] = value & 0xff;
+}
+
+export function setUint32(
+ buffer: Uint8Array,
+ offset: number,
+ value: number,
+ littleEndian: boolean,
+): void {
+ if (littleEndian) {
+ buffer[offset] = value & 0xff;
+ buffer[offset + 1] = (value >> 8) & 0xff;
+ buffer[offset + 2] = (value >> 16) & 0xff;
+ buffer[offset + 3] = (value >> 24) & 0xff;
+ } else {
+ buffer[offset] = (value >> 24) & 0xff;
+ buffer[offset + 1] = (value >> 16) & 0xff;
+ buffer[offset + 2] = (value >> 8) & 0xff;
+ buffer[offset + 3] = value & 0xff;
+ }
+}
diff --git a/libraries/no-data-view/src/uint64.spec.ts b/libraries/no-data-view/src/uint64.spec.ts
new file mode 100644
index 00000000..89e2ed95
--- /dev/null
+++ b/libraries/no-data-view/src/uint64.spec.ts
@@ -0,0 +1,181 @@
+import { describe, expect, it } from "@jest/globals";
+
+import {
+ getUint64,
+ getUint64BigEndian,
+ getUint64LittleEndian,
+ setUint64,
+ setUint64BigEndian,
+ setUint64LittleEndian,
+} from "./uint64.js";
+
+describe("getUint64", () => {
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const array = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]);
+ expect(getUint64LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigUint64(0, true),
+ );
+ });
+
+ it("should work for maximal value", () => {
+ const array = new Uint8Array([
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ ]);
+ expect(getUint64LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigUint64(0, true),
+ );
+ });
+
+ it("should work for middle value", () => {
+ const array = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0x80]);
+ expect(getUint64LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigUint64(0, true),
+ );
+ });
+
+ it("should work for random value", () => {
+ const array = new Uint8Array([
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ ]);
+ expect(getUint64LittleEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigUint64(0, true),
+ );
+ });
+ });
+
+ describe("big endian", () => {
+ it("should work for minimal value", () => {
+ const array = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0]);
+ expect(getUint64BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigUint64(0, false),
+ );
+ });
+
+ it("should work for maximal value", () => {
+ const array = new Uint8Array([
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ ]);
+ expect(getUint64BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigUint64(0, false),
+ );
+ });
+
+ it("should work for middle value", () => {
+ const array = new Uint8Array([0x80, 0, 0, 0, 0, 0, 0, 0]);
+ expect(getUint64BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigUint64(0, false),
+ );
+ });
+
+ it("should work for random value", () => {
+ const array = new Uint8Array([
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ ]);
+ expect(getUint64BigEndian(array, 0)).toBe(
+ new DataView(array.buffer).getBigUint64(0, false),
+ );
+ });
+ });
+
+ it("should work for selected endianness", () => {
+ const array = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
+ expect(getUint64(array, 0, false)).toBe(
+ new DataView(array.buffer).getBigUint64(0, false),
+ );
+ expect(getUint64(array, 0, true)).toBe(
+ new DataView(array.buffer).getBigUint64(0, true),
+ );
+ });
+});
+
+describe("setUint64", () => {
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const expected = new Uint8Array(8);
+ new DataView(expected.buffer).setBigUint64(0, 0n, true);
+ const actual = new Uint8Array(8);
+ setUint64LittleEndian(actual, 0, 0n);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for maximal value", () => {
+ const expected = new Uint8Array(8);
+ new DataView(expected.buffer).setBigUint64(
+ 0,
+ 0xffff_ffff_ffff_ffffn,
+ true,
+ );
+ const actual = new Uint8Array(8);
+ setUint64LittleEndian(actual, 0, 0xffff_ffff_ffff_ffffn);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for middle value", () => {
+ const expected = new Uint8Array(8);
+ new DataView(expected.buffer).setBigUint64(
+ 0,
+ 0x8000_0000_0000_0000n,
+ true,
+ );
+ const actual = new Uint8Array(8);
+ setUint64LittleEndian(actual, 0, 0x8000_0000_0000_0000n);
+ expect(actual).toEqual(expected);
+ });
+ });
+
+ describe("little endian", () => {
+ it("should work for minimal value", () => {
+ const expected = new Uint8Array(8);
+ new DataView(expected.buffer).setBigUint64(0, 0n, false);
+ const actual = new Uint8Array(8);
+ setUint64BigEndian(actual, 0, 0n);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for maximal value", () => {
+ const expected = new Uint8Array(8);
+ new DataView(expected.buffer).setBigUint64(
+ 0,
+ 0xffff_ffff_ffff_ffffn,
+ false,
+ );
+ const actual = new Uint8Array(8);
+ setUint64BigEndian(actual, 0, 0xffff_ffff_ffff_ffffn);
+ expect(actual).toEqual(expected);
+ });
+
+ it("should work for middle value", () => {
+ const expected = new Uint8Array(8);
+ new DataView(expected.buffer).setBigUint64(
+ 0,
+ 0x8000_0000_0000_0000n,
+ false,
+ );
+ const actual = new Uint8Array(8);
+ setUint64BigEndian(actual, 0, 0x8000_0000_0000_0000n);
+ expect(actual).toEqual(expected);
+ });
+ });
+
+ it("should work for selected endianness", () => {
+ const expected = new Uint8Array(8);
+ const actual = new Uint8Array(8);
+
+ new DataView(expected.buffer).setBigUint64(
+ 0,
+ 0xffff_ffff_ffff_ffffn,
+ false,
+ );
+ setUint64(actual, 0, 0xffff_ffff_ffff_ffffn, false);
+ expect(actual).toEqual(expected);
+
+ new DataView(expected.buffer).setBigUint64(
+ 0,
+ 0xffff_ffff_ffff_ffffn,
+ true,
+ );
+ setUint64(actual, 0, 0xffff_ffff_ffff_ffffn, true);
+ expect(actual).toEqual(expected);
+ });
+});
diff --git a/libraries/no-data-view/src/uint64.ts b/libraries/no-data-view/src/uint64.ts
new file mode 100644
index 00000000..e5a33916
--- /dev/null
+++ b/libraries/no-data-view/src/uint64.ts
@@ -0,0 +1,109 @@
+export function getUint64LittleEndian(
+ buffer: Uint8Array,
+ offset: number,
+): bigint {
+ return (
+ BigInt(buffer[offset]!) |
+ (BigInt(buffer[offset + 1]!) << 8n) |
+ (BigInt(buffer[offset + 2]!) << 16n) |
+ (BigInt(buffer[offset + 3]!) << 24n) |
+ (BigInt(buffer[offset + 4]!) << 32n) |
+ (BigInt(buffer[offset + 5]!) << 40n) |
+ (BigInt(buffer[offset + 6]!) << 48n) |
+ (BigInt(buffer[offset + 7]!) << 56n)
+ );
+}
+
+export function getUint64BigEndian(buffer: Uint8Array, offset: number): bigint {
+ return (
+ (BigInt(buffer[offset]!) << 56n) |
+ (BigInt(buffer[offset + 1]!) << 48n) |
+ (BigInt(buffer[offset + 2]!) << 40n) |
+ (BigInt(buffer[offset + 3]!) << 32n) |
+ (BigInt(buffer[offset + 4]!) << 24n) |
+ (BigInt(buffer[offset + 5]!) << 16n) |
+ (BigInt(buffer[offset + 6]!) << 8n) |
+ BigInt(buffer[offset + 7]!)
+ );
+}
+
+export function getUint64(
+ buffer: Uint8Array,
+ offset: number,
+ littleEndian: boolean,
+): bigint {
+ return littleEndian
+ ? BigInt(buffer[offset]!) |
+ (BigInt(buffer[offset + 1]!) << 8n) |
+ (BigInt(buffer[offset + 2]!) << 16n) |
+ (BigInt(buffer[offset + 3]!) << 24n) |
+ (BigInt(buffer[offset + 4]!) << 32n) |
+ (BigInt(buffer[offset + 5]!) << 40n) |
+ (BigInt(buffer[offset + 6]!) << 48n) |
+ (BigInt(buffer[offset + 7]!) << 56n)
+ : (BigInt(buffer[offset]!) << 56n) |
+ (BigInt(buffer[offset + 1]!) << 48n) |
+ (BigInt(buffer[offset + 2]!) << 40n) |
+ (BigInt(buffer[offset + 3]!) << 32n) |
+ (BigInt(buffer[offset + 4]!) << 24n) |
+ (BigInt(buffer[offset + 5]!) << 16n) |
+ (BigInt(buffer[offset + 6]!) << 8n) |
+ BigInt(buffer[offset + 7]!);
+}
+
+export function setUint64LittleEndian(
+ buffer: Uint8Array,
+ offset: number,
+ value: bigint,
+): void {
+ buffer[offset] = Number(value & 0xffn);
+ buffer[offset + 1] = Number((value >> 8n) & 0xffn);
+ buffer[offset + 2] = Number((value >> 16n) & 0xffn);
+ buffer[offset + 3] = Number((value >> 24n) & 0xffn);
+ buffer[offset + 4] = Number((value >> 32n) & 0xffn);
+ buffer[offset + 5] = Number((value >> 40n) & 0xffn);
+ buffer[offset + 6] = Number((value >> 48n) & 0xffn);
+ buffer[offset + 7] = Number((value >> 56n) & 0xffn);
+}
+
+export function setUint64BigEndian(
+ buffer: Uint8Array,
+ offset: number,
+ value: bigint,
+): void {
+ buffer[offset] = Number((value >> 56n) & 0xffn);
+ buffer[offset + 1] = Number((value >> 48n) & 0xffn);
+ buffer[offset + 2] = Number((value >> 40n) & 0xffn);
+ buffer[offset + 3] = Number((value >> 32n) & 0xffn);
+ buffer[offset + 4] = Number((value >> 24n) & 0xffn);
+ buffer[offset + 5] = Number((value >> 16n) & 0xffn);
+ buffer[offset + 6] = Number((value >> 8n) & 0xffn);
+ buffer[offset + 7] = Number(value & 0xffn);
+}
+
+export function setUint64(
+ buffer: Uint8Array,
+ offset: number,
+ value: bigint,
+ littleEndian: boolean,
+): void {
+ if (littleEndian) {
+ buffer[offset] = Number(value & 0xffn);
+ buffer[offset + 1] = Number((value >> 8n) & 0xffn);
+ buffer[offset + 2] = Number((value >> 16n) & 0xffn);
+ buffer[offset + 3] = Number((value >> 24n) & 0xffn);
+ buffer[offset + 4] = Number((value >> 32n) & 0xffn);
+ buffer[offset + 5] = Number((value >> 40n) & 0xffn);
+ buffer[offset + 6] = Number((value >> 48n) & 0xffn);
+ buffer[offset + 7] = Number((value >> 56n) & 0xffn);
+ } else {
+ buffer[offset] = Number((value >> 56n) & 0xffn);
+ buffer[offset + 1] = Number((value >> 48n) & 0xffn);
+ buffer[offset + 2] = Number((value >> 40n) & 0xffn);
+ buffer[offset + 3] = Number((value >> 32n) & 0xffn);
+ buffer[offset + 4] = Number((value >> 24n) & 0xffn);
+ buffer[offset + 5] = Number((value >> 16n) & 0xffn);
+ buffer[offset + 6] = Number((value >> 8n) & 0xffn);
+ buffer[offset + 7] = Number(value & 0xffn);
+ }
+}
diff --git a/libraries/no-data-view/tsconfig.build.json b/libraries/no-data-view/tsconfig.build.json
new file mode 100644
index 00000000..2cb23249
--- /dev/null
+++ b/libraries/no-data-view/tsconfig.build.json
@@ -0,0 +1,3 @@
+{
+ "extends": "./node_modules/@yume-chan/tsconfig/tsconfig.base.json"
+}
diff --git a/libraries/no-data-view/tsconfig.json b/libraries/no-data-view/tsconfig.json
new file mode 100644
index 00000000..85fc5a7a
--- /dev/null
+++ b/libraries/no-data-view/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "references": [
+ {
+ "path": "./tsconfig.test.json"
+ },
+ {
+ "path": "./tsconfig.build.json"
+ },
+ ]
+}
diff --git a/libraries/no-data-view/tsconfig.test.json b/libraries/no-data-view/tsconfig.test.json
new file mode 100644
index 00000000..e987f757
--- /dev/null
+++ b/libraries/no-data-view/tsconfig.test.json
@@ -0,0 +1,8 @@
+{
+ "extends": "./tsconfig.build.json",
+ "compilerOptions": {
+ "types": [
+ ],
+ },
+ "exclude": []
+}
diff --git a/libraries/pcm-player/package.json b/libraries/pcm-player/package.json
index 8477fbd4..86af9d0e 100644
--- a/libraries/pcm-player/package.json
+++ b/libraries/pcm-player/package.json
@@ -29,9 +29,7 @@
"lint": "run-eslint && prettier src/**/*.ts --write --tab-width 4",
"prepublishOnly": "npm run build"
},
- "dependencies": {
- "tslib": "^2.6.2"
- },
+ "dependencies": {},
"devDependencies": {
"@jest/globals": "^30.0.0-alpha.3",
"@types/audioworklet": "^0.0.54",
diff --git a/libraries/scrcpy-decoder-tinyh264/package.json b/libraries/scrcpy-decoder-tinyh264/package.json
index 0e432d23..8abe7ebf 100644
--- a/libraries/scrcpy-decoder-tinyh264/package.json
+++ b/libraries/scrcpy-decoder-tinyh264/package.json
@@ -39,7 +39,6 @@
"@yume-chan/scrcpy": "workspace:^0.0.23",
"@yume-chan/stream-extra": "workspace:^0.0.23",
"tinyh264": "^0.0.7",
- "tslib": "^2.6.2",
"yuv-buffer": "^1.0.0",
"yuv-canvas": "^1.2.11"
},
diff --git a/libraries/scrcpy-decoder-webcodecs/package.json b/libraries/scrcpy-decoder-webcodecs/package.json
index 5f7fe85b..f1967be2 100644
--- a/libraries/scrcpy-decoder-webcodecs/package.json
+++ b/libraries/scrcpy-decoder-webcodecs/package.json
@@ -34,10 +34,10 @@
},
"dependencies": {
"@yume-chan/event": "workspace:^0.0.23",
+ "@yume-chan/no-data-view": "workspace:^0.0.23",
"@yume-chan/scrcpy": "workspace:^0.0.23",
"@yume-chan/scrcpy-decoder-tinyh264": "workspace:^0.0.23",
- "@yume-chan/stream-extra": "workspace:^0.0.23",
- "tslib": "^2.6.2"
+ "@yume-chan/stream-extra": "workspace:^0.0.23"
},
"devDependencies": {
"@jest/globals": "^30.0.0-alpha.3",
diff --git a/libraries/scrcpy-decoder-webcodecs/src/index.ts b/libraries/scrcpy-decoder-webcodecs/src/index.ts
index cb320d40..3732585e 100644
--- a/libraries/scrcpy-decoder-webcodecs/src/index.ts
+++ b/libraries/scrcpy-decoder-webcodecs/src/index.ts
@@ -8,6 +8,7 @@ import {
h264ParseConfiguration,
h265ParseConfiguration,
} from "@yume-chan/scrcpy";
+import { getUint32LittleEndian } from "@yume-chan/no-data-view";
import type {
ScrcpyVideoDecoder,
ScrcpyVideoDecoderCapability,
@@ -22,15 +23,6 @@ function toHex(value: number) {
return value.toString(16).padStart(2, "0").toUpperCase();
}
-function toUint32Le(data: Uint8Array, offset: number) {
- return (
- data[offset]! |
- (data[offset + 1]! << 8) |
- (data[offset + 2]! << 16) |
- (data[offset + 3]! << 24)
- );
-}
-
export class WebCodecsDecoder implements ScrcpyVideoDecoder {
static isSupported() {
return typeof globalThis.VideoDecoder !== "undefined";
@@ -137,74 +129,83 @@ export class WebCodecsDecoder implements ScrcpyVideoDecoder {
this.#animationFrameId = requestAnimationFrame(this.#onFramePresented);
};
+ #configureH264(data: Uint8Array) {
+ const {
+ profileIndex,
+ constraintSet,
+ levelIndex,
+ croppedWidth,
+ croppedHeight,
+ } = h264ParseConfiguration(data);
+
+ this.#canvas.width = croppedWidth;
+ this.#canvas.height = croppedHeight;
+ this.#sizeChanged.fire({
+ width: croppedWidth,
+ height: croppedHeight,
+ });
+
+ // https://www.rfc-editor.org/rfc/rfc6381#section-3.3
+ // ISO Base Media File Format Name Space
+ const codec =
+ "avc1." +
+ toHex(profileIndex) +
+ toHex(constraintSet) +
+ toHex(levelIndex);
+ this.#decoder.configure({
+ codec: codec,
+ optimizeForLatency: true,
+ });
+ }
+
+ #configureH265(data: Uint8Array) {
+ const {
+ generalProfileSpace,
+ generalProfileIndex,
+ generalProfileCompatibilitySet,
+ generalTierFlag,
+ generalLevelIndex,
+ generalConstraintSet,
+ croppedWidth,
+ croppedHeight,
+ } = h265ParseConfiguration(data);
+
+ this.#canvas.width = croppedWidth;
+ this.#canvas.height = croppedHeight;
+ this.#sizeChanged.fire({
+ width: croppedWidth,
+ height: croppedHeight,
+ });
+
+ const codec = [
+ "hev1",
+ ["", "A", "B", "C"][generalProfileSpace]! +
+ generalProfileIndex.toString(),
+ getUint32LittleEndian(generalProfileCompatibilitySet, 0).toString(
+ 16,
+ ),
+ (generalTierFlag ? "H" : "L") + generalLevelIndex.toString(),
+ getUint32LittleEndian(generalConstraintSet, 0)
+ .toString(16)
+ .toUpperCase(),
+ getUint32LittleEndian(generalConstraintSet, 4)
+ .toString(16)
+ .toUpperCase(),
+ ].join(".");
+ this.#decoder.configure({
+ codec,
+ optimizeForLatency: true,
+ });
+ }
+
#configure(data: Uint8Array) {
switch (this.#codec) {
- case ScrcpyVideoCodecId.H264: {
- const {
- profileIndex,
- constraintSet,
- levelIndex,
- croppedWidth,
- croppedHeight,
- } = h264ParseConfiguration(data);
-
- this.#canvas.width = croppedWidth;
- this.#canvas.height = croppedHeight;
- this.#sizeChanged.fire({
- width: croppedWidth,
- height: croppedHeight,
- });
-
- // https://www.rfc-editor.org/rfc/rfc6381#section-3.3
- // ISO Base Media File Format Name Space
- const codec = `avc1.${[profileIndex, constraintSet, levelIndex]
- .map(toHex)
- .join("")}`;
- this.#decoder.configure({
- codec: codec,
- optimizeForLatency: true,
- });
+ case ScrcpyVideoCodecId.H264:
+ this.#configureH264(data);
break;
- }
- case ScrcpyVideoCodecId.H265: {
- const {
- generalProfileSpace,
- generalProfileIndex,
- generalProfileCompatibilitySet,
- generalTierFlag,
- generalLevelIndex,
- generalConstraintSet,
- croppedWidth,
- croppedHeight,
- } = h265ParseConfiguration(data);
-
- this.#canvas.width = croppedWidth;
- this.#canvas.height = croppedHeight;
- this.#sizeChanged.fire({
- width: croppedWidth,
- height: croppedHeight,
- });
-
- const codec = [
- "hev1",
- ["", "A", "B", "C"][generalProfileSpace]! +
- generalProfileIndex.toString(),
- toUint32Le(generalProfileCompatibilitySet, 0).toString(16),
- (generalTierFlag ? "H" : "L") +
- generalLevelIndex.toString(),
- toUint32Le(generalConstraintSet, 0)
- .toString(16)
- .toUpperCase(),
- toUint32Le(generalConstraintSet, 4)
- .toString(16)
- .toUpperCase(),
- ].join(".");
- this.#decoder.configure({
- codec,
- optimizeForLatency: true,
- });
+ case ScrcpyVideoCodecId.H265:
+ this.#configureH265(data);
break;
- }
}
this.#config = data;
}
diff --git a/libraries/scrcpy-decoder-webcodecs/tsconfig.json b/libraries/scrcpy-decoder-webcodecs/tsconfig.json
index 85fc5a7a..04f9aba7 100644
--- a/libraries/scrcpy-decoder-webcodecs/tsconfig.json
+++ b/libraries/scrcpy-decoder-webcodecs/tsconfig.json
@@ -1,5 +1,8 @@
{
"references": [
+ {
+ "path": "../no-data-view/tsconfig.build.json"
+ },
{
"path": "./tsconfig.test.json"
},
diff --git a/libraries/scrcpy/package.json b/libraries/scrcpy/package.json
index b9fac034..7361f389 100644
--- a/libraries/scrcpy/package.json
+++ b/libraries/scrcpy/package.json
@@ -33,6 +33,7 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
+ "@yume-chan/no-data-view": "workspace:^0.0.23",
"@yume-chan/stream-extra": "workspace:^0.0.23",
"@yume-chan/struct": "workspace:^0.0.23",
"tslib": "^2.6.2"
diff --git a/libraries/scrcpy/src/options/1_16/float-to-uint16.ts b/libraries/scrcpy/src/options/1_16/float-to-uint16.ts
index 3f21625a..7986efbe 100644
--- a/libraries/scrcpy/src/options/1_16/float-to-uint16.ts
+++ b/libraries/scrcpy/src/options/1_16/float-to-uint16.ts
@@ -1,4 +1,6 @@
-import { NumberFieldDefinition, NumberFieldType } from "@yume-chan/struct";
+import { getUint16 } from "@yume-chan/no-data-view";
+import type { NumberFieldType } from "@yume-chan/struct";
+import { NumberFieldDefinition } from "@yume-chan/struct";
export function clamp(value: number, min: number, max: number): number {
if (value < min) {
@@ -16,7 +18,7 @@ export const ScrcpyFloatToUint16NumberType: NumberFieldType = {
size: 2,
signed: false,
deserialize(array, littleEndian) {
- const value = NumberFieldType.Uint16.deserialize(array, littleEndian);
+ const value = getUint16(array, 0, littleEndian);
// https://github.com/Genymobile/scrcpy/blob/1f138aef41de651668043b32c4effc2d4adbfc44/server/src/main/java/com/genymobile/scrcpy/Binary.java#L22
return value === 0xffff ? 1 : value / 0x10000;
},
@@ -24,7 +26,7 @@ export const ScrcpyFloatToUint16NumberType: NumberFieldType = {
// https://github.com/Genymobile/scrcpy/blob/1f138aef41de651668043b32c4effc2d4adbfc44/app/src/util/binary.h#L51
value = clamp(value, -1, 1);
value = value === 1 ? 0xffff : value * 0x10000;
- NumberFieldType.Uint16.serialize(dataView, offset, value, littleEndian);
+ dataView.setUint16(offset, value, littleEndian);
},
};
diff --git a/libraries/scrcpy/src/options/1_16/options.ts b/libraries/scrcpy/src/options/1_16/options.ts
index 7f416448..ef11d33e 100644
--- a/libraries/scrcpy/src/options/1_16/options.ts
+++ b/libraries/scrcpy/src/options/1_16/options.ts
@@ -5,7 +5,7 @@ import {
TransformStream,
} from "@yume-chan/stream-extra";
import type { AsyncExactReadable, ValueOrPromise } from "@yume-chan/struct";
-import { NumberFieldType, decodeUtf8 } from "@yume-chan/struct";
+import { decodeUtf8 } from "@yume-chan/struct";
import type {
ScrcpyBackOrScreenOnControlMessage,
@@ -23,6 +23,10 @@ import { ScrcpyVideoCodecId } from "../codec.js";
import type { ScrcpyDisplay, ScrcpyEncoder, ScrcpyOptions } from "../types.js";
import { toScrcpyOptionValue } from "../types.js";
+import {
+ getUint16BigEndian,
+ getUint32BigEndian,
+} from "@yume-chan/no-data-view";
import { CodecOptions } from "./codec-options.js";
import type { ScrcpyOptionsInit1_16 } from "./init.js";
import { ScrcpyLogLevel1_16, ScrcpyVideoOrientation1_16 } from "./init.js";
@@ -84,13 +88,13 @@ export class ScrcpyOptions1_16 implements ScrcpyOptions {
}
static async parseUint16BE(stream: AsyncExactReadable): Promise {
- const buffer = await stream.readExactly(NumberFieldType.Uint16.size);
- return NumberFieldType.Uint16.deserialize(buffer, false);
+ const buffer = await stream.readExactly(2);
+ return getUint16BigEndian(buffer, 0);
}
static async parseUint32BE(stream: AsyncExactReadable): Promise {
- const buffer = await stream.readExactly(NumberFieldType.Uint32.size);
- return NumberFieldType.Uint32.deserialize(buffer, false);
+ const buffer = await stream.readExactly(4);
+ return getUint32BigEndian(buffer, 0);
}
value: Required;
diff --git a/libraries/scrcpy/src/options/1_25/scroll.ts b/libraries/scrcpy/src/options/1_25/scroll.ts
index 92380f70..118ddc11 100644
--- a/libraries/scrcpy/src/options/1_25/scroll.ts
+++ b/libraries/scrcpy/src/options/1_25/scroll.ts
@@ -1,7 +1,6 @@
-import Struct, {
- NumberFieldDefinition,
- NumberFieldType,
-} from "@yume-chan/struct";
+import { getInt16 } from "@yume-chan/no-data-view";
+import type { NumberFieldType } from "@yume-chan/struct";
+import Struct, { NumberFieldDefinition } from "@yume-chan/struct";
import type { ScrcpyInjectScrollControlMessage } from "../../control/index.js";
import { ScrcpyControlMessageType } from "../../control/index.js";
@@ -12,7 +11,7 @@ export const ScrcpyFloatToInt16NumberType: NumberFieldType = {
size: 2,
signed: true,
deserialize(array, littleEndian) {
- const value = NumberFieldType.Int16.deserialize(array, littleEndian);
+ const value = getInt16(array, 0, littleEndian);
// https://github.com/Genymobile/scrcpy/blob/1f138aef41de651668043b32c4effc2d4adbfc44/server/src/main/java/com/genymobile/scrcpy/Binary.java#L34
return value === 0x7fff ? 1 : value / 0x8000;
},
@@ -20,7 +19,7 @@ export const ScrcpyFloatToInt16NumberType: NumberFieldType = {
// https://github.com/Genymobile/scrcpy/blob/1f138aef41de651668043b32c4effc2d4adbfc44/app/src/util/binary.h#L65
value = clamp(value, -1, 1);
value = value === 1 ? 0x7fff : value * 0x8000;
- NumberFieldType.Int16.serialize(dataView, offset, value, littleEndian);
+ dataView.setInt16(offset, value, littleEndian);
},
};
diff --git a/libraries/scrcpy/src/options/2_0.ts b/libraries/scrcpy/src/options/2_0.ts
index 090bd127..47b57a63 100644
--- a/libraries/scrcpy/src/options/2_0.ts
+++ b/libraries/scrcpy/src/options/2_0.ts
@@ -4,13 +4,14 @@ import {
PushReadableStream,
} from "@yume-chan/stream-extra";
import type { ValueOrPromise } from "@yume-chan/struct";
-import Struct, { NumberFieldType, placeholder } from "@yume-chan/struct";
+import Struct, { placeholder } from "@yume-chan/struct";
import type {
AndroidMotionEventAction,
ScrcpyInjectTouchControlMessage,
} from "../control/index.js";
+import { getUint32BigEndian } from "@yume-chan/no-data-view";
import {
CodecOptions,
ScrcpyFloatToUint16FieldDefinition,
@@ -256,14 +257,9 @@ export class ScrcpyOptions2_0 extends ScrcpyOptionsBase<
): ValueOrPromise {
return (async (): Promise => {
const buffered = new BufferedReadableStream(stream);
- const buffer = await buffered.readExactly(
- NumberFieldType.Uint32.size,
- );
+ const buffer = await buffered.readExactly(4);
- const codecMetadataValue = NumberFieldType.Uint32.deserialize(
- buffer,
- false,
- );
+ const codecMetadataValue = getUint32BigEndian(buffer, 0);
// Server will send `0x00_00_00_00` and `0x00_00_00_01` even if `sendCodecMeta` is false
switch (codecMetadataValue) {
case 0x00_00_00_00:
diff --git a/libraries/stream-extra/package.json b/libraries/stream-extra/package.json
index a79531ba..9a983e89 100644
--- a/libraries/stream-extra/package.json
+++ b/libraries/stream-extra/package.json
@@ -33,8 +33,7 @@
},
"dependencies": {
"@yume-chan/async": "^2.2.0",
- "@yume-chan/struct": "workspace:^0.0.23",
- "tslib": "^2.6.2"
+ "@yume-chan/struct": "workspace:^0.0.23"
},
"devDependencies": {
"@jest/globals": "^30.0.0-alpha.3",
diff --git a/libraries/struct/package.json b/libraries/struct/package.json
index 446415fb..05d6f065 100644
--- a/libraries/struct/package.json
+++ b/libraries/struct/package.json
@@ -34,8 +34,7 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
- "@yume-chan/dataview-bigint-polyfill": "workspace:^0.0.23",
- "tslib": "^2.6.2"
+ "@yume-chan/no-data-view": "workspace:^0.0.23"
},
"devDependencies": {
"@jest/globals": "^30.0.0-alpha.3",
diff --git a/libraries/struct/src/basic/field-value.spec.ts b/libraries/struct/src/basic/field-value.spec.ts
index d1ae396b..5c172259 100644
--- a/libraries/struct/src/basic/field-value.spec.ts
+++ b/libraries/struct/src/basic/field-value.spec.ts
@@ -13,8 +13,13 @@ describe("StructFieldValue", () => {
describe(".constructor", () => {
it("should save parameters", () => {
class MockStructFieldValue extends StructFieldValue {
- serialize(dataView: DataView, offset: number): void {
+ serialize(
+ dataView: DataView,
+ array: Uint8Array,
+ offset: number,
+ ): void {
void dataView;
+ void array;
void offset;
throw new Error("Method not implemented.");
}
@@ -78,8 +83,13 @@ describe("StructFieldValue", () => {
}
class MockStructFieldValue extends StructFieldValue {
- serialize(dataView: DataView, offset: number): void {
+ serialize(
+ dataView: DataView,
+ array: Uint8Array,
+ offset: number,
+ ): void {
void dataView;
+ void array;
void offset;
throw new Error("Method not implemented.");
}
@@ -99,8 +109,13 @@ describe("StructFieldValue", () => {
describe("#set", () => {
it("should update its internal value", () => {
class MockStructFieldValue extends StructFieldValue {
- serialize(dataView: DataView, offset: number): void {
+ serialize(
+ dataView: DataView,
+ array: Uint8Array,
+ offset: number,
+ ): void {
void dataView;
+ void array;
void offset;
throw new Error("Method not implemented.");
}
diff --git a/libraries/struct/src/basic/field-value.ts b/libraries/struct/src/basic/field-value.ts
index 417bd37a..2eb60af8 100644
--- a/libraries/struct/src/basic/field-value.ts
+++ b/libraries/struct/src/basic/field-value.ts
@@ -67,5 +67,9 @@ export abstract class StructFieldValue<
/**
* When implemented in derived classes, serializes this field into `dataView` at `offset`
*/
- abstract serialize(dataView: DataView, offset: number): void;
+ abstract serialize(
+ dataView: DataView,
+ array: Uint8Array,
+ offset: number,
+ ): void;
}
diff --git a/libraries/struct/src/struct.ts b/libraries/struct/src/struct.ts
index 69c7c0b0..dcdc7efb 100644
--- a/libraries/struct/src/struct.ts
+++ b/libraries/struct/src/struct.ts
@@ -697,7 +697,7 @@ export class Struct<
);
let offset = 0;
for (const { fieldValue, size } of fieldsInfo) {
- fieldValue.serialize(dataView, offset);
+ fieldValue.serialize(dataView, output, offset);
offset += size;
}
diff --git a/libraries/struct/src/types/bigint.ts b/libraries/struct/src/types/bigint.ts
index dff626c5..84e775f0 100644
--- a/libraries/struct/src/types/bigint.ts
+++ b/libraries/struct/src/types/bigint.ts
@@ -1,10 +1,9 @@
import {
- getBigInt64,
- getBigUint64,
- setBigInt64,
- setBigUint64,
-} from "@yume-chan/dataview-bigint-polyfill/esm/fallback.js";
-
+ getInt64,
+ getUint64,
+ setInt64,
+ setUint64,
+} from "@yume-chan/no-data-view";
import type {
AsyncExactReadable,
ExactReadable,
@@ -15,17 +14,17 @@ import { StructFieldDefinition, StructFieldValue } from "../basic/index.js";
import { SyncPromise } from "../sync-promise.js";
import type { ValueOrPromise } from "../utils.js";
-type DataViewBigInt64Getter = (
- dataView: DataView,
+type GetBigInt64 = (
+ array: Uint8Array,
byteOffset: number,
- littleEndian: boolean | undefined,
+ littleEndian: boolean,
) => bigint;
-type DataViewBigInt64Setter = (
- dataView: DataView,
+type SetBigInt64 = (
+ array: Uint8Array,
byteOffset: number,
value: bigint,
- littleEndian: boolean | undefined,
+ littleEndian: boolean,
) => void;
export class BigIntFieldType {
@@ -33,23 +32,19 @@ export class BigIntFieldType {
readonly size: number;
- readonly getter: DataViewBigInt64Getter;
+ readonly getter: GetBigInt64;
- readonly setter: DataViewBigInt64Setter;
+ readonly setter: SetBigInt64;
- constructor(
- size: number,
- getter: DataViewBigInt64Getter,
- setter: DataViewBigInt64Setter,
- ) {
+ constructor(size: number, getter: GetBigInt64, setter: SetBigInt64) {
this.size = size;
this.getter = getter;
this.setter = setter;
}
- static readonly Int64 = new BigIntFieldType(8, getBigInt64, setBigInt64);
+ static readonly Int64 = new BigIntFieldType(8, getInt64, setInt64);
- static readonly Uint64 = new BigIntFieldType(8, getBigUint64, setBigUint64);
+ static readonly Uint64 = new BigIntFieldType(8, getUint64, setUint64);
}
export class BigIntFieldDefinition<
@@ -95,12 +90,7 @@ export class BigIntFieldDefinition<
return stream.readExactly(this.getSize());
})
.then((array) => {
- const view = new DataView(
- array.buffer,
- array.byteOffset,
- array.byteLength,
- );
- const value = this.type.getter(view, 0, options.littleEndian);
+ const value = this.type.getter(array, 0, options.littleEndian);
return this.create(options, struct, value as never);
})
.valueOrPromise();
@@ -110,9 +100,13 @@ export class BigIntFieldDefinition<
export class BigIntFieldValue<
TDefinition extends BigIntFieldDefinition,
> extends StructFieldValue {
- serialize(dataView: DataView, offset: number): void {
+ override serialize(
+ dataView: DataView,
+ array: Uint8Array,
+ offset: number,
+ ): void {
this.definition.type.setter(
- dataView,
+ array,
offset,
this.value as never,
this.options.littleEndian,
diff --git a/libraries/struct/src/types/buffer/base.spec.ts b/libraries/struct/src/types/buffer/base.spec.ts
index b2bc60d2..6d688aca 100644
--- a/libraries/struct/src/types/buffer/base.spec.ts
+++ b/libraries/struct/src/types/buffer/base.spec.ts
@@ -189,7 +189,7 @@ describe("Types", () => {
const targetArray = new Uint8Array(size);
const targetView = new DataView(targetArray.buffer);
- fieldValue.serialize(targetView, 0);
+ fieldValue.serialize(targetView, targetArray, 0);
expect(targetArray).toEqual(sourceArray);
});
@@ -219,7 +219,7 @@ describe("Types", () => {
const targetArray = new Uint8Array(size);
const targetView = new DataView(targetArray.buffer);
- fieldValue.serialize(targetView, 0);
+ fieldValue.serialize(targetView, targetArray, 0);
expect(targetArray).toEqual(sourceArray);
});
diff --git a/libraries/struct/src/types/buffer/base.ts b/libraries/struct/src/types/buffer/base.ts
index 7dab8647..d5d1549e 100644
--- a/libraries/struct/src/types/buffer/base.ts
+++ b/libraries/struct/src/types/buffer/base.ts
@@ -186,15 +186,12 @@ export class BufferLikeFieldValue<
this.array = undefined;
}
- serialize(dataView: DataView, offset: number): void {
- if (!this.array) {
- this.array = this.definition.type.toBuffer(this.value);
- }
-
- new Uint8Array(
- dataView.buffer,
- dataView.byteOffset,
- dataView.byteLength,
- ).set(this.array, offset);
+ override serialize(
+ dataView: DataView,
+ array: Uint8Array,
+ offset: number,
+ ): void {
+ this.array ??= this.definition.type.toBuffer(this.value);
+ array.set(this.array, offset);
}
}
diff --git a/libraries/struct/src/types/buffer/variable-length.spec.ts b/libraries/struct/src/types/buffer/variable-length.spec.ts
index 9131e67d..32ee5f9f 100644
--- a/libraries/struct/src/types/buffer/variable-length.spec.ts
+++ b/libraries/struct/src/types/buffer/variable-length.spec.ts
@@ -39,10 +39,12 @@ class MockLengthFieldValue extends StructFieldValue {
void value;
});
- serialize = jest.fn((dataView: DataView, offset: number): void => {
- void dataView;
- void offset;
- });
+ serialize = jest.fn(
+ (dataView: DataView, array: Uint8Array, offset: number): void => {
+ void dataView;
+ void offset;
+ },
+ );
}
describe("Types", () => {
@@ -62,8 +64,13 @@ describe("Types", () => {
override getSize = jest.fn(() => this.size);
- serialize(dataView: DataView, offset: number): void {
+ serialize(
+ dataView: DataView,
+ array: Uint8Array,
+ offset: number,
+ ): void {
void dataView;
+ void array;
void offset;
throw new Error("Method not implemented.");
}
@@ -181,11 +188,12 @@ describe("Types", () => {
);
const dataView = 0 as any;
+ const array = 2 as any;
const offset = 1 as any;
mockOriginalFieldValue.value = 10;
mockArrayBufferFieldValue.size = 0;
- lengthFieldValue.serialize(dataView, offset);
+ lengthFieldValue.serialize(dataView, array, offset);
expect(mockOriginalFieldValue.get).toHaveBeenCalledTimes(1);
expect(mockOriginalFieldValue.get).toHaveReturnedWith(10);
expect(mockOriginalFieldValue.set).toHaveBeenCalledTimes(1);
@@ -195,13 +203,14 @@ describe("Types", () => {
);
expect(mockOriginalFieldValue.serialize).toHaveBeenCalledWith(
dataView,
+ array,
offset,
);
mockOriginalFieldValue.set.mockClear();
mockOriginalFieldValue.serialize.mockClear();
mockArrayBufferFieldValue.size = 100;
- lengthFieldValue.serialize(dataView, offset);
+ lengthFieldValue.serialize(dataView, array, offset);
expect(mockOriginalFieldValue.set).toHaveBeenCalledTimes(1);
expect(mockOriginalFieldValue.set).toHaveBeenCalledWith(100);
expect(mockOriginalFieldValue.serialize).toHaveBeenCalledTimes(
@@ -209,6 +218,7 @@ describe("Types", () => {
);
expect(mockOriginalFieldValue.serialize).toHaveBeenCalledWith(
dataView,
+ array,
offset,
);
});
@@ -224,11 +234,12 @@ describe("Types", () => {
);
const dataView = 0 as any;
+ const array = 2 as any;
const offset = 1 as any;
mockOriginalFieldValue.value = "10";
mockArrayBufferFieldValue.size = 0;
- lengthFieldValue.serialize(dataView, offset);
+ lengthFieldValue.serialize(dataView, array, offset);
expect(mockOriginalFieldValue.get).toHaveBeenCalledTimes(1);
expect(mockOriginalFieldValue.get).toHaveReturnedWith("10");
expect(mockOriginalFieldValue.set).toHaveBeenCalledTimes(1);
@@ -238,13 +249,14 @@ describe("Types", () => {
);
expect(mockOriginalFieldValue.serialize).toHaveBeenCalledWith(
dataView,
+ array,
offset,
);
mockOriginalFieldValue.set.mockClear();
mockOriginalFieldValue.serialize.mockClear();
mockArrayBufferFieldValue.size = 100;
- lengthFieldValue.serialize(dataView, offset);
+ lengthFieldValue.serialize(dataView, array, offset);
expect(mockOriginalFieldValue.set).toHaveBeenCalledTimes(1);
expect(mockOriginalFieldValue.set).toHaveBeenCalledWith("100");
expect(mockOriginalFieldValue.serialize).toHaveBeenCalledTimes(
@@ -252,6 +264,7 @@ describe("Types", () => {
);
expect(mockOriginalFieldValue.serialize).toHaveBeenCalledWith(
dataView,
+ array,
offset,
);
});
@@ -271,11 +284,12 @@ describe("Types", () => {
radix;
const dataView = 0 as any;
+ const array = 2 as any;
const offset = 1 as any;
mockOriginalFieldValue.value = "10";
mockArrayBufferFieldValue.size = 0;
- lengthFieldValue.serialize(dataView, offset);
+ lengthFieldValue.serialize(dataView, array, offset);
expect(mockOriginalFieldValue.get).toHaveBeenCalledTimes(1);
expect(mockOriginalFieldValue.get).toHaveReturnedWith("10");
expect(mockOriginalFieldValue.set).toHaveBeenCalledTimes(1);
@@ -285,13 +299,14 @@ describe("Types", () => {
);
expect(mockOriginalFieldValue.serialize).toHaveBeenCalledWith(
dataView,
+ array,
offset,
);
mockOriginalFieldValue.set.mockClear();
mockOriginalFieldValue.serialize.mockClear();
mockArrayBufferFieldValue.size = 100;
- lengthFieldValue.serialize(dataView, offset);
+ lengthFieldValue.serialize(dataView, array, offset);
expect(mockOriginalFieldValue.set).toHaveBeenCalledTimes(1);
expect(mockOriginalFieldValue.set).toHaveBeenCalledWith(
(100).toString(radix),
@@ -301,6 +316,7 @@ describe("Types", () => {
);
expect(mockOriginalFieldValue.serialize).toHaveBeenCalledWith(
dataView,
+ array,
offset,
);
});
diff --git a/libraries/struct/src/types/buffer/variable-length.ts b/libraries/struct/src/types/buffer/variable-length.ts
index 9d646a69..85845720 100644
--- a/libraries/struct/src/types/buffer/variable-length.ts
+++ b/libraries/struct/src/types/buffer/variable-length.ts
@@ -180,8 +180,8 @@ export class VariableLengthBufferLikeFieldLengthValue extends StructFieldValue<
// It will always be in sync with the buffer size
}
- serialize(dataView: DataView, offset: number) {
+ serialize(dataView: DataView, array: Uint8Array, offset: number) {
this.originalField.set(this.get());
- this.originalField.serialize(dataView, offset);
+ this.originalField.serialize(dataView, array, offset);
}
}
diff --git a/libraries/struct/src/types/number.spec.ts b/libraries/struct/src/types/number.spec.ts
index 591ec165..95519c77 100644
--- a/libraries/struct/src/types/number.spec.ts
+++ b/libraries/struct/src/types/number.spec.ts
@@ -316,7 +316,7 @@ describe("Types", () => {
const array = new Uint8Array(10);
const dataView = new DataView(array.buffer);
- value.serialize(dataView, 2);
+ value.serialize(dataView, array, 2);
expect(Array.from(array)).toEqual([
0, 0, 42, 0, 0, 0, 0, 0, 0, 0,
diff --git a/libraries/struct/src/types/number.ts b/libraries/struct/src/types/number.ts
index 10575911..f1c6696a 100644
--- a/libraries/struct/src/types/number.ts
+++ b/libraries/struct/src/types/number.ts
@@ -1,3 +1,9 @@
+import {
+ getInt16,
+ getInt32,
+ getUint16,
+ getUint32,
+} from "@yume-chan/no-data-view";
import type {
AsyncExactReadable,
ExactReadable,
@@ -51,9 +57,7 @@ export namespace NumberFieldType {
// PERF: Creating many `DataView`s over small buffers is 90% slower
// than this. Even if the `DataView` is cached, `DataView#getUint16`
// is still 1% slower than this.
- const a = (array[1]! << 8) | array[0]!;
- const b = (array[0]! << 8) | array[1]!;
- return littleEndian ? a : b;
+ return getUint16(array, 0, littleEndian);
},
serialize(dataView, offset, value, littleEndian) {
dataView.setUint16(offset, value, littleEndian);
@@ -64,8 +68,7 @@ export namespace NumberFieldType {
signed: true,
size: 2,
deserialize(array, littleEndian) {
- const value = Uint16.deserialize(array, littleEndian);
- return (value << 16) >> 16;
+ return getInt16(array, 0, littleEndian);
},
serialize(dataView, offset, value, littleEndian) {
dataView.setInt16(offset, value, littleEndian);
@@ -76,8 +79,7 @@ export namespace NumberFieldType {
signed: false,
size: 4,
deserialize(array, littleEndian) {
- const value = Int32.deserialize(array, littleEndian);
- return value >>> 0;
+ return getUint32(array, 0, littleEndian);
},
serialize(dataView, offset, value, littleEndian) {
dataView.setUint32(offset, value, littleEndian);
@@ -88,17 +90,7 @@ export namespace NumberFieldType {
signed: true,
size: 4,
deserialize(array, littleEndian) {
- const a =
- (array[3]! << 24) |
- (array[2]! << 16) |
- (array[1]! << 8) |
- array[0]!;
- const b =
- (array[0]! << 24) |
- (array[1]! << 16) |
- (array[2]! << 8) |
- array[3]!;
- return littleEndian ? a : b;
+ return getInt32(array, 0, littleEndian);
},
serialize(dataView, offset, value, littleEndian) {
dataView.setInt32(offset, value, littleEndian);
@@ -162,7 +154,7 @@ export class NumberFieldDefinition<
export class NumberFieldValue<
TDefinition extends NumberFieldDefinition,
> extends StructFieldValue {
- serialize(dataView: DataView, offset: number): void {
+ serialize(dataView: DataView, array: Uint8Array, offset: number): void {
this.definition.type.serialize(
dataView,
offset,
diff --git a/libraries/struct/tsconfig.json b/libraries/struct/tsconfig.json
index 85fc5a7a..04f9aba7 100644
--- a/libraries/struct/tsconfig.json
+++ b/libraries/struct/tsconfig.json
@@ -1,5 +1,8 @@
{
"references": [
+ {
+ "path": "../no-data-view/tsconfig.build.json"
+ },
{
"path": "./tsconfig.test.json"
},
diff --git a/rush.json b/rush.json
index d77c21be..036d2f0c 100644
--- a/rush.json
+++ b/rush.json
@@ -437,6 +437,12 @@
"shouldPublish": true,
"versionPolicyName": "adb"
},
+ {
+ "packageName": "@yume-chan/no-data-view",
+ "projectFolder": "libraries/no-data-view",
+ "shouldPublish": true,
+ "versionPolicyName": "adb"
+ },
{
"packageName": "@yume-chan/scrcpy-decoder-tinyh264",
"projectFolder": "libraries/scrcpy-decoder-tinyh264",
diff --git a/toolchain/tsconfig/tsconfig.base.json b/toolchain/tsconfig/tsconfig.base.json
index c780f6a7..9eb0b51a 100644
--- a/toolchain/tsconfig/tsconfig.base.json
+++ b/toolchain/tsconfig/tsconfig.base.json
@@ -16,7 +16,7 @@
"stripInternal": true,
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "noEmit": true, /* Do not emit outputs. */
- "importHelpers": true, // /* Import emit helpers from 'tslib'. */
+ // "importHelpers": true, // /* Import emit helpers from 'tslib'. */
"skipLibCheck": true, // /* Skip type checking of all declaration files (*.d.ts). */
/* Strict Type-Checking Options */
"strict": true, // /* Enable all strict type-checking options. */