mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-03 01:39:21 +02:00
refactor: remove TypeScript enum and namespace to improve tree-shaking
This commit is contained in:
parent
b1787e8ef4
commit
2c8912e9ac
34 changed files with 744 additions and 619 deletions
|
@ -1,11 +1,13 @@
|
|||
import type { AdbFeature } from "./features.js";
|
||||
|
||||
export enum AdbBannerKey {
|
||||
Product = "ro.product.name",
|
||||
Model = "ro.product.model",
|
||||
Device = "ro.product.device",
|
||||
Features = "features",
|
||||
}
|
||||
export const AdbBannerKey = {
|
||||
Product: "ro.product.name",
|
||||
Model: "ro.product.model",
|
||||
Device: "ro.product.device",
|
||||
Features: "features",
|
||||
} as const;
|
||||
|
||||
export type AdbBannerKey = (typeof AdbBannerKey)[keyof typeof AdbBannerKey];
|
||||
|
||||
export class AdbBanner {
|
||||
static parse(banner: string) {
|
||||
|
|
|
@ -3,40 +3,46 @@ import Struct, { StructEmptyError } from "@yume-chan/struct";
|
|||
|
||||
import type { Adb } from "../adb.js";
|
||||
|
||||
const Version = new Struct({ littleEndian: true }).uint32("version");
|
||||
const Version =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true }).uint32("version");
|
||||
|
||||
export const AdbFrameBufferV1 = new Struct({ littleEndian: true })
|
||||
.uint32("bpp")
|
||||
.uint32("size")
|
||||
.uint32("width")
|
||||
.uint32("height")
|
||||
.uint32("red_offset")
|
||||
.uint32("red_length")
|
||||
.uint32("blue_offset")
|
||||
.uint32("blue_length")
|
||||
.uint32("green_offset")
|
||||
.uint32("green_length")
|
||||
.uint32("alpha_offset")
|
||||
.uint32("alpha_length")
|
||||
.uint8Array("data", { lengthField: "size" });
|
||||
export const AdbFrameBufferV1 =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true })
|
||||
.uint32("bpp")
|
||||
.uint32("size")
|
||||
.uint32("width")
|
||||
.uint32("height")
|
||||
.uint32("red_offset")
|
||||
.uint32("red_length")
|
||||
.uint32("blue_offset")
|
||||
.uint32("blue_length")
|
||||
.uint32("green_offset")
|
||||
.uint32("green_length")
|
||||
.uint32("alpha_offset")
|
||||
.uint32("alpha_length")
|
||||
.uint8Array("data", { lengthField: "size" });
|
||||
|
||||
export type AdbFrameBufferV1 = (typeof AdbFrameBufferV1)["TDeserializeResult"];
|
||||
|
||||
export const AdbFrameBufferV2 = new Struct({ littleEndian: true })
|
||||
.uint32("bpp")
|
||||
.uint32("colorSpace")
|
||||
.uint32("size")
|
||||
.uint32("width")
|
||||
.uint32("height")
|
||||
.uint32("red_offset")
|
||||
.uint32("red_length")
|
||||
.uint32("blue_offset")
|
||||
.uint32("blue_length")
|
||||
.uint32("green_offset")
|
||||
.uint32("green_length")
|
||||
.uint32("alpha_offset")
|
||||
.uint32("alpha_length")
|
||||
.uint8Array("data", { lengthField: "size" });
|
||||
export const AdbFrameBufferV2 =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true })
|
||||
.uint32("bpp")
|
||||
.uint32("colorSpace")
|
||||
.uint32("size")
|
||||
.uint32("width")
|
||||
.uint32("height")
|
||||
.uint32("red_offset")
|
||||
.uint32("red_length")
|
||||
.uint32("blue_offset")
|
||||
.uint32("blue_length")
|
||||
.uint32("green_offset")
|
||||
.uint32("green_length")
|
||||
.uint32("alpha_offset")
|
||||
.uint32("alpha_length")
|
||||
.uint8Array("data", { lengthField: "size" });
|
||||
|
||||
export type AdbFrameBufferV2 = (typeof AdbFrameBufferV2)["TDeserializeResult"];
|
||||
|
||||
|
|
|
@ -14,9 +14,11 @@ export interface AdbForwardListener {
|
|||
remoteName: string;
|
||||
}
|
||||
|
||||
const AdbReverseStringResponse = new Struct()
|
||||
.string("length", { length: 4 })
|
||||
.string("content", { lengthField: "length", lengthFieldRadix: 16 });
|
||||
const AdbReverseStringResponse =
|
||||
/* #__PURE__ */
|
||||
new Struct()
|
||||
.string("length", { length: 4 })
|
||||
.string("content", { lengthField: "length", lengthFieldRadix: 16 });
|
||||
|
||||
export class AdbReverseError extends Error {
|
||||
constructor(message: string) {
|
||||
|
@ -33,9 +35,9 @@ export class AdbReverseNotSupportedError extends AdbReverseError {
|
|||
}
|
||||
}
|
||||
|
||||
const AdbReverseErrorResponse = new Struct()
|
||||
.concat(AdbReverseStringResponse)
|
||||
.postDeserialize((value) => {
|
||||
const AdbReverseErrorResponse =
|
||||
/* #__PURE__ */
|
||||
new Struct().concat(AdbReverseStringResponse).postDeserialize((value) => {
|
||||
// https://issuetracker.google.com/issues/37066218
|
||||
// ADB on Android <9 can't create reverse tunnels when connected wirelessly (ADB over Wi-Fi),
|
||||
// and returns this confusing "more than one device/emulator" error.
|
||||
|
|
|
@ -19,20 +19,25 @@ import { encodeUtf8 } from "../../../utils/index.js";
|
|||
|
||||
import type { AdbSubprocessProtocol } from "./types.js";
|
||||
|
||||
export enum AdbShellProtocolId {
|
||||
Stdin,
|
||||
Stdout,
|
||||
Stderr,
|
||||
Exit,
|
||||
CloseStdin,
|
||||
WindowSizeChange,
|
||||
}
|
||||
export const AdbShellProtocolId = {
|
||||
Stdin: 0,
|
||||
Stdout: 1,
|
||||
Stderr: 2,
|
||||
Exit: 3,
|
||||
CloseStdin: 4,
|
||||
WindowSizeChange: 5,
|
||||
} as const;
|
||||
|
||||
export type AdbShellProtocolId =
|
||||
(typeof AdbShellProtocolId)[keyof typeof AdbShellProtocolId];
|
||||
|
||||
// This packet format is used in both directions.
|
||||
export const AdbShellProtocolPacket = new Struct({ littleEndian: true })
|
||||
.uint8("id", placeholder<AdbShellProtocolId>())
|
||||
.uint32("length")
|
||||
.uint8Array("data", { lengthField: "length" });
|
||||
export const AdbShellProtocolPacket =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true })
|
||||
.uint8("id", placeholder<AdbShellProtocolId>())
|
||||
.uint32("length")
|
||||
.uint8Array("data", { lengthField: "length" });
|
||||
|
||||
type AdbShellProtocolPacket = StructValueType<typeof AdbShellProtocolPacket>;
|
||||
|
||||
|
|
|
@ -14,18 +14,22 @@ export interface AdbSyncEntry extends AdbSyncStat {
|
|||
name: string;
|
||||
}
|
||||
|
||||
export const AdbSyncEntryResponse = new Struct({ littleEndian: true })
|
||||
.concat(AdbSyncLstatResponse)
|
||||
.uint32("nameLength")
|
||||
.string("name", { lengthField: "nameLength" });
|
||||
export const AdbSyncEntryResponse =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true })
|
||||
.concat(AdbSyncLstatResponse)
|
||||
.uint32("nameLength")
|
||||
.string("name", { lengthField: "nameLength" });
|
||||
|
||||
export type AdbSyncEntryResponse =
|
||||
(typeof AdbSyncEntryResponse)["TDeserializeResult"];
|
||||
|
||||
export const AdbSyncEntry2Response = new Struct({ littleEndian: true })
|
||||
.concat(AdbSyncStatResponse)
|
||||
.uint32("nameLength")
|
||||
.string("name", { lengthField: "nameLength" });
|
||||
export const AdbSyncEntry2Response =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true })
|
||||
.concat(AdbSyncStatResponse)
|
||||
.uint32("nameLength")
|
||||
.string("name", { lengthField: "nameLength" });
|
||||
|
||||
export type AdbSyncEntry2Response =
|
||||
(typeof AdbSyncEntry2Response)["TDeserializeResult"];
|
||||
|
|
|
@ -6,9 +6,11 @@ import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
|||
import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js";
|
||||
import type { AdbSyncSocket } from "./socket.js";
|
||||
|
||||
export const AdbSyncDataResponse = new Struct({ littleEndian: true })
|
||||
.uint32("dataLength")
|
||||
.uint8Array("data", { lengthField: "dataLength" });
|
||||
export const AdbSyncDataResponse =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true })
|
||||
.uint32("dataLength")
|
||||
.uint8Array("data", { lengthField: "dataLength" });
|
||||
|
||||
export type AdbSyncDataResponse =
|
||||
(typeof AdbSyncDataResponse)["TDeserializeResult"];
|
||||
|
|
|
@ -25,9 +25,9 @@ export interface AdbSyncPushV1Options {
|
|||
packetSize?: number;
|
||||
}
|
||||
|
||||
export const AdbSyncOkResponse = new Struct({ littleEndian: true }).uint32(
|
||||
"unused",
|
||||
);
|
||||
export const AdbSyncOkResponse =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true }).uint32("unused");
|
||||
|
||||
async function pipeFileData(
|
||||
locked: AdbSyncSocketLocked,
|
||||
|
@ -86,19 +86,22 @@ export async function adbSyncPushV1({
|
|||
}
|
||||
}
|
||||
|
||||
export enum AdbSyncSendV2Flags {
|
||||
None = 0,
|
||||
Brotli = 1,
|
||||
export const AdbSyncSendV2Flags = {
|
||||
None: 0,
|
||||
Brotli: 1,
|
||||
/**
|
||||
* 2
|
||||
*/
|
||||
Lz4 = 1 << 1,
|
||||
Lz4: 1 << 1,
|
||||
/**
|
||||
* 4
|
||||
*/
|
||||
Zstd = 1 << 2,
|
||||
DryRun = 0x80000000,
|
||||
}
|
||||
Zstd: 1 << 2,
|
||||
DryRun: 0x80000000,
|
||||
} as const;
|
||||
|
||||
export type AdbSyncSendV2Flags =
|
||||
(typeof AdbSyncSendV2Flags)[keyof typeof AdbSyncSendV2Flags];
|
||||
|
||||
export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
|
||||
/**
|
||||
|
@ -110,10 +113,12 @@ export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
|
|||
dryRun?: boolean;
|
||||
}
|
||||
|
||||
export const AdbSyncSendV2Request = new Struct({ littleEndian: true })
|
||||
.uint32("id")
|
||||
.uint32("mode")
|
||||
.uint32("flags", placeholder<AdbSyncSendV2Flags>());
|
||||
export const AdbSyncSendV2Request =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true })
|
||||
.uint32("id")
|
||||
.uint32("mode")
|
||||
.uint32("flags", placeholder<AdbSyncSendV2Flags>());
|
||||
|
||||
export async function adbSyncPushV2({
|
||||
socket,
|
||||
|
|
|
@ -4,22 +4,22 @@ import { encodeUtf8 } from "../../utils/index.js";
|
|||
|
||||
import { adbSyncEncodeId } from "./response.js";
|
||||
|
||||
export namespace AdbSyncRequestId {
|
||||
export const List = adbSyncEncodeId("LIST");
|
||||
export const ListV2 = adbSyncEncodeId("LIS2");
|
||||
export const Send = adbSyncEncodeId("SEND");
|
||||
export const SendV2 = adbSyncEncodeId("SND2");
|
||||
export const Lstat = adbSyncEncodeId("STAT");
|
||||
export const Stat = adbSyncEncodeId("STA2");
|
||||
export const LstatV2 = adbSyncEncodeId("LST2");
|
||||
export const Data = adbSyncEncodeId("DATA");
|
||||
export const Done = adbSyncEncodeId("DONE");
|
||||
export const Receive = adbSyncEncodeId("RECV");
|
||||
}
|
||||
export const AdbSyncRequestId = {
|
||||
List: adbSyncEncodeId("LIST"),
|
||||
ListV2: adbSyncEncodeId("LIS2"),
|
||||
Send: adbSyncEncodeId("SEND"),
|
||||
SendV2: adbSyncEncodeId("SND2"),
|
||||
Lstat: adbSyncEncodeId("STAT"),
|
||||
Stat: adbSyncEncodeId("STA2"),
|
||||
LstatV2: adbSyncEncodeId("LST2"),
|
||||
Data: adbSyncEncodeId("DATA"),
|
||||
Done: adbSyncEncodeId("DONE"),
|
||||
Receive: adbSyncEncodeId("RECV"),
|
||||
} as const;
|
||||
|
||||
export const AdbSyncNumberRequest = new Struct({ littleEndian: true })
|
||||
.uint32("id")
|
||||
.uint32("arg");
|
||||
export const AdbSyncNumberRequest =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true }).uint32("id").uint32("arg");
|
||||
|
||||
export interface AdbSyncWritable {
|
||||
write(buffer: Uint8Array): Promise<void>;
|
||||
|
|
|
@ -18,32 +18,36 @@ function encodeAsciiUnchecked(value: string): Uint8Array {
|
|||
* Encode ID to numbers for faster comparison
|
||||
* @param value A 4-character string
|
||||
* @returns A 32-bit integer by encoding the string as little-endian
|
||||
*
|
||||
* #__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
export function adbSyncEncodeId(value: string): number {
|
||||
const buffer = encodeAsciiUnchecked(value);
|
||||
return getUint32LittleEndian(buffer, 0);
|
||||
}
|
||||
|
||||
export namespace AdbSyncResponseId {
|
||||
export const Entry = adbSyncEncodeId("DENT");
|
||||
export const Entry2 = adbSyncEncodeId("DNT2");
|
||||
export const Lstat = adbSyncEncodeId("STAT");
|
||||
export const Stat = adbSyncEncodeId("STA2");
|
||||
export const Lstat2 = adbSyncEncodeId("LST2");
|
||||
export const Done = adbSyncEncodeId("DONE");
|
||||
export const Data = adbSyncEncodeId("DATA");
|
||||
export const Ok = adbSyncEncodeId("OKAY");
|
||||
export const Fail = adbSyncEncodeId("FAIL");
|
||||
}
|
||||
export const AdbSyncResponseId = {
|
||||
Entry: adbSyncEncodeId("DENT"),
|
||||
Entry2: adbSyncEncodeId("DNT2"),
|
||||
Lstat: adbSyncEncodeId("STAT"),
|
||||
Stat: adbSyncEncodeId("STA2"),
|
||||
Lstat2: adbSyncEncodeId("LST2"),
|
||||
Done: adbSyncEncodeId("DONE"),
|
||||
Data: adbSyncEncodeId("DATA"),
|
||||
Ok: adbSyncEncodeId("OKAY"),
|
||||
Fail: adbSyncEncodeId("FAIL"),
|
||||
};
|
||||
|
||||
export class AdbSyncError extends Error {}
|
||||
|
||||
export const AdbSyncFailResponse = new Struct({ littleEndian: true })
|
||||
.uint32("messageLength")
|
||||
.string("message", { lengthField: "messageLength" })
|
||||
.postDeserialize((object) => {
|
||||
throw new AdbSyncError(object.message);
|
||||
});
|
||||
export const AdbSyncFailResponse =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true })
|
||||
.uint32("messageLength")
|
||||
.string("message", { lengthField: "messageLength" })
|
||||
.postDeserialize((object) => {
|
||||
throw new AdbSyncError(object.message);
|
||||
});
|
||||
|
||||
export async function adbSyncReadResponse<T>(
|
||||
stream: AsyncExactReadable,
|
||||
|
|
|
@ -5,11 +5,13 @@ import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
|
|||
import type { AdbSyncSocket } from "./socket.js";
|
||||
|
||||
// https://github.com/python/cpython/blob/4e581d64b8aff3e2eda99b12f080c877bb78dfca/Lib/stat.py#L36
|
||||
export enum LinuxFileType {
|
||||
Directory = 0o04,
|
||||
File = 0o10,
|
||||
Link = 0o12,
|
||||
}
|
||||
export const LinuxFileType = {
|
||||
Directory: 0o04,
|
||||
File: 0o10,
|
||||
Link: 0o12,
|
||||
} as const;
|
||||
|
||||
export type LinuxFileType = (typeof LinuxFileType)[keyof typeof LinuxFileType];
|
||||
|
||||
export interface AdbSyncStat {
|
||||
mode: number;
|
||||
|
@ -24,76 +26,92 @@ export interface AdbSyncStat {
|
|||
ctime?: bigint;
|
||||
}
|
||||
|
||||
export const AdbSyncLstatResponse = new Struct({ littleEndian: true })
|
||||
.int32("mode")
|
||||
.int32("size")
|
||||
.int32("mtime")
|
||||
.extra({
|
||||
get type() {
|
||||
return (this.mode >> 12) as LinuxFileType;
|
||||
},
|
||||
get permission() {
|
||||
return this.mode & 0b00001111_11111111;
|
||||
},
|
||||
})
|
||||
.postDeserialize((object) => {
|
||||
if (object.mode === 0 && object.size === 0 && object.mtime === 0) {
|
||||
throw new Error("lstat error");
|
||||
}
|
||||
});
|
||||
export const AdbSyncLstatResponse =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true })
|
||||
.int32("mode")
|
||||
.int32("size")
|
||||
.int32("mtime")
|
||||
.extra({
|
||||
get type() {
|
||||
return (this.mode >> 12) as LinuxFileType;
|
||||
},
|
||||
get permission() {
|
||||
return this.mode & 0b00001111_11111111;
|
||||
},
|
||||
})
|
||||
.postDeserialize((object) => {
|
||||
if (object.mode === 0 && object.size === 0 && object.mtime === 0) {
|
||||
throw new Error("lstat error");
|
||||
}
|
||||
});
|
||||
|
||||
export type AdbSyncLstatResponse =
|
||||
(typeof AdbSyncLstatResponse)["TDeserializeResult"];
|
||||
|
||||
export enum AdbSyncStatErrorCode {
|
||||
SUCCESS = 0,
|
||||
EACCES = 13,
|
||||
EEXIST = 17,
|
||||
EFAULT = 14,
|
||||
EFBIG = 27,
|
||||
EINTR = 4,
|
||||
EINVAL = 22,
|
||||
EIO = 5,
|
||||
EISDIR = 21,
|
||||
ELOOP = 40,
|
||||
EMFILE = 24,
|
||||
ENAMETOOLONG = 36,
|
||||
ENFILE = 23,
|
||||
ENOENT = 2,
|
||||
ENOMEM = 12,
|
||||
ENOSPC = 28,
|
||||
ENOTDIR = 20,
|
||||
EOVERFLOW = 75,
|
||||
EPERM = 1,
|
||||
EROFS = 30,
|
||||
ETXTBSY = 26,
|
||||
}
|
||||
export const AdbSyncStatErrorCode = {
|
||||
SUCCESS: 0,
|
||||
EACCES: 13,
|
||||
EEXIST: 17,
|
||||
EFAULT: 14,
|
||||
EFBIG: 27,
|
||||
EINTR: 4,
|
||||
EINVAL: 22,
|
||||
EIO: 5,
|
||||
EISDIR: 21,
|
||||
ELOOP: 40,
|
||||
EMFILE: 24,
|
||||
ENAMETOOLONG: 36,
|
||||
ENFILE: 23,
|
||||
ENOENT: 2,
|
||||
ENOMEM: 12,
|
||||
ENOSPC: 28,
|
||||
ENOTDIR: 20,
|
||||
EOVERFLOW: 75,
|
||||
EPERM: 1,
|
||||
EROFS: 30,
|
||||
ETXTBSY: 26,
|
||||
} as const;
|
||||
|
||||
export const AdbSyncStatResponse = new Struct({ littleEndian: true })
|
||||
.uint32("error", placeholder<AdbSyncStatErrorCode>())
|
||||
.uint64("dev")
|
||||
.uint64("ino")
|
||||
.uint32("mode")
|
||||
.uint32("nlink")
|
||||
.uint32("uid")
|
||||
.uint32("gid")
|
||||
.uint64("size")
|
||||
.uint64("atime")
|
||||
.uint64("mtime")
|
||||
.uint64("ctime")
|
||||
.extra({
|
||||
get type() {
|
||||
return (this.mode >> 12) as LinuxFileType;
|
||||
},
|
||||
get permission() {
|
||||
return this.mode & 0b00001111_11111111;
|
||||
},
|
||||
})
|
||||
.postDeserialize((object) => {
|
||||
if (object.error) {
|
||||
throw new Error(AdbSyncStatErrorCode[object.error]);
|
||||
}
|
||||
});
|
||||
export type AdbSyncStatErrorCode =
|
||||
(typeof AdbSyncStatErrorCode)[keyof typeof AdbSyncStatErrorCode];
|
||||
|
||||
const AdbSyncStatErrorName =
|
||||
/* #__PURE__ */
|
||||
Object.fromEntries(
|
||||
Object.entries(AdbSyncStatErrorCode).map(([key, value]) => [
|
||||
value,
|
||||
key,
|
||||
]),
|
||||
);
|
||||
|
||||
export const AdbSyncStatResponse =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true })
|
||||
.uint32("error", placeholder<AdbSyncStatErrorCode>())
|
||||
.uint64("dev")
|
||||
.uint64("ino")
|
||||
.uint32("mode")
|
||||
.uint32("nlink")
|
||||
.uint32("uid")
|
||||
.uint32("gid")
|
||||
.uint64("size")
|
||||
.uint64("atime")
|
||||
.uint64("mtime")
|
||||
.uint64("ctime")
|
||||
.extra({
|
||||
get type() {
|
||||
return (this.mode >> 12) as LinuxFileType;
|
||||
},
|
||||
get permission() {
|
||||
return this.mode & 0b00001111_11111111;
|
||||
},
|
||||
})
|
||||
.postDeserialize((object) => {
|
||||
if (object.error) {
|
||||
throw new Error(AdbSyncStatErrorName[object.error]);
|
||||
}
|
||||
});
|
||||
|
||||
export type AdbSyncStatResponse =
|
||||
(typeof AdbSyncStatResponse)["TDeserializeResult"];
|
||||
|
|
|
@ -1,30 +1,36 @@
|
|||
import { Consumable, TransformStream } from "@yume-chan/stream-extra";
|
||||
import Struct from "@yume-chan/struct";
|
||||
|
||||
export enum AdbCommand {
|
||||
Auth = 0x48545541, // 'AUTH'
|
||||
Close = 0x45534c43, // 'CLSE'
|
||||
Connect = 0x4e584e43, // 'CNXN'
|
||||
Okay = 0x59414b4f, // 'OKAY'
|
||||
Open = 0x4e45504f, // 'OPEN'
|
||||
Write = 0x45545257, // 'WRTE'
|
||||
}
|
||||
export const AdbCommand = {
|
||||
Auth: 0x48545541, // 'AUTH'
|
||||
Close: 0x45534c43, // 'CLSE'
|
||||
Connect: 0x4e584e43, // 'CNXN'
|
||||
Okay: 0x59414b4f, // 'OKAY'
|
||||
Open: 0x4e45504f, // 'OPEN'
|
||||
Write: 0x45545257, // 'WRTE'
|
||||
} as const;
|
||||
|
||||
export const AdbPacketHeader = new Struct({ littleEndian: true })
|
||||
.uint32("command")
|
||||
.uint32("arg0")
|
||||
.uint32("arg1")
|
||||
.uint32("payloadLength")
|
||||
.uint32("checksum")
|
||||
.int32("magic");
|
||||
export type AdbCommand = (typeof AdbCommand)[keyof typeof AdbCommand];
|
||||
|
||||
export const AdbPacketHeader =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true })
|
||||
.uint32("command")
|
||||
.uint32("arg0")
|
||||
.uint32("arg1")
|
||||
.uint32("payloadLength")
|
||||
.uint32("checksum")
|
||||
.int32("magic");
|
||||
|
||||
export type AdbPacketHeader = (typeof AdbPacketHeader)["TDeserializeResult"];
|
||||
|
||||
type AdbPacketHeaderInit = (typeof AdbPacketHeader)["TInit"];
|
||||
|
||||
export const AdbPacket = new Struct({ littleEndian: true })
|
||||
.concat(AdbPacketHeader)
|
||||
.uint8Array("payload", { lengthField: "payloadLength" });
|
||||
export const AdbPacket =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true })
|
||||
.concat(AdbPacketHeader)
|
||||
.uint8Array("payload", { lengthField: "payloadLength" });
|
||||
|
||||
export type AdbPacket = (typeof AdbPacket)["TDeserializeResult"];
|
||||
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
// The order follows
|
||||
// https://cs.android.com/android/platform/superproject/+/master:packages/modules/adb/transport.cpp;l=77;drc=6d14d35d0241f6fee145f8e54ffd77252e8d29fd
|
||||
export enum AdbFeature {
|
||||
ShellV2 = "shell_v2",
|
||||
Cmd = "cmd",
|
||||
StatV2 = "stat_v2",
|
||||
ListV2 = "ls_v2",
|
||||
FixedPushMkdir = "fixed_push_mkdir",
|
||||
Abb = "abb",
|
||||
AbbExec = "abb_exec",
|
||||
SendReceiveV2 = "sendrecv_v2",
|
||||
DelayedAck = "delayed_ack",
|
||||
}
|
||||
export const AdbFeature = {
|
||||
ShellV2: "shell_v2",
|
||||
Cmd: "cmd",
|
||||
StatV2: "stat_v2",
|
||||
ListV2: "ls_v2",
|
||||
FixedPushMkdir: "fixed_push_mkdir",
|
||||
Abb: "abb",
|
||||
AbbExec: "abb_exec",
|
||||
SendReceiveV2: "sendrecv_v2",
|
||||
DelayedAck: "delayed_ack",
|
||||
} as const;
|
||||
|
||||
export type AdbFeature = (typeof AdbFeature)[keyof typeof AdbFeature];
|
||||
|
|
|
@ -1,23 +1,31 @@
|
|||
// Array is faster than object literal or `Map`
|
||||
const charToIndex: number[] = [];
|
||||
const indexToChar: number[] = [];
|
||||
const paddingChar = "=".charCodeAt(0);
|
||||
const [charToIndex, indexToChar, paddingChar] = /* #__PURE__ */ (() => {
|
||||
// Array is faster than object literal or `Map`
|
||||
const charToIndex: number[] = [];
|
||||
const indexToChar: number[] = [];
|
||||
const paddingChar = "=".charCodeAt(0);
|
||||
|
||||
function addRange(start: string, end: string) {
|
||||
const charCodeStart = start.charCodeAt(0);
|
||||
const charCodeEnd = end.charCodeAt(0);
|
||||
function addRange(start: string, end: string) {
|
||||
const charCodeStart = start.charCodeAt(0);
|
||||
const charCodeEnd = end.charCodeAt(0);
|
||||
|
||||
for (let charCode = charCodeStart; charCode <= charCodeEnd; charCode += 1) {
|
||||
charToIndex[charCode] = indexToChar.length;
|
||||
indexToChar.push(charCode);
|
||||
for (
|
||||
let charCode = charCodeStart;
|
||||
charCode <= charCodeEnd;
|
||||
charCode += 1
|
||||
) {
|
||||
charToIndex[charCode] = indexToChar.length;
|
||||
indexToChar.push(charCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addRange("A", "Z");
|
||||
addRange("a", "z");
|
||||
addRange("0", "9");
|
||||
addRange("+", "+");
|
||||
addRange("/", "/");
|
||||
addRange("A", "Z");
|
||||
addRange("a", "z");
|
||||
addRange("0", "9");
|
||||
addRange("+", "+");
|
||||
addRange("/", "/");
|
||||
|
||||
return [charToIndex, indexToChar, paddingChar];
|
||||
})();
|
||||
|
||||
/**
|
||||
* Calculate the required length of the output buffer for the given input length.
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* #__NO_SIDE_EFFECTS__ */
|
||||
export const NOOP = () => {
|
||||
// no-op
|
||||
};
|
||||
|
|
|
@ -31,7 +31,32 @@ const BatteryDumpFields: Record<
|
|||
current: { type: "number", field: "current" },
|
||||
};
|
||||
|
||||
const Status = {
|
||||
Unknown: 1,
|
||||
Charging: 2,
|
||||
Discharging: 3,
|
||||
NotCharging: 4,
|
||||
Full: 5,
|
||||
} as const;
|
||||
|
||||
const Health = {
|
||||
Unknown: 1,
|
||||
Good: 2,
|
||||
Overheat: 3,
|
||||
Dead: 4,
|
||||
OverVoltage: 5,
|
||||
UnspecifiedFailure: 6,
|
||||
Cold: 7,
|
||||
} as const;
|
||||
|
||||
const Battery = {
|
||||
Status,
|
||||
Health,
|
||||
};
|
||||
|
||||
export class DumpSys extends AdbCommandBase {
|
||||
static readonly Battery = Battery;
|
||||
|
||||
async diskStats() {
|
||||
const output = await this.adb.subprocess.spawnAndWaitLegacy([
|
||||
"dumpsys",
|
||||
|
@ -113,6 +138,9 @@ export class DumpSys extends AdbCommandBase {
|
|||
|
||||
export namespace DumpSys {
|
||||
export namespace Battery {
|
||||
export type Status = (typeof Status)[keyof typeof Status];
|
||||
export type Health = (typeof Health)[keyof typeof Health];
|
||||
|
||||
export interface Info {
|
||||
acPowered: boolean;
|
||||
usbPowered: boolean;
|
||||
|
@ -131,23 +159,5 @@ export namespace DumpSys {
|
|||
technology?: string;
|
||||
current?: number;
|
||||
}
|
||||
|
||||
export enum Status {
|
||||
Unknown = 1,
|
||||
Charging,
|
||||
Discharging,
|
||||
NotCharging,
|
||||
Full,
|
||||
}
|
||||
|
||||
export enum Health {
|
||||
Unknown = 1,
|
||||
Good,
|
||||
Overheat,
|
||||
Dead,
|
||||
OverVoltage,
|
||||
UnspecifiedFailure,
|
||||
Cold,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,30 +17,39 @@ import Struct, { decodeUtf8 } from "@yume-chan/struct";
|
|||
// so instead of adding to core library, it's implemented here
|
||||
|
||||
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/android/log.h;l=141;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
|
||||
export enum LogId {
|
||||
All = -1,
|
||||
Main,
|
||||
Radio,
|
||||
Events,
|
||||
System,
|
||||
Crash,
|
||||
Stats,
|
||||
Security,
|
||||
Kernel,
|
||||
}
|
||||
export const LogId = {
|
||||
All: -1,
|
||||
Main: 0,
|
||||
Radio: 1,
|
||||
Events: 2,
|
||||
System: 3,
|
||||
Crash: 4,
|
||||
Stats: 5,
|
||||
Security: 6,
|
||||
Kernel: 7,
|
||||
} as const;
|
||||
|
||||
export type LogId = (typeof LogId)[keyof typeof LogId];
|
||||
|
||||
const LogIdName =
|
||||
/* #__PURE__ */
|
||||
Object.fromEntries(Object.entries(LogId).map(([k, v]) => [v, k]));
|
||||
|
||||
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/android/log.h;l=73;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
|
||||
export enum AndroidLogPriority {
|
||||
Unknown,
|
||||
Default,
|
||||
Verbose,
|
||||
Debug,
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
Fatal,
|
||||
Silent,
|
||||
}
|
||||
export const AndroidLogPriority = {
|
||||
Unknown: 0,
|
||||
Default: 1,
|
||||
Verbose: 2,
|
||||
Debug: 3,
|
||||
Info: 4,
|
||||
Warn: 5,
|
||||
Error: 6,
|
||||
Fatal: 7,
|
||||
Silent: 8,
|
||||
} as const;
|
||||
|
||||
export type AndroidLogPriority =
|
||||
(typeof AndroidLogPriority)[keyof typeof AndroidLogPriority];
|
||||
|
||||
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/logprint.cpp;l=140;drc=8dbf3b2bb6b6d1652d9797e477b9abd03278bb79
|
||||
export const AndroidLogPriorityToCharacter: Record<AndroidLogPriority, string> =
|
||||
|
@ -56,16 +65,18 @@ export const AndroidLogPriorityToCharacter: Record<AndroidLogPriority, string> =
|
|||
[AndroidLogPriority.Silent]: "S",
|
||||
};
|
||||
|
||||
export enum LogcatFormat {
|
||||
Brief,
|
||||
Process,
|
||||
Tag,
|
||||
Thread,
|
||||
Raw,
|
||||
Time,
|
||||
ThreadTime,
|
||||
Long,
|
||||
}
|
||||
export const LogcatFormat = {
|
||||
Brief: 0,
|
||||
Process: 1,
|
||||
Tag: 2,
|
||||
Thread: 3,
|
||||
Raw: 4,
|
||||
Time: 5,
|
||||
ThreadTime: 6,
|
||||
Long: 7,
|
||||
} as const;
|
||||
|
||||
export type LogcatFormat = (typeof LogcatFormat)[keyof typeof LogcatFormat];
|
||||
|
||||
export interface LogcatFormatModifiers {
|
||||
microseconds?: boolean;
|
||||
|
@ -88,23 +99,25 @@ export interface LogcatOptions {
|
|||
const NANOSECONDS_PER_SECOND = BigInt(1e9);
|
||||
|
||||
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/log/log_read.h;l=39;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
|
||||
export const LoggerEntry = new Struct({ littleEndian: true })
|
||||
.uint16("payloadSize")
|
||||
.uint16("headerSize")
|
||||
.int32("pid")
|
||||
.uint32("tid")
|
||||
.uint32("seconds")
|
||||
.uint32("nanoseconds")
|
||||
.uint32("logId")
|
||||
.uint32("uid")
|
||||
.extra({
|
||||
get timestamp() {
|
||||
return (
|
||||
BigInt(this.seconds) * NANOSECONDS_PER_SECOND +
|
||||
BigInt(this.nanoseconds)
|
||||
);
|
||||
},
|
||||
});
|
||||
export const LoggerEntry =
|
||||
/* #__PURE__ */
|
||||
new Struct({ littleEndian: true })
|
||||
.uint16("payloadSize")
|
||||
.uint16("headerSize")
|
||||
.int32("pid")
|
||||
.uint32("tid")
|
||||
.uint32("seconds")
|
||||
.uint32("nanoseconds")
|
||||
.uint32("logId")
|
||||
.uint32("uid")
|
||||
.extra({
|
||||
get timestamp() {
|
||||
return (
|
||||
BigInt(this.seconds) * NANOSECONDS_PER_SECOND +
|
||||
BigInt(this.nanoseconds)
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export type LoggerEntry = (typeof LoggerEntry)["TDeserializeResult"];
|
||||
|
||||
|
@ -385,7 +398,7 @@ export interface LogSize {
|
|||
|
||||
export class Logcat extends AdbCommandBase {
|
||||
static logIdToName(id: LogId): string {
|
||||
return LogId[id];
|
||||
return LogIdName[id]!;
|
||||
}
|
||||
|
||||
static logNameToId(name: string): LogId {
|
||||
|
|
|
@ -92,10 +92,9 @@ class VideoFrameCapturer {
|
|||
}
|
||||
}
|
||||
|
||||
const VideoFrameCapturerPool = /*@__PURE__*/ new Pool(
|
||||
() => new VideoFrameCapturer(),
|
||||
4,
|
||||
);
|
||||
const VideoFrameCapturerPool =
|
||||
/* #__PURE__ */
|
||||
new Pool(() => new VideoFrameCapturer(), 4);
|
||||
|
||||
export interface WebCodecsVideoDecoderInit {
|
||||
/**
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { Struct } from "@yume-chan/struct";
|
||||
|
||||
export const EmptyControlMessage = new Struct().uint8("type");
|
||||
export const EmptyControlMessage = /* #__PURE__ */ new Struct().uint8("type");
|
||||
|
|
|
@ -205,12 +205,14 @@ export enum AndroidKeyCode {
|
|||
AndroidPaste,
|
||||
}
|
||||
|
||||
export const ScrcpyInjectKeyCodeControlMessage = new Struct()
|
||||
.uint8("type")
|
||||
.uint8("action", placeholder<AndroidKeyEventAction>())
|
||||
.uint32("keyCode", placeholder<AndroidKeyCode>())
|
||||
.uint32("repeat")
|
||||
.uint32("metaState", placeholder<AndroidKeyEventMeta>());
|
||||
export const ScrcpyInjectKeyCodeControlMessage =
|
||||
/* #__PURE__ */
|
||||
new Struct()
|
||||
.uint8("type")
|
||||
.uint8("action", placeholder<AndroidKeyEventAction>())
|
||||
.uint32("keyCode", placeholder<AndroidKeyCode>())
|
||||
.uint32("repeat")
|
||||
.uint32("metaState", placeholder<AndroidKeyEventMeta>());
|
||||
|
||||
export type ScrcpyInjectKeyCodeControlMessage =
|
||||
(typeof ScrcpyInjectKeyCodeControlMessage)["TInit"];
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import Struct from "@yume-chan/struct";
|
||||
|
||||
export const ScrcpyInjectTextControlMessage = new Struct()
|
||||
.uint8("type")
|
||||
.uint32("length")
|
||||
.string("text", { lengthField: "length" });
|
||||
export const ScrcpyInjectTextControlMessage =
|
||||
/* #__PURE__ */
|
||||
new Struct()
|
||||
.uint8("type")
|
||||
.uint32("length")
|
||||
.string("text", { lengthField: "length" });
|
||||
|
||||
export type ScrcpyInjectTextControlMessage =
|
||||
(typeof ScrcpyInjectTextControlMessage)["TInit"];
|
||||
|
|
|
@ -6,9 +6,11 @@ export enum AndroidScreenPowerMode {
|
|||
Normal = 2,
|
||||
}
|
||||
|
||||
export const ScrcpySetScreenPowerModeControlMessage = new Struct()
|
||||
.uint8("type")
|
||||
.uint8("mode", placeholder<AndroidScreenPowerMode>());
|
||||
export const ScrcpySetScreenPowerModeControlMessage =
|
||||
/* #__PURE__ */
|
||||
new Struct()
|
||||
.uint8("type")
|
||||
.uint8("mode", placeholder<AndroidScreenPowerMode>());
|
||||
|
||||
export type ScrcpySetScreenPowerModeControlMessage =
|
||||
(typeof ScrcpySetScreenPowerModeControlMessage)["TInit"];
|
||||
|
|
|
@ -23,37 +23,43 @@ export const SCRCPY_CONTROL_MESSAGE_TYPES_1_16: readonly ScrcpyControlMessageTyp
|
|||
/* 10 */ ScrcpyControlMessageType.RotateDevice,
|
||||
];
|
||||
|
||||
export const ScrcpyMediaStreamRawPacket = new Struct()
|
||||
.uint64("pts")
|
||||
.uint32("size")
|
||||
.uint8Array("data", { lengthField: "size" });
|
||||
export const ScrcpyMediaStreamRawPacket =
|
||||
/* #__PURE__ */
|
||||
new Struct()
|
||||
.uint64("pts")
|
||||
.uint32("size")
|
||||
.uint8Array("data", { lengthField: "size" });
|
||||
|
||||
export const SCRCPY_MEDIA_PACKET_FLAG_CONFIG = 1n << 63n;
|
||||
|
||||
export const ScrcpyInjectTouchControlMessage1_16 = new Struct()
|
||||
.uint8("type")
|
||||
.uint8("action", placeholder<AndroidMotionEventAction>())
|
||||
.uint64("pointerId")
|
||||
.uint32("pointerX")
|
||||
.uint32("pointerY")
|
||||
.uint16("screenWidth")
|
||||
.uint16("screenHeight")
|
||||
.field("pressure", ScrcpyUnsignedFloatFieldDefinition)
|
||||
.uint32("buttons");
|
||||
export const ScrcpyInjectTouchControlMessage1_16 =
|
||||
/* #__PURE__ */
|
||||
new Struct()
|
||||
.uint8("type")
|
||||
.uint8("action", placeholder<AndroidMotionEventAction>())
|
||||
.uint64("pointerId")
|
||||
.uint32("pointerX")
|
||||
.uint32("pointerY")
|
||||
.uint16("screenWidth")
|
||||
.uint16("screenHeight")
|
||||
.field("pressure", ScrcpyUnsignedFloatFieldDefinition)
|
||||
.uint32("buttons");
|
||||
|
||||
export type ScrcpyInjectTouchControlMessage1_16 =
|
||||
(typeof ScrcpyInjectTouchControlMessage1_16)["TInit"];
|
||||
|
||||
export const ScrcpyBackOrScreenOnControlMessage1_16 = EmptyControlMessage;
|
||||
|
||||
export const ScrcpySetClipboardControlMessage1_15 = new Struct()
|
||||
.uint8("type")
|
||||
.uint32("length")
|
||||
.string("content", { lengthField: "length" });
|
||||
export const ScrcpySetClipboardControlMessage1_15 =
|
||||
/* #__PURE__ */
|
||||
new Struct()
|
||||
.uint8("type")
|
||||
.uint32("length")
|
||||
.string("content", { lengthField: "length" });
|
||||
|
||||
export type ScrcpySetClipboardControlMessage1_15 =
|
||||
(typeof ScrcpySetClipboardControlMessage1_15)["TInit"];
|
||||
|
||||
export const ScrcpyClipboardDeviceMessage = new Struct()
|
||||
.uint32("length")
|
||||
.string("content", { lengthField: "length" });
|
||||
export const ScrcpyClipboardDeviceMessage =
|
||||
/* #__PURE__ */
|
||||
new Struct().uint32("length").string("content", { lengthField: "length" });
|
||||
|
|
|
@ -8,14 +8,16 @@ export interface ScrcpyScrollController {
|
|||
): Uint8Array | undefined;
|
||||
}
|
||||
|
||||
export const ScrcpyInjectScrollControlMessage1_16 = new Struct()
|
||||
.uint8("type")
|
||||
.uint32("pointerX")
|
||||
.uint32("pointerY")
|
||||
.uint16("screenWidth")
|
||||
.uint16("screenHeight")
|
||||
.int32("scrollX")
|
||||
.int32("scrollY");
|
||||
export const ScrcpyInjectScrollControlMessage1_16 =
|
||||
/* #__PURE__ */
|
||||
new Struct()
|
||||
.uint8("type")
|
||||
.uint32("pointerX")
|
||||
.uint32("pointerY")
|
||||
.uint16("screenWidth")
|
||||
.uint16("screenHeight")
|
||||
.int32("scrollX")
|
||||
.int32("scrollY");
|
||||
|
||||
/**
|
||||
* Old version of Scrcpy server only supports integer values for scroll.
|
||||
|
|
|
@ -42,9 +42,11 @@ export interface ScrcpyOptionsInit1_18
|
|||
powerOffOnClose?: boolean;
|
||||
}
|
||||
|
||||
export const ScrcpyBackOrScreenOnControlMessage1_18 = new Struct()
|
||||
.concat(ScrcpyBackOrScreenOnControlMessage1_16)
|
||||
.uint8("action", placeholder<AndroidKeyEventAction>());
|
||||
export const ScrcpyBackOrScreenOnControlMessage1_18 =
|
||||
/* #__PURE__ */
|
||||
new Struct()
|
||||
.concat(ScrcpyBackOrScreenOnControlMessage1_16)
|
||||
.uint8("action", placeholder<AndroidKeyEventAction>());
|
||||
|
||||
export type ScrcpyBackOrScreenOnControlMessage1_18 =
|
||||
(typeof ScrcpyBackOrScreenOnControlMessage1_18)["TInit"];
|
||||
|
|
|
@ -10,7 +10,9 @@ import type { ScrcpyOptionsInit1_18 } from "./1_18.js";
|
|||
import { ScrcpyOptions1_18 } from "./1_18.js";
|
||||
import { ScrcpyOptions, toScrcpyOptionValue } from "./types.js";
|
||||
|
||||
export const ScrcpyAckClipboardDeviceMessage = new Struct().uint64("sequence");
|
||||
export const ScrcpyAckClipboardDeviceMessage =
|
||||
/* #__PURE__ */
|
||||
new Struct().uint64("sequence");
|
||||
|
||||
export interface ScrcpyOptionsInit1_21 extends ScrcpyOptionsInit1_18 {
|
||||
clipboardAutosync?: boolean;
|
||||
|
@ -20,12 +22,14 @@ function toSnakeCase(input: string): string {
|
|||
return input.replace(/([A-Z])/g, "_$1").toLowerCase();
|
||||
}
|
||||
|
||||
export const ScrcpySetClipboardControlMessage1_21 = new Struct()
|
||||
.uint8("type")
|
||||
.uint64("sequence")
|
||||
.int8("paste", placeholder<boolean>())
|
||||
.uint32("length")
|
||||
.string("content", { lengthField: "length" });
|
||||
export const ScrcpySetClipboardControlMessage1_21 =
|
||||
/* #__PURE__ */
|
||||
new Struct()
|
||||
.uint8("type")
|
||||
.uint64("sequence")
|
||||
.int8("paste", placeholder<boolean>())
|
||||
.uint32("length")
|
||||
.string("content", { lengthField: "length" });
|
||||
|
||||
export type ScrcpySetClipboardControlMessage1_21 =
|
||||
(typeof ScrcpySetClipboardControlMessage1_21)["TInit"];
|
||||
|
|
|
@ -5,9 +5,9 @@ import {
|
|||
ScrcpyScrollController1_16,
|
||||
} from "../1_16/index.js";
|
||||
|
||||
export const ScrcpyInjectScrollControlMessage1_22 = new Struct()
|
||||
.concat(ScrcpyInjectScrollControlMessage1_16)
|
||||
.int32("buttons");
|
||||
export const ScrcpyInjectScrollControlMessage1_22 =
|
||||
/* #__PURE__ */
|
||||
new Struct().concat(ScrcpyInjectScrollControlMessage1_16).int32("buttons");
|
||||
|
||||
export type ScrcpyInjectScrollControlMessage1_22 =
|
||||
(typeof ScrcpyInjectScrollControlMessage1_22)["TInit"];
|
||||
|
|
|
@ -27,15 +27,17 @@ const ScrcpySignedFloatFieldDefinition = new NumberFieldDefinition(
|
|||
ScrcpySignedFloatNumberVariant,
|
||||
);
|
||||
|
||||
export const ScrcpyInjectScrollControlMessage1_25 = new Struct()
|
||||
.uint8("type", ScrcpyControlMessageType.InjectScroll as const)
|
||||
.uint32("pointerX")
|
||||
.uint32("pointerY")
|
||||
.uint16("screenWidth")
|
||||
.uint16("screenHeight")
|
||||
.field("scrollX", ScrcpySignedFloatFieldDefinition)
|
||||
.field("scrollY", ScrcpySignedFloatFieldDefinition)
|
||||
.int32("buttons");
|
||||
export const ScrcpyInjectScrollControlMessage1_25 =
|
||||
/* #__PURE__ */
|
||||
new Struct()
|
||||
.uint8("type", ScrcpyControlMessageType.InjectScroll as const)
|
||||
.uint32("pointerX")
|
||||
.uint32("pointerY")
|
||||
.uint16("screenWidth")
|
||||
.uint16("screenHeight")
|
||||
.field("scrollX", ScrcpySignedFloatFieldDefinition)
|
||||
.field("scrollY", ScrcpySignedFloatFieldDefinition)
|
||||
.int32("buttons");
|
||||
|
||||
export type ScrcpyInjectScrollControlMessage1_25 =
|
||||
(typeof ScrcpyInjectScrollControlMessage1_25)["TInit"];
|
||||
|
|
|
@ -30,17 +30,19 @@ import type {
|
|||
} from "./types.js";
|
||||
import { ScrcpyOptions } from "./types.js";
|
||||
|
||||
export const ScrcpyInjectTouchControlMessage2_0 = new Struct()
|
||||
.uint8("type")
|
||||
.uint8("action", placeholder<AndroidMotionEventAction>())
|
||||
.uint64("pointerId")
|
||||
.uint32("pointerX")
|
||||
.uint32("pointerY")
|
||||
.uint16("screenWidth")
|
||||
.uint16("screenHeight")
|
||||
.field("pressure", ScrcpyUnsignedFloatFieldDefinition)
|
||||
.uint32("actionButton")
|
||||
.uint32("buttons");
|
||||
export const ScrcpyInjectTouchControlMessage2_0 =
|
||||
/* #__PURE__ */
|
||||
new Struct()
|
||||
.uint8("type")
|
||||
.uint8("action", placeholder<AndroidMotionEventAction>())
|
||||
.uint64("pointerId")
|
||||
.uint32("pointerX")
|
||||
.uint32("pointerY")
|
||||
.uint16("screenWidth")
|
||||
.uint16("screenHeight")
|
||||
.field("pressure", ScrcpyUnsignedFloatFieldDefinition)
|
||||
.uint32("actionButton")
|
||||
.uint32("buttons");
|
||||
|
||||
export type ScrcpyInjectTouchControlMessage2_0 =
|
||||
(typeof ScrcpyInjectTouchControlMessage2_0)["TInit"];
|
||||
|
|
|
@ -17,6 +17,121 @@ function isPromiseLike(value: unknown): value is PromiseLike<unknown> {
|
|||
}
|
||||
|
||||
export class Consumable<T> {
|
||||
static readonly WritableStream = class WritableStream<
|
||||
in T,
|
||||
> extends NativeWritableStream<Consumable<T>> {
|
||||
static async write<T>(
|
||||
writer: WritableStreamDefaultWriter<Consumable<T>>,
|
||||
value: T,
|
||||
) {
|
||||
const consumable = new Consumable(value);
|
||||
await writer.write(consumable);
|
||||
await consumable.consumed;
|
||||
}
|
||||
|
||||
constructor(
|
||||
sink: Consumable.WritableStreamSink<T>,
|
||||
strategy?: QueuingStrategy<T>,
|
||||
) {
|
||||
let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
|
||||
if (strategy) {
|
||||
wrappedStrategy = {};
|
||||
if ("highWaterMark" in strategy) {
|
||||
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
||||
}
|
||||
if ("size" in strategy) {
|
||||
wrappedStrategy.size = (chunk) => {
|
||||
return strategy.size!(
|
||||
chunk instanceof Consumable ? chunk.value : chunk,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
super(
|
||||
{
|
||||
start(controller) {
|
||||
return sink.start?.(controller);
|
||||
},
|
||||
async write(chunk, controller) {
|
||||
await chunk.tryConsume((chunk) =>
|
||||
sink.write?.(chunk, controller),
|
||||
);
|
||||
},
|
||||
abort(reason) {
|
||||
return sink.abort?.(reason);
|
||||
},
|
||||
close() {
|
||||
return sink.close?.();
|
||||
},
|
||||
},
|
||||
wrappedStrategy,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
static readonly ReadableStream = class ReadableStream<
|
||||
T,
|
||||
> extends NativeReadableStream<Consumable<T>> {
|
||||
static async enqueue<T>(
|
||||
controller: { enqueue: (chunk: Consumable<T>) => void },
|
||||
chunk: T,
|
||||
) {
|
||||
const output = new Consumable(chunk);
|
||||
controller.enqueue(output);
|
||||
await output.consumed;
|
||||
}
|
||||
|
||||
constructor(
|
||||
source: Consumable.ReadableStreamSource<T>,
|
||||
strategy?: QueuingStrategy<T>,
|
||||
) {
|
||||
let wrappedController:
|
||||
| Consumable.ReadableStreamController<T>
|
||||
| undefined;
|
||||
|
||||
let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
|
||||
if (strategy) {
|
||||
wrappedStrategy = {};
|
||||
if ("highWaterMark" in strategy) {
|
||||
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
||||
}
|
||||
if ("size" in strategy) {
|
||||
wrappedStrategy.size = (chunk) => {
|
||||
return strategy.size!(chunk.value);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
super(
|
||||
{
|
||||
async start(controller) {
|
||||
wrappedController = {
|
||||
async enqueue(chunk) {
|
||||
await ReadableStream.enqueue(controller, chunk);
|
||||
},
|
||||
close() {
|
||||
controller.close();
|
||||
},
|
||||
error(reason) {
|
||||
controller.error(reason);
|
||||
},
|
||||
};
|
||||
|
||||
await source.start?.(wrappedController);
|
||||
},
|
||||
async pull() {
|
||||
await source.pull?.(wrappedController!);
|
||||
},
|
||||
async cancel(reason) {
|
||||
await source.cancel?.(reason);
|
||||
},
|
||||
},
|
||||
wrappedStrategy,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
readonly #task: Task;
|
||||
readonly #resolver: PromiseResolver<void>;
|
||||
|
||||
|
@ -76,58 +191,7 @@ export namespace Consumable {
|
|||
close?(): void | PromiseLike<void>;
|
||||
}
|
||||
|
||||
export class WritableStream<in T> extends NativeWritableStream<
|
||||
Consumable<T>
|
||||
> {
|
||||
static async write<T>(
|
||||
writer: WritableStreamDefaultWriter<Consumable<T>>,
|
||||
value: T,
|
||||
) {
|
||||
const consumable = new Consumable(value);
|
||||
await writer.write(consumable);
|
||||
await consumable.consumed;
|
||||
}
|
||||
|
||||
constructor(
|
||||
sink: WritableStreamSink<T>,
|
||||
strategy?: QueuingStrategy<T>,
|
||||
) {
|
||||
let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
|
||||
if (strategy) {
|
||||
wrappedStrategy = {};
|
||||
if ("highWaterMark" in strategy) {
|
||||
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
||||
}
|
||||
if ("size" in strategy) {
|
||||
wrappedStrategy.size = (chunk) => {
|
||||
return strategy.size!(
|
||||
chunk instanceof Consumable ? chunk.value : chunk,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
super(
|
||||
{
|
||||
start(controller) {
|
||||
return sink.start?.(controller);
|
||||
},
|
||||
async write(chunk, controller) {
|
||||
await chunk.tryConsume((chunk) =>
|
||||
sink.write?.(chunk, controller),
|
||||
);
|
||||
},
|
||||
abort(reason) {
|
||||
return sink.abort?.(reason);
|
||||
},
|
||||
close() {
|
||||
return sink.close?.();
|
||||
},
|
||||
},
|
||||
wrappedStrategy,
|
||||
);
|
||||
}
|
||||
}
|
||||
export type WritableStream<in T> = typeof Consumable.WritableStream<T>;
|
||||
|
||||
export interface ReadableStreamController<T> {
|
||||
enqueue(chunk: T): Promise<void>;
|
||||
|
@ -145,61 +209,5 @@ export namespace Consumable {
|
|||
cancel?(reason: unknown): void | PromiseLike<void>;
|
||||
}
|
||||
|
||||
export class ReadableStream<T> extends NativeReadableStream<Consumable<T>> {
|
||||
static async enqueue<T>(
|
||||
controller: { enqueue: (chunk: Consumable<T>) => void },
|
||||
chunk: T,
|
||||
) {
|
||||
const output = new Consumable(chunk);
|
||||
controller.enqueue(output);
|
||||
await output.consumed;
|
||||
}
|
||||
|
||||
constructor(
|
||||
source: ReadableStreamSource<T>,
|
||||
strategy?: QueuingStrategy<T>,
|
||||
) {
|
||||
let wrappedController: ReadableStreamController<T> | undefined;
|
||||
|
||||
let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
|
||||
if (strategy) {
|
||||
wrappedStrategy = {};
|
||||
if ("highWaterMark" in strategy) {
|
||||
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
||||
}
|
||||
if ("size" in strategy) {
|
||||
wrappedStrategy.size = (chunk) => {
|
||||
return strategy.size!(chunk.value);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
super(
|
||||
{
|
||||
async start(controller) {
|
||||
wrappedController = {
|
||||
async enqueue(chunk) {
|
||||
await ReadableStream.enqueue(controller, chunk);
|
||||
},
|
||||
close() {
|
||||
controller.close();
|
||||
},
|
||||
error(reason) {
|
||||
controller.error(reason);
|
||||
},
|
||||
};
|
||||
|
||||
await source.start?.(wrappedController);
|
||||
},
|
||||
async pull() {
|
||||
await source.pull?.(wrappedController!);
|
||||
},
|
||||
async cancel(reason) {
|
||||
await source.cancel?.(reason);
|
||||
},
|
||||
},
|
||||
wrappedStrategy,
|
||||
);
|
||||
}
|
||||
}
|
||||
export type ReadableStream<T> = typeof Consumable.ReadableStream<T>;
|
||||
}
|
||||
|
|
90
libraries/stream-extra/src/maybe-consumable-ns.ts
Normal file
90
libraries/stream-extra/src/maybe-consumable-ns.ts
Normal file
|
@ -0,0 +1,90 @@
|
|||
import { Consumable } from "./consumable.js";
|
||||
import type { MaybeConsumable } from "./maybe-consumable.js";
|
||||
import type {
|
||||
QueuingStrategy,
|
||||
WritableStreamDefaultController,
|
||||
} from "./stream.js";
|
||||
import {
|
||||
WritableStream as NativeWritableStream,
|
||||
TransformStream,
|
||||
} from "./stream.js";
|
||||
|
||||
export function getValue<T>(value: MaybeConsumable<T>): T {
|
||||
return value instanceof Consumable ? value.value : value;
|
||||
}
|
||||
|
||||
export function tryConsume<T, R>(
|
||||
value: T,
|
||||
callback: (value: T extends Consumable<infer U> ? U : T) => R,
|
||||
): R {
|
||||
if (value instanceof Consumable) {
|
||||
return value.tryConsume(callback);
|
||||
} else {
|
||||
return callback(value as never);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnwrapStream<T> extends TransformStream<MaybeConsumable<T>, T> {
|
||||
constructor() {
|
||||
super({
|
||||
transform(chunk, controller) {
|
||||
tryConsume(chunk, (chunk) => {
|
||||
controller.enqueue(chunk as T);
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface WritableStreamSink<in T> {
|
||||
start?(
|
||||
controller: WritableStreamDefaultController,
|
||||
): void | PromiseLike<void>;
|
||||
write?(
|
||||
chunk: T,
|
||||
controller: WritableStreamDefaultController,
|
||||
): void | PromiseLike<void>;
|
||||
abort?(reason: unknown): void | PromiseLike<void>;
|
||||
close?(): void | PromiseLike<void>;
|
||||
}
|
||||
|
||||
export class WritableStream<in T> extends NativeWritableStream<
|
||||
MaybeConsumable<T>
|
||||
> {
|
||||
constructor(sink: WritableStreamSink<T>, strategy?: QueuingStrategy<T>) {
|
||||
let wrappedStrategy: QueuingStrategy<MaybeConsumable<T>> | undefined;
|
||||
if (strategy) {
|
||||
wrappedStrategy = {};
|
||||
if ("highWaterMark" in strategy) {
|
||||
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
||||
}
|
||||
if ("size" in strategy) {
|
||||
wrappedStrategy.size = (chunk) => {
|
||||
return strategy.size!(
|
||||
chunk instanceof Consumable ? chunk.value : chunk,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
super(
|
||||
{
|
||||
start(controller) {
|
||||
return sink.start?.(controller);
|
||||
},
|
||||
async write(chunk, controller) {
|
||||
await tryConsume(chunk, (chunk) =>
|
||||
sink.write?.(chunk as T, controller),
|
||||
);
|
||||
},
|
||||
abort(reason) {
|
||||
return sink.abort?.(reason);
|
||||
},
|
||||
close() {
|
||||
return sink.close?.();
|
||||
},
|
||||
},
|
||||
wrappedStrategy,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,101 +1,5 @@
|
|||
import { Consumable } from "./consumable.js";
|
||||
import type {
|
||||
QueuingStrategy,
|
||||
WritableStreamDefaultController,
|
||||
} from "./stream.js";
|
||||
import {
|
||||
WritableStream as NativeWritableStream,
|
||||
TransformStream,
|
||||
} from "./stream.js";
|
||||
import type { Consumable } from "./consumable.js";
|
||||
|
||||
export type MaybeConsumable<T> = T | Consumable<T>;
|
||||
|
||||
export namespace MaybeConsumable {
|
||||
export function getValue<T>(value: MaybeConsumable<T>): T {
|
||||
return value instanceof Consumable ? value.value : value;
|
||||
}
|
||||
|
||||
export function tryConsume<T, R>(
|
||||
value: T,
|
||||
callback: (value: T extends Consumable<infer U> ? U : T) => R,
|
||||
): R {
|
||||
if (value instanceof Consumable) {
|
||||
return value.tryConsume(callback);
|
||||
} else {
|
||||
return callback(value as never);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnwrapStream<T> extends TransformStream<
|
||||
MaybeConsumable<T>,
|
||||
T
|
||||
> {
|
||||
constructor() {
|
||||
super({
|
||||
transform(chunk, controller) {
|
||||
MaybeConsumable.tryConsume(chunk, (chunk) => {
|
||||
controller.enqueue(chunk as T);
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface WritableStreamSink<in T> {
|
||||
start?(
|
||||
controller: WritableStreamDefaultController,
|
||||
): void | PromiseLike<void>;
|
||||
write?(
|
||||
chunk: T,
|
||||
controller: WritableStreamDefaultController,
|
||||
): void | PromiseLike<void>;
|
||||
abort?(reason: unknown): void | PromiseLike<void>;
|
||||
close?(): void | PromiseLike<void>;
|
||||
}
|
||||
|
||||
export class WritableStream<in T> extends NativeWritableStream<
|
||||
MaybeConsumable<T>
|
||||
> {
|
||||
constructor(
|
||||
sink: WritableStreamSink<T>,
|
||||
strategy?: QueuingStrategy<T>,
|
||||
) {
|
||||
let wrappedStrategy:
|
||||
| QueuingStrategy<MaybeConsumable<T>>
|
||||
| undefined;
|
||||
if (strategy) {
|
||||
wrappedStrategy = {};
|
||||
if ("highWaterMark" in strategy) {
|
||||
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
||||
}
|
||||
if ("size" in strategy) {
|
||||
wrappedStrategy.size = (chunk) => {
|
||||
return strategy.size!(
|
||||
chunk instanceof Consumable ? chunk.value : chunk,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
super(
|
||||
{
|
||||
start(controller) {
|
||||
return sink.start?.(controller);
|
||||
},
|
||||
async write(chunk, controller) {
|
||||
await MaybeConsumable.tryConsume(chunk, (chunk) =>
|
||||
sink.write?.(chunk as T, controller),
|
||||
);
|
||||
},
|
||||
abort(reason) {
|
||||
return sink.abort?.(reason);
|
||||
},
|
||||
close() {
|
||||
return sink.close?.();
|
||||
},
|
||||
},
|
||||
wrappedStrategy,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
export * as MaybeConsumable from "./maybe-consumable-ns.js";
|
||||
|
|
|
@ -32,15 +32,13 @@ interface GlobalExtension {
|
|||
TransformStream: typeof TransformStreamType;
|
||||
}
|
||||
|
||||
const Global = globalThis as unknown as GlobalExtension;
|
||||
|
||||
export const AbortController = Global.AbortController;
|
||||
|
||||
export type ReadableStream<out T> = ReadableStreamType<T>;
|
||||
export const ReadableStream = Global.ReadableStream;
|
||||
|
||||
export type WritableStream<in T> = WritableStreamType<T>;
|
||||
export const WritableStream = Global.WritableStream;
|
||||
|
||||
export type TransformStream<I, O> = TransformStreamType<I, O>;
|
||||
export const TransformStream = Global.TransformStream;
|
||||
|
||||
export const {
|
||||
AbortController,
|
||||
ReadableStream,
|
||||
WritableStream,
|
||||
TransformStream,
|
||||
} = globalThis as unknown as GlobalExtension;
|
||||
|
|
|
@ -33,7 +33,7 @@ class MockDeserializationStream implements ExactReadable {
|
|||
describe("Struct", () => {
|
||||
describe(".constructor", () => {
|
||||
it("should initialize fields", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
assert.deepStrictEqual(struct.options, StructDefaultOptions);
|
||||
assert.strictEqual(struct.size, 0);
|
||||
});
|
||||
|
@ -82,7 +82,7 @@ describe("Struct", () => {
|
|||
}
|
||||
|
||||
it("should push a field and update size", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
|
||||
const field1 = "foo";
|
||||
const fieldDefinition1 = new MockFieldDefinition(4);
|
||||
|
@ -104,7 +104,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("should throw an error if field name already exists", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
const fieldName = "foo";
|
||||
struct.field(fieldName, new MockFieldDefinition(4));
|
||||
assert.throws(() => {
|
||||
|
@ -115,7 +115,7 @@ describe("Struct", () => {
|
|||
|
||||
describe("#number", () => {
|
||||
it("`int8` should append an `int8` field", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
struct.int8("foo");
|
||||
assert.strictEqual(struct.size, 1);
|
||||
|
||||
|
@ -125,7 +125,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("`uint8` should append an `uint8` field", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
struct.uint8("foo");
|
||||
assert.strictEqual(struct.size, 1);
|
||||
|
||||
|
@ -135,7 +135,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("`int16` should append an `int16` field", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
struct.int16("foo");
|
||||
assert.strictEqual(struct.size, 2);
|
||||
|
||||
|
@ -145,7 +145,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("`uint16` should append an `uint16` field", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
struct.uint16("foo");
|
||||
assert.strictEqual(struct.size, 2);
|
||||
|
||||
|
@ -155,7 +155,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("`int32` should append an `int32` field", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
struct.int32("foo");
|
||||
assert.strictEqual(struct.size, 4);
|
||||
|
||||
|
@ -165,7 +165,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("`uint32` should append an `uint32` field", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
struct.uint32("foo");
|
||||
assert.strictEqual(struct.size, 4);
|
||||
|
||||
|
@ -175,7 +175,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("`int64` should append an `int64` field", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
struct.int64("foo");
|
||||
assert.strictEqual(struct.size, 8);
|
||||
|
||||
|
@ -185,7 +185,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("`uint64` should append an `uint64` field", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
struct.uint64("foo");
|
||||
assert.strictEqual(struct.size, 8);
|
||||
|
||||
|
@ -197,7 +197,7 @@ describe("Struct", () => {
|
|||
describe("#uint8ArrayLike", () => {
|
||||
describe("FixedLengthBufferLikeFieldDefinition", () => {
|
||||
it("`#uint8Array` with fixed length", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
struct.uint8Array("foo", { length: 10 });
|
||||
assert.strictEqual(struct.size, 10);
|
||||
|
||||
|
@ -214,7 +214,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("`#string` with fixed length", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
struct.string("foo", { length: 10 });
|
||||
assert.strictEqual(struct.size, 10);
|
||||
|
||||
|
@ -233,7 +233,9 @@ describe("Struct", () => {
|
|||
|
||||
describe("VariableLengthBufferLikeFieldDefinition", () => {
|
||||
it("`#uint8Array` with variable length", () => {
|
||||
const struct = new Struct().int8("barLength");
|
||||
const struct = /* #__PURE__ */ new Struct().int8(
|
||||
"barLength",
|
||||
);
|
||||
assert.strictEqual(struct.size, 1);
|
||||
|
||||
struct.uint8Array("bar", { lengthField: "barLength" });
|
||||
|
@ -255,7 +257,9 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("`#string` with variable length", () => {
|
||||
const struct = new Struct().int8("barLength");
|
||||
const struct = /* #__PURE__ */ new Struct().int8(
|
||||
"barLength",
|
||||
);
|
||||
assert.strictEqual(struct.size, 1);
|
||||
|
||||
struct.string("bar", { lengthField: "barLength" });
|
||||
|
@ -280,9 +284,11 @@ describe("Struct", () => {
|
|||
|
||||
describe("#concat", () => {
|
||||
it("should append all fields from other struct", () => {
|
||||
const sub = new Struct().int16("int16").int32("int32");
|
||||
const sub = /* #__PURE__ */ new Struct()
|
||||
.int16("int16")
|
||||
.int32("int32");
|
||||
|
||||
const struct = new Struct()
|
||||
const struct = /* #__PURE__ */ new Struct()
|
||||
.int8("int8")
|
||||
.concat(sub)
|
||||
.int64("int64");
|
||||
|
@ -312,7 +318,9 @@ describe("Struct", () => {
|
|||
|
||||
describe("#deserialize", () => {
|
||||
it("should deserialize without dynamic size fields", () => {
|
||||
const struct = new Struct().int8("foo").int16("bar");
|
||||
const struct = /* #__PURE__ */ new Struct()
|
||||
.int8("foo")
|
||||
.int16("bar");
|
||||
|
||||
const stream = new MockDeserializationStream();
|
||||
stream.readExactly.mock.mockImplementationOnce(
|
||||
|
@ -339,7 +347,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("should deserialize with dynamic size fields", () => {
|
||||
const struct = new Struct()
|
||||
const struct = /* #__PURE__ */ new Struct()
|
||||
.int8("fooLength")
|
||||
.uint8Array("foo", { lengthField: "fooLength" });
|
||||
|
||||
|
@ -376,7 +384,10 @@ describe("Struct", () => {
|
|||
|
||||
describe("#extra", () => {
|
||||
it("should accept plain field", () => {
|
||||
const struct = new Struct().extra({ foo: 42, bar: true });
|
||||
const struct = /* #__PURE__ */ new Struct().extra({
|
||||
foo: 42,
|
||||
bar: true,
|
||||
});
|
||||
|
||||
const stream = new MockDeserializationStream();
|
||||
const result = struct.deserialize(stream);
|
||||
|
@ -411,7 +422,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("should accept accessors", () => {
|
||||
const struct = new Struct().extra({
|
||||
const struct = /* #__PURE__ */ new Struct().extra({
|
||||
get foo() {
|
||||
return 42;
|
||||
},
|
||||
|
@ -438,7 +449,7 @@ describe("Struct", () => {
|
|||
|
||||
describe("#postDeserialize", () => {
|
||||
it("can throw errors", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
const callback = mock.fn(() => {
|
||||
throw new Error("mock");
|
||||
});
|
||||
|
@ -450,7 +461,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("can replace return value", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
const callback = mock.fn(() => "mock");
|
||||
struct.postDeserialize(callback);
|
||||
|
||||
|
@ -461,7 +472,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("can return nothing", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
const callback = mock.fn();
|
||||
struct.postDeserialize(callback);
|
||||
|
||||
|
@ -473,7 +484,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("should overwrite callback", () => {
|
||||
const struct = new Struct();
|
||||
const struct = /* #__PURE__ */ new Struct();
|
||||
|
||||
const callback1 = mock.fn();
|
||||
struct.postDeserialize(callback1);
|
||||
|
@ -492,7 +503,9 @@ describe("Struct", () => {
|
|||
|
||||
describe("#serialize", () => {
|
||||
it("should serialize without dynamic size fields", () => {
|
||||
const struct = new Struct().int8("foo").int16("bar");
|
||||
const struct = /* #__PURE__ */ new Struct()
|
||||
.int8("foo")
|
||||
.int16("bar");
|
||||
|
||||
const result = new Uint8Array(
|
||||
struct.serialize({ foo: 0x42, bar: 0x1024 }),
|
||||
|
@ -505,7 +518,7 @@ describe("Struct", () => {
|
|||
});
|
||||
|
||||
it("should serialize with dynamic size fields", () => {
|
||||
const struct = new Struct()
|
||||
const struct = /* #__PURE__ */ new Struct()
|
||||
.int8("fooLength")
|
||||
.uint8Array("foo", { lengthField: "fooLength" });
|
||||
|
||||
|
|
|
@ -82,9 +82,10 @@ interface GlobalExtension {
|
|||
|
||||
const { TextEncoder, TextDecoder } = globalThis as unknown as GlobalExtension;
|
||||
|
||||
const SharedEncoder = new TextEncoder();
|
||||
const SharedDecoder = new TextDecoder();
|
||||
const SharedEncoder = /* #__PURE__ */ new TextEncoder();
|
||||
const SharedDecoder = /* #__PURE__ */ new TextDecoder();
|
||||
|
||||
/* #__NO_SIDE_EFFECTS__ */
|
||||
export function encodeUtf8(input: string): Uint8Array {
|
||||
return SharedEncoder.encode(input);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue