mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-05 19:42:15 +02:00
refactor(struct): improve tree-shaking
This commit is contained in:
parent
e8d59b232e
commit
c91baa9116
32 changed files with 266 additions and 266 deletions
|
@ -1,12 +1,12 @@
|
||||||
import { BufferedReadableStream } from "@yume-chan/stream-extra";
|
import { BufferedReadableStream } from "@yume-chan/stream-extra";
|
||||||
import type { StructValue } from "@yume-chan/struct";
|
import type { StructValue } from "@yume-chan/struct";
|
||||||
import { buffer, Struct, StructEmptyError, u32 } from "@yume-chan/struct";
|
import { buffer, struct, StructEmptyError, u32 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import type { Adb } from "../adb.js";
|
import type { Adb } from "../adb.js";
|
||||||
|
|
||||||
const Version = new Struct({ version: u32 }, { littleEndian: true });
|
const Version = struct({ version: u32 }, { littleEndian: true });
|
||||||
|
|
||||||
export const AdbFrameBufferV1 = new Struct(
|
export const AdbFrameBufferV1 = struct(
|
||||||
{
|
{
|
||||||
bpp: u32,
|
bpp: u32,
|
||||||
size: u32,
|
size: u32,
|
||||||
|
@ -27,7 +27,7 @@ export const AdbFrameBufferV1 = new Struct(
|
||||||
|
|
||||||
export type AdbFrameBufferV1 = StructValue<typeof AdbFrameBufferV1>;
|
export type AdbFrameBufferV1 = StructValue<typeof AdbFrameBufferV1>;
|
||||||
|
|
||||||
export const AdbFrameBufferV2 = new Struct(
|
export const AdbFrameBufferV2 = struct(
|
||||||
{
|
{
|
||||||
bpp: u32,
|
bpp: u32,
|
||||||
colorSpace: u32,
|
colorSpace: u32,
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
import { BufferedReadableStream } from "@yume-chan/stream-extra";
|
import { BufferedReadableStream } from "@yume-chan/stream-extra";
|
||||||
import {
|
import {
|
||||||
ExactReadableEndedError,
|
|
||||||
Struct,
|
|
||||||
encodeUtf8,
|
encodeUtf8,
|
||||||
|
ExactReadableEndedError,
|
||||||
string,
|
string,
|
||||||
|
struct,
|
||||||
} from "@yume-chan/struct";
|
} from "@yume-chan/struct";
|
||||||
|
|
||||||
import type { Adb, AdbIncomingSocketHandler } from "../adb.js";
|
import type { Adb, AdbIncomingSocketHandler } from "../adb.js";
|
||||||
|
@ -19,7 +19,7 @@ export interface AdbForwardListener {
|
||||||
remoteName: string;
|
remoteName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AdbReverseStringResponse = new Struct(
|
const AdbReverseStringResponse = struct(
|
||||||
{
|
{
|
||||||
length: string(4),
|
length: string(4),
|
||||||
content: string({
|
content: string({
|
||||||
|
@ -38,7 +38,6 @@ const AdbReverseStringResponse = new Struct(
|
||||||
export class AdbReverseError extends Error {
|
export class AdbReverseError extends Error {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
super(message);
|
super(message);
|
||||||
Object.setPrototypeOf(this, new.target.prototype);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +49,9 @@ export class AdbReverseNotSupportedError extends AdbReverseError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AdbReverseErrorResponse = new Struct(AdbReverseStringResponse.fields, {
|
const AdbReverseErrorResponse = struct(
|
||||||
|
/* #__PURE__ */ (() => AdbReverseStringResponse.fields)(),
|
||||||
|
{
|
||||||
littleEndian: true,
|
littleEndian: true,
|
||||||
postDeserialize: (value) => {
|
postDeserialize: (value) => {
|
||||||
// https://issuetracker.google.com/issues/37066218
|
// https://issuetracker.google.com/issues/37066218
|
||||||
|
@ -62,7 +63,8 @@ const AdbReverseErrorResponse = new Struct(AdbReverseStringResponse.fields, {
|
||||||
throw new AdbReverseError(value.content);
|
throw new AdbReverseError(value.content);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// Like `hexToNumber`, it's much faster than first converting `buffer` to a string
|
// Like `hexToNumber`, it's much faster than first converting `buffer` to a string
|
||||||
function decimalToNumber(buffer: Uint8Array) {
|
function decimalToNumber(buffer: Uint8Array) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
WritableStream,
|
WritableStream,
|
||||||
} from "@yume-chan/stream-extra";
|
} from "@yume-chan/stream-extra";
|
||||||
import type { StructValue } from "@yume-chan/struct";
|
import type { StructValue } from "@yume-chan/struct";
|
||||||
import { Struct, buffer, u32, u8 } from "@yume-chan/struct";
|
import { buffer, struct, u32, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import type { Adb, AdbSocket } from "../../../adb.js";
|
import type { Adb, AdbSocket } from "../../../adb.js";
|
||||||
import { AdbFeature } from "../../../features.js";
|
import { AdbFeature } from "../../../features.js";
|
||||||
|
@ -32,7 +32,7 @@ export type AdbShellProtocolId =
|
||||||
(typeof AdbShellProtocolId)[keyof typeof AdbShellProtocolId];
|
(typeof AdbShellProtocolId)[keyof typeof AdbShellProtocolId];
|
||||||
|
|
||||||
// This packet format is used in both directions.
|
// This packet format is used in both directions.
|
||||||
export const AdbShellProtocolPacket = new Struct(
|
export const AdbShellProtocolPacket = struct(
|
||||||
{
|
{
|
||||||
id: u8.as<AdbShellProtocolId>(),
|
id: u8.as<AdbShellProtocolId>(),
|
||||||
data: buffer(u32),
|
data: buffer(u32),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { StructValue } from "@yume-chan/struct";
|
import type { StructValue } from "@yume-chan/struct";
|
||||||
import { Struct, string, u32 } from "@yume-chan/struct";
|
import { string, struct, u32 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
||||||
import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js";
|
import { AdbSyncResponseId, adbSyncReadResponses } from "./response.js";
|
||||||
|
@ -15,21 +15,21 @@ export interface AdbSyncEntry extends AdbSyncStat {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdbSyncEntryResponse = new Struct(
|
export const AdbSyncEntryResponse = struct(
|
||||||
{
|
/* #__PURE__ */ (() => ({
|
||||||
...AdbSyncLstatResponse.fields,
|
...AdbSyncLstatResponse.fields,
|
||||||
name: string(u32),
|
name: string(u32),
|
||||||
},
|
}))(),
|
||||||
{ littleEndian: true, extra: AdbSyncLstatResponse.extra },
|
{ littleEndian: true, extra: AdbSyncLstatResponse.extra },
|
||||||
);
|
);
|
||||||
|
|
||||||
export type AdbSyncEntryResponse = StructValue<typeof AdbSyncEntryResponse>;
|
export type AdbSyncEntryResponse = StructValue<typeof AdbSyncEntryResponse>;
|
||||||
|
|
||||||
export const AdbSyncEntry2Response = new Struct(
|
export const AdbSyncEntry2Response = struct(
|
||||||
{
|
/* #__PURE__ */ (() => ({
|
||||||
...AdbSyncStatResponse.fields,
|
...AdbSyncStatResponse.fields,
|
||||||
name: string(u32),
|
name: string(u32),
|
||||||
},
|
}))(),
|
||||||
{ littleEndian: true, extra: AdbSyncStatResponse.extra },
|
{ littleEndian: true, extra: AdbSyncStatResponse.extra },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import type { ReadableStream } from "@yume-chan/stream-extra";
|
import type { ReadableStream } from "@yume-chan/stream-extra";
|
||||||
import { PushReadableStream } from "@yume-chan/stream-extra";
|
import { PushReadableStream } from "@yume-chan/stream-extra";
|
||||||
import type { StructValue } from "@yume-chan/struct";
|
import type { StructValue } from "@yume-chan/struct";
|
||||||
import { buffer, Struct, u32 } from "@yume-chan/struct";
|
import { buffer, struct, u32 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
||||||
import { adbSyncReadResponses, AdbSyncResponseId } from "./response.js";
|
import { adbSyncReadResponses, AdbSyncResponseId } from "./response.js";
|
||||||
import type { AdbSyncSocket } from "./socket.js";
|
import type { AdbSyncSocket } from "./socket.js";
|
||||||
|
|
||||||
export const AdbSyncDataResponse = new Struct(
|
export const AdbSyncDataResponse = struct(
|
||||||
{ data: buffer(u32) },
|
{ data: buffer(u32) },
|
||||||
{ littleEndian: true },
|
{ littleEndian: true },
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
DistributionStream,
|
DistributionStream,
|
||||||
MaybeConsumable,
|
MaybeConsumable,
|
||||||
} from "@yume-chan/stream-extra";
|
} from "@yume-chan/stream-extra";
|
||||||
import { Struct, u32 } from "@yume-chan/struct";
|
import { struct, u32 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import { NOOP } from "../../utils/index.js";
|
import { NOOP } from "../../utils/index.js";
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ export interface AdbSyncPushV1Options {
|
||||||
packetSize?: number;
|
packetSize?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdbSyncOkResponse = new Struct(
|
export const AdbSyncOkResponse = struct(
|
||||||
{ unused: u32 },
|
{ unused: u32 },
|
||||||
{ littleEndian: true },
|
{ littleEndian: true },
|
||||||
);
|
);
|
||||||
|
@ -114,7 +114,7 @@ export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
|
||||||
dryRun?: boolean;
|
dryRun?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdbSyncSendV2Request = new Struct(
|
export const AdbSyncSendV2Request = struct(
|
||||||
{ id: u32, mode: u32, flags: u32.as<AdbSyncSendV2Flags>() },
|
{ id: u32, mode: u32, flags: u32.as<AdbSyncSendV2Flags>() },
|
||||||
{ littleEndian: true },
|
{ littleEndian: true },
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { encodeUtf8, Struct, u32 } from "@yume-chan/struct";
|
import { encodeUtf8, struct, u32 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import { adbSyncEncodeId } from "./response.js";
|
import { adbSyncEncodeId } from "./response.js";
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ export const AdbSyncRequestId = {
|
||||||
Receive: adbSyncEncodeId("RECV"),
|
Receive: adbSyncEncodeId("RECV"),
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const AdbSyncNumberRequest = new Struct(
|
export const AdbSyncNumberRequest = struct(
|
||||||
{ id: u32, arg: u32 },
|
{ id: u32, arg: u32 },
|
||||||
{ littleEndian: true },
|
{ littleEndian: true },
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { getUint32LittleEndian } from "@yume-chan/no-data-view";
|
import { getUint32LittleEndian } from "@yume-chan/no-data-view";
|
||||||
import type { AsyncExactReadable, StructLike } from "@yume-chan/struct";
|
import type { AsyncExactReadable, StructLike } from "@yume-chan/struct";
|
||||||
import { Struct, decodeUtf8, string, u32 } from "@yume-chan/struct";
|
import { decodeUtf8, string, struct, u32 } from "@yume-chan/struct";
|
||||||
|
|
||||||
function encodeAsciiUnchecked(value: string): Uint8Array {
|
function encodeAsciiUnchecked(value: string): Uint8Array {
|
||||||
const result = new Uint8Array(value.length);
|
const result = new Uint8Array(value.length);
|
||||||
|
@ -36,7 +36,7 @@ export const AdbSyncResponseId = {
|
||||||
|
|
||||||
export class AdbSyncError extends Error {}
|
export class AdbSyncError extends Error {}
|
||||||
|
|
||||||
export const AdbSyncFailResponse = new Struct(
|
export const AdbSyncFailResponse = struct(
|
||||||
{ message: string(u32) },
|
{ message: string(u32) },
|
||||||
{
|
{
|
||||||
littleEndian: true,
|
littleEndian: true,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { StructValue } from "@yume-chan/struct";
|
import type { StructValue } from "@yume-chan/struct";
|
||||||
import { Struct, u32, u64 } from "@yume-chan/struct";
|
import { struct, u32, u64 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
import { AdbSyncRequestId, adbSyncWriteRequest } from "./request.js";
|
||||||
import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
|
import { AdbSyncResponseId, adbSyncReadResponse } from "./response.js";
|
||||||
|
@ -27,7 +27,7 @@ export interface AdbSyncStat {
|
||||||
ctime?: bigint;
|
ctime?: bigint;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdbSyncLstatResponse = new Struct(
|
export const AdbSyncLstatResponse = struct(
|
||||||
{ mode: u32, size: u32, mtime: u32 },
|
{ mode: u32, size: u32, mtime: u32 },
|
||||||
{
|
{
|
||||||
littleEndian: true,
|
littleEndian: true,
|
||||||
|
@ -86,7 +86,7 @@ const AdbSyncStatErrorName =
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const AdbSyncStatResponse = new Struct(
|
export const AdbSyncStatResponse = struct(
|
||||||
{
|
{
|
||||||
error: u32.as<AdbSyncStatErrorCode>(),
|
error: u32.as<AdbSyncStatErrorCode>(),
|
||||||
dev: u64,
|
dev: u64,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Consumable, TransformStream } from "@yume-chan/stream-extra";
|
import { Consumable, TransformStream } from "@yume-chan/stream-extra";
|
||||||
import type { StructInit, StructValue } from "@yume-chan/struct";
|
import type { StructInit, StructValue } from "@yume-chan/struct";
|
||||||
import { buffer, s32, Struct, u32 } from "@yume-chan/struct";
|
import { buffer, s32, struct, u32 } from "@yume-chan/struct";
|
||||||
|
|
||||||
export const AdbCommand = {
|
export const AdbCommand = {
|
||||||
Auth: 0x48545541, // 'AUTH'
|
Auth: 0x48545541, // 'AUTH'
|
||||||
|
@ -13,7 +13,7 @@ export const AdbCommand = {
|
||||||
|
|
||||||
export type AdbCommand = (typeof AdbCommand)[keyof typeof AdbCommand];
|
export type AdbCommand = (typeof AdbCommand)[keyof typeof AdbCommand];
|
||||||
|
|
||||||
export const AdbPacketHeader = new Struct(
|
export const AdbPacketHeader = struct(
|
||||||
{
|
{
|
||||||
command: u32,
|
command: u32,
|
||||||
arg0: u32,
|
arg0: u32,
|
||||||
|
@ -29,8 +29,11 @@ export type AdbPacketHeader = StructValue<typeof AdbPacketHeader>;
|
||||||
|
|
||||||
type AdbPacketHeaderInit = StructInit<typeof AdbPacketHeader>;
|
type AdbPacketHeaderInit = StructInit<typeof AdbPacketHeader>;
|
||||||
|
|
||||||
export const AdbPacket = new Struct(
|
export const AdbPacket = struct(
|
||||||
{ ...AdbPacketHeader.fields, payload: buffer("payloadLength") },
|
/* #__PURE__ */ (() => ({
|
||||||
|
...AdbPacketHeader.fields,
|
||||||
|
payload: buffer("payloadLength"),
|
||||||
|
}))(),
|
||||||
{ littleEndian: true },
|
{ littleEndian: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
WritableStream,
|
WritableStream,
|
||||||
} from "@yume-chan/stream-extra";
|
} from "@yume-chan/stream-extra";
|
||||||
import type { AsyncExactReadable, StructValue } from "@yume-chan/struct";
|
import type { AsyncExactReadable, StructValue } from "@yume-chan/struct";
|
||||||
import { Struct, decodeUtf8, u16, u32 } from "@yume-chan/struct";
|
import { decodeUtf8, struct, u16, u32 } from "@yume-chan/struct";
|
||||||
|
|
||||||
// `adb logcat` is an alias to `adb shell logcat`
|
// `adb logcat` is an alias to `adb shell logcat`
|
||||||
// so instead of adding to core library, it's implemented here
|
// so instead of adding to core library, it's implemented here
|
||||||
|
@ -99,7 +99,7 @@ export interface LogcatOptions {
|
||||||
const NANOSECONDS_PER_SECOND = /* #__PURE__ */ BigInt(1e9);
|
const NANOSECONDS_PER_SECOND = /* #__PURE__ */ BigInt(1e9);
|
||||||
|
|
||||||
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/include/log/log_read.h;l=39;drc=82b5738732161dbaafb2e2f25cce19cd26b9157d
|
// 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(
|
export const LoggerEntry = struct(
|
||||||
{
|
{
|
||||||
payloadSize: u16,
|
payloadSize: u16,
|
||||||
headerSize: u16,
|
headerSize: u16,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { StructInit } from "@yume-chan/struct";
|
import type { StructInit } from "@yume-chan/struct";
|
||||||
import { Struct, u8 } from "@yume-chan/struct";
|
import { struct, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
export const EmptyControlMessage = new Struct(
|
export const EmptyControlMessage = struct(
|
||||||
{ type: u8 },
|
{ type: u8 },
|
||||||
{ littleEndian: false },
|
{ littleEndian: false },
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { StructInit } from "@yume-chan/struct";
|
import type { StructInit } from "@yume-chan/struct";
|
||||||
import { Struct, u32, u8 } from "@yume-chan/struct";
|
import { struct, u32, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
export enum AndroidKeyEventAction {
|
export enum AndroidKeyEventAction {
|
||||||
Down = 0,
|
Down = 0,
|
||||||
|
@ -206,7 +206,7 @@ export enum AndroidKeyCode {
|
||||||
AndroidPaste,
|
AndroidPaste,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScrcpyInjectKeyCodeControlMessage = new Struct(
|
export const ScrcpyInjectKeyCodeControlMessage = struct(
|
||||||
{
|
{
|
||||||
type: u8,
|
type: u8,
|
||||||
action: u8.as<AndroidKeyEventAction>(),
|
action: u8.as<AndroidKeyEventAction>(),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { StructInit } from "@yume-chan/struct";
|
import type { StructInit } from "@yume-chan/struct";
|
||||||
import { string, Struct, u32, u8 } from "@yume-chan/struct";
|
import { string, struct, u32, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
export const ScrcpyInjectTextControlMessage = new Struct(
|
export const ScrcpyInjectTextControlMessage = struct(
|
||||||
{ type: u8, text: string(u32) },
|
{ type: u8, text: string(u32) },
|
||||||
{ littleEndian: false },
|
{ littleEndian: false },
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { StructInit } from "@yume-chan/struct";
|
import type { StructInit } from "@yume-chan/struct";
|
||||||
import { Struct, u8 } from "@yume-chan/struct";
|
import { struct, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/SurfaceControl.java;l=659;drc=20303e05bf73796124ab70a279cf849b61b97905
|
// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/SurfaceControl.java;l=659;drc=20303e05bf73796124ab70a279cf849b61b97905
|
||||||
export const AndroidScreenPowerMode = {
|
export const AndroidScreenPowerMode = {
|
||||||
|
@ -10,7 +10,7 @@ export const AndroidScreenPowerMode = {
|
||||||
export type AndroidScreenPowerMode =
|
export type AndroidScreenPowerMode =
|
||||||
(typeof AndroidScreenPowerMode)[keyof typeof AndroidScreenPowerMode];
|
(typeof AndroidScreenPowerMode)[keyof typeof AndroidScreenPowerMode];
|
||||||
|
|
||||||
export const ScrcpySetScreenPowerModeControlMessage = new Struct(
|
export const ScrcpySetScreenPowerModeControlMessage = struct(
|
||||||
{ type: u8, mode: u8.as<AndroidScreenPowerMode>() },
|
{ type: u8, mode: u8.as<AndroidScreenPowerMode>() },
|
||||||
{ littleEndian: false },
|
{ littleEndian: false },
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
import type { CodecOptions } from "./codec-options.js";
|
import type { CodecOptions } from "./codec-options.js";
|
||||||
|
|
||||||
export enum ScrcpyLogLevel1_16 {
|
export type ScrcpyLogLevel1_16 = "debug" | "info" | "warn" | "error";
|
||||||
Debug = "debug",
|
|
||||||
Info = "info",
|
|
||||||
Warn = "warn",
|
|
||||||
Error = "error",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum ScrcpyVideoOrientation1_16 {
|
export enum ScrcpyVideoOrientation1_16 {
|
||||||
Unlocked = -1,
|
Unlocked = -1,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { StructInit } from "@yume-chan/struct";
|
import type { StructInit } from "@yume-chan/struct";
|
||||||
import { Struct, buffer, string, u16, u32, u64, u8 } from "@yume-chan/struct";
|
import { buffer, string, struct, u16, u32, u64, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import type { AndroidMotionEventAction } from "../../control/index.js";
|
import type { AndroidMotionEventAction } from "../../control/index.js";
|
||||||
import {
|
import {
|
||||||
|
@ -24,14 +24,14 @@ export const SCRCPY_CONTROL_MESSAGE_TYPES_1_16: readonly ScrcpyControlMessageTyp
|
||||||
/* 10 */ ScrcpyControlMessageType.RotateDevice,
|
/* 10 */ ScrcpyControlMessageType.RotateDevice,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ScrcpyMediaStreamRawPacket = new Struct(
|
export const ScrcpyMediaStreamRawPacket = struct(
|
||||||
{ pts: u64, data: buffer(u32) },
|
{ pts: u64, data: buffer(u32) },
|
||||||
{ littleEndian: false },
|
{ littleEndian: false },
|
||||||
);
|
);
|
||||||
|
|
||||||
export const SCRCPY_MEDIA_PACKET_FLAG_CONFIG = 1n << 63n;
|
export const SCRCPY_MEDIA_PACKET_FLAG_CONFIG = 1n << 63n;
|
||||||
|
|
||||||
export const ScrcpyInjectTouchControlMessage1_16 = new Struct(
|
export const ScrcpyInjectTouchControlMessage1_16 = struct(
|
||||||
{
|
{
|
||||||
type: u8,
|
type: u8,
|
||||||
action: u8.as<AndroidMotionEventAction>(),
|
action: u8.as<AndroidMotionEventAction>(),
|
||||||
|
@ -52,7 +52,7 @@ export type ScrcpyInjectTouchControlMessage1_16 = StructInit<
|
||||||
|
|
||||||
export const ScrcpyBackOrScreenOnControlMessage1_16 = EmptyControlMessage;
|
export const ScrcpyBackOrScreenOnControlMessage1_16 = EmptyControlMessage;
|
||||||
|
|
||||||
export const ScrcpySetClipboardControlMessage1_15 = new Struct(
|
export const ScrcpySetClipboardControlMessage1_15 = struct(
|
||||||
{ type: u8, content: string(u32) },
|
{ type: u8, content: string(u32) },
|
||||||
{ littleEndian: false },
|
{ littleEndian: false },
|
||||||
);
|
);
|
||||||
|
@ -61,7 +61,7 @@ export type ScrcpySetClipboardControlMessage1_15 = StructInit<
|
||||||
typeof ScrcpySetClipboardControlMessage1_15
|
typeof ScrcpySetClipboardControlMessage1_15
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export const ScrcpyClipboardDeviceMessage = new Struct(
|
export const ScrcpyClipboardDeviceMessage = struct(
|
||||||
{ content: string(u32) },
|
{ content: string(u32) },
|
||||||
{ littleEndian: false },
|
{ littleEndian: false },
|
||||||
);
|
);
|
||||||
|
|
|
@ -37,7 +37,7 @@ import {
|
||||||
|
|
||||||
import { CodecOptions } from "./codec-options.js";
|
import { CodecOptions } from "./codec-options.js";
|
||||||
import type { ScrcpyOptionsInit1_16 } from "./init.js";
|
import type { ScrcpyOptionsInit1_16 } from "./init.js";
|
||||||
import { ScrcpyLogLevel1_16, ScrcpyVideoOrientation1_16 } from "./init.js";
|
import { ScrcpyVideoOrientation1_16 } from "./init.js";
|
||||||
import {
|
import {
|
||||||
SCRCPY_CONTROL_MESSAGE_TYPES_1_16,
|
SCRCPY_CONTROL_MESSAGE_TYPES_1_16,
|
||||||
SCRCPY_MEDIA_PACKET_FLAG_CONFIG,
|
SCRCPY_MEDIA_PACKET_FLAG_CONFIG,
|
||||||
|
@ -52,7 +52,7 @@ import { ScrcpyScrollController1_16 } from "./scroll.js";
|
||||||
|
|
||||||
export class ScrcpyOptions1_16 extends ScrcpyOptions<ScrcpyOptionsInit1_16> {
|
export class ScrcpyOptions1_16 extends ScrcpyOptions<ScrcpyOptionsInit1_16> {
|
||||||
static readonly DEFAULTS = {
|
static readonly DEFAULTS = {
|
||||||
logLevel: ScrcpyLogLevel1_16.Debug,
|
logLevel: "debug",
|
||||||
maxSize: 0,
|
maxSize: 0,
|
||||||
bitRate: 8_000_000,
|
bitRate: 8_000_000,
|
||||||
maxFps: 0,
|
maxFps: 0,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { s32, Struct, u16, u32, u8 } from "@yume-chan/struct";
|
import { s32, struct, u16, u32, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import type { ScrcpyInjectScrollControlMessage } from "../../control/index.js";
|
import type { ScrcpyInjectScrollControlMessage } from "../../control/index.js";
|
||||||
import { ScrcpyControlMessageType } from "../../control/index.js";
|
import { ScrcpyControlMessageType } from "../../control/index.js";
|
||||||
|
@ -9,7 +9,7 @@ export interface ScrcpyScrollController {
|
||||||
): Uint8Array | undefined;
|
): Uint8Array | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScrcpyInjectScrollControlMessage1_16 = new Struct(
|
export const ScrcpyInjectScrollControlMessage1_16 = struct(
|
||||||
{
|
{
|
||||||
type: u8.as(ScrcpyControlMessageType.InjectScroll as const),
|
type: u8.as(ScrcpyControlMessageType.InjectScroll as const),
|
||||||
pointerX: u32,
|
pointerX: u32,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { StructInit } from "@yume-chan/struct";
|
import type { StructInit } from "@yume-chan/struct";
|
||||||
import { Struct, u8 } from "@yume-chan/struct";
|
import { struct, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
AndroidKeyEventAction,
|
AndroidKeyEventAction,
|
||||||
|
@ -17,22 +17,24 @@ import { ScrcpyOptions1_17 } from "./1_17.js";
|
||||||
import type { ScrcpyEncoder } from "./types.js";
|
import type { ScrcpyEncoder } from "./types.js";
|
||||||
import { ScrcpyOptions } from "./types.js";
|
import { ScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export enum ScrcpyLogLevel1_18 {
|
export type ScrcpyLogLevel1_18 =
|
||||||
Verbose = "verbose",
|
| "verbose"
|
||||||
Debug = "debug",
|
| "debug"
|
||||||
Info = "info",
|
| "info"
|
||||||
Warn = "warn",
|
| "warn"
|
||||||
Error = "error",
|
| "error";
|
||||||
}
|
|
||||||
|
|
||||||
export enum ScrcpyVideoOrientation1_18 {
|
export const ScrcpyVideoOrientation1_18 = {
|
||||||
Initial = -2,
|
Initial: -2,
|
||||||
Unlocked = -1,
|
Unlocked: -1,
|
||||||
Portrait = 0,
|
Portrait: 0,
|
||||||
Landscape = 1,
|
Landscape: 1,
|
||||||
PortraitFlipped = 2,
|
PortraitFlipped: 2,
|
||||||
LandscapeFlipped = 3,
|
LandscapeFlipped: 3,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export type ScrcpyVideoOrientation1_18 =
|
||||||
|
(typeof ScrcpyVideoOrientation1_18)[keyof typeof ScrcpyVideoOrientation1_18];
|
||||||
|
|
||||||
export interface ScrcpyOptionsInit1_18
|
export interface ScrcpyOptionsInit1_18
|
||||||
extends Omit<ScrcpyOptionsInit1_17, "logLevel" | "lockVideoOrientation"> {
|
extends Omit<ScrcpyOptionsInit1_17, "logLevel" | "lockVideoOrientation"> {
|
||||||
|
@ -43,11 +45,11 @@ export interface ScrcpyOptionsInit1_18
|
||||||
powerOffOnClose?: boolean;
|
powerOffOnClose?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScrcpyBackOrScreenOnControlMessage1_18 = new Struct(
|
export const ScrcpyBackOrScreenOnControlMessage1_18 = struct(
|
||||||
{
|
/* #__PURE__ */ (() => ({
|
||||||
...ScrcpyBackOrScreenOnControlMessage1_16.fields,
|
...ScrcpyBackOrScreenOnControlMessage1_16.fields,
|
||||||
action: u8.as<AndroidKeyEventAction>(),
|
action: u8.as<AndroidKeyEventAction>(),
|
||||||
},
|
}))(),
|
||||||
{ littleEndian: false },
|
{ littleEndian: false },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -55,18 +57,16 @@ export type ScrcpyBackOrScreenOnControlMessage1_18 = StructInit<
|
||||||
typeof ScrcpyBackOrScreenOnControlMessage1_18
|
typeof ScrcpyBackOrScreenOnControlMessage1_18
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export const SCRCPY_CONTROL_MESSAGE_TYPES_1_18 =
|
export const SCRCPY_CONTROL_MESSAGE_TYPES_1_18 = /* #__PURE__ */ (() => {
|
||||||
SCRCPY_CONTROL_MESSAGE_TYPES_1_16.slice();
|
const result = SCRCPY_CONTROL_MESSAGE_TYPES_1_16.slice();
|
||||||
SCRCPY_CONTROL_MESSAGE_TYPES_1_18.splice(
|
result.splice(6, 0, ScrcpyControlMessageType.ExpandSettingPanel);
|
||||||
6,
|
return result;
|
||||||
0,
|
})();
|
||||||
ScrcpyControlMessageType.ExpandSettingPanel,
|
|
||||||
);
|
|
||||||
|
|
||||||
export class ScrcpyOptions1_18 extends ScrcpyOptions<ScrcpyOptionsInit1_18> {
|
export class ScrcpyOptions1_18 extends ScrcpyOptions<ScrcpyOptionsInit1_18> {
|
||||||
static readonly DEFAULTS = {
|
static readonly DEFAULTS = {
|
||||||
...ScrcpyOptions1_17.DEFAULTS,
|
...ScrcpyOptions1_17.DEFAULTS,
|
||||||
logLevel: ScrcpyLogLevel1_18.Debug,
|
logLevel: "debug",
|
||||||
lockVideoOrientation: ScrcpyVideoOrientation1_18.Unlocked,
|
lockVideoOrientation: ScrcpyVideoOrientation1_18.Unlocked,
|
||||||
powerOffOnClose: false,
|
powerOffOnClose: false,
|
||||||
} as const satisfies Required<ScrcpyOptionsInit1_18>;
|
} as const satisfies Required<ScrcpyOptionsInit1_18>;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { PromiseResolver } from "@yume-chan/async";
|
import { PromiseResolver } from "@yume-chan/async";
|
||||||
import type { AsyncExactReadable, StructInit } from "@yume-chan/struct";
|
import type { AsyncExactReadable, StructInit } from "@yume-chan/struct";
|
||||||
import { Struct, string, u32, u64, u8 } from "@yume-chan/struct";
|
import { string, struct, u32, u64, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import type { ScrcpySetClipboardControlMessage } from "../control/index.js";
|
import type { ScrcpySetClipboardControlMessage } from "../control/index.js";
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import type { ScrcpyOptionsInit1_18 } from "./1_18.js";
|
||||||
import { ScrcpyOptions1_18 } from "./1_18.js";
|
import { ScrcpyOptions1_18 } from "./1_18.js";
|
||||||
import { ScrcpyOptions, toScrcpyOptionValue } from "./types.js";
|
import { ScrcpyOptions, toScrcpyOptionValue } from "./types.js";
|
||||||
|
|
||||||
export const ScrcpyAckClipboardDeviceMessage = new Struct(
|
export const ScrcpyAckClipboardDeviceMessage = struct(
|
||||||
{ sequence: u64 },
|
{ sequence: u64 },
|
||||||
{ littleEndian: false },
|
{ littleEndian: false },
|
||||||
);
|
);
|
||||||
|
@ -24,7 +24,7 @@ function toSnakeCase(input: string): string {
|
||||||
return input.replace(/([A-Z])/g, "_$1").toLowerCase();
|
return input.replace(/([A-Z])/g, "_$1").toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ScrcpySetClipboardControlMessage1_21 = new Struct(
|
export const ScrcpySetClipboardControlMessage1_21 = struct(
|
||||||
{
|
{
|
||||||
type: u8,
|
type: u8,
|
||||||
sequence: u64,
|
sequence: u64,
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
import type { StructInit } from "@yume-chan/struct";
|
import type { StructInit } from "@yume-chan/struct";
|
||||||
import { s32, Struct } from "@yume-chan/struct";
|
import { s32, struct } from "@yume-chan/struct";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ScrcpyInjectScrollControlMessage1_16,
|
ScrcpyInjectScrollControlMessage1_16,
|
||||||
ScrcpyScrollController1_16,
|
ScrcpyScrollController1_16,
|
||||||
} from "../1_16/index.js";
|
} from "../1_16/index.js";
|
||||||
|
|
||||||
export const ScrcpyInjectScrollControlMessage1_22 = new Struct(
|
export const ScrcpyInjectScrollControlMessage1_22 = struct(
|
||||||
{ ...ScrcpyInjectScrollControlMessage1_16.fields, buttons: s32 },
|
/* #__PURE__ */ (() => ({
|
||||||
|
...ScrcpyInjectScrollControlMessage1_16.fields,
|
||||||
|
buttons: s32,
|
||||||
|
}))(),
|
||||||
{ littleEndian: false },
|
{ littleEndian: false },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { getInt16, setInt16 } from "@yume-chan/no-data-view";
|
import { getInt16, setInt16 } from "@yume-chan/no-data-view";
|
||||||
import type { Field, StructInit } from "@yume-chan/struct";
|
import type { Field, StructInit } from "@yume-chan/struct";
|
||||||
import { bipedal, Struct, u16, u32, u8 } from "@yume-chan/struct";
|
import { bipedal, struct, u16, u32, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import type { ScrcpyInjectScrollControlMessage } from "../../control/index.js";
|
import type { ScrcpyInjectScrollControlMessage } from "../../control/index.js";
|
||||||
import { ScrcpyControlMessageType } from "../../control/index.js";
|
import { ScrcpyControlMessageType } from "../../control/index.js";
|
||||||
|
@ -23,7 +23,7 @@ export const ScrcpySignedFloat: Field<number, never, never> = {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ScrcpyInjectScrollControlMessage1_25 = new Struct(
|
export const ScrcpyInjectScrollControlMessage1_25 = struct(
|
||||||
{
|
{
|
||||||
type: u8.as(ScrcpyControlMessageType.InjectScroll as const),
|
type: u8.as(ScrcpyControlMessageType.InjectScroll as const),
|
||||||
pointerX: u32,
|
pointerX: u32,
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {
|
||||||
PushReadableStream,
|
PushReadableStream,
|
||||||
} from "@yume-chan/stream-extra";
|
} from "@yume-chan/stream-extra";
|
||||||
import type { MaybePromiseLike, StructInit } from "@yume-chan/struct";
|
import type { MaybePromiseLike, StructInit } from "@yume-chan/struct";
|
||||||
import { Struct, u16, u32, u64, u8 } from "@yume-chan/struct";
|
import { struct, u16, u32, u64, u8 } from "@yume-chan/struct";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
AndroidMotionEventAction,
|
AndroidMotionEventAction,
|
||||||
|
@ -30,7 +30,7 @@ import type {
|
||||||
} from "./types.js";
|
} from "./types.js";
|
||||||
import { ScrcpyOptions } from "./types.js";
|
import { ScrcpyOptions } from "./types.js";
|
||||||
|
|
||||||
export const ScrcpyInjectTouchControlMessage2_0 = new Struct(
|
export const ScrcpyInjectTouchControlMessage2_0 = struct(
|
||||||
{
|
{
|
||||||
type: u8,
|
type: u8,
|
||||||
action: u8.as<AndroidMotionEventAction>(),
|
action: u8.as<AndroidMotionEventAction>(),
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { ScrcpyLogLevel1_18, ScrcpyVideoOrientation1_18 } from "./1_18.js";
|
import type { ScrcpyLogLevel1_18 } from "./1_18.js";
|
||||||
|
import { ScrcpyVideoOrientation1_18 } from "./1_18.js";
|
||||||
import type { ScrcpyOptionsInit2_3 } from "./2_3.js";
|
import type { ScrcpyOptionsInit2_3 } from "./2_3.js";
|
||||||
import { ScrcpyOptions2_3 } from "./2_3.js";
|
import { ScrcpyOptions2_3 } from "./2_3.js";
|
||||||
|
|
||||||
export const ScrcpyLogLevel = ScrcpyLogLevel1_18;
|
|
||||||
export type ScrcpyLogLevel = ScrcpyLogLevel1_18;
|
export type ScrcpyLogLevel = ScrcpyLogLevel1_18;
|
||||||
|
|
||||||
export const ScrcpyVideoOrientation = ScrcpyVideoOrientation1_18;
|
export const ScrcpyVideoOrientation = ScrcpyVideoOrientation1_18;
|
||||||
|
|
|
@ -25,9 +25,9 @@ $ npm i @yume-chan/struct
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { Struct, u8, u16, s32, buffer, string } from "@yume-chan/struct";
|
import { struct, u8, u16, s32, buffer, string } from "@yume-chan/struct";
|
||||||
|
|
||||||
const Message = new Struct(
|
const Message = struct(
|
||||||
{
|
{
|
||||||
a: u8,
|
a: u8,
|
||||||
b: u16,
|
b: u16,
|
||||||
|
@ -94,7 +94,7 @@ const MyField: Field<number, never, never> = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const Message2 = new Struct({
|
const Message2 = struct({
|
||||||
a: u8,
|
a: u8,
|
||||||
b: MyField,
|
b: MyField,
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,15 +4,12 @@ import { describe, it } from "node:test";
|
||||||
import { buffer } from "./buffer.js";
|
import { buffer } from "./buffer.js";
|
||||||
import type { ExactReadable } from "./readable.js";
|
import type { ExactReadable } from "./readable.js";
|
||||||
import { ExactReadableEndedError } from "./readable.js";
|
import { ExactReadableEndedError } from "./readable.js";
|
||||||
import { Struct } from "./struct.js";
|
import { struct } from "./struct.js";
|
||||||
|
|
||||||
describe("buffer", () => {
|
describe("buffer", () => {
|
||||||
describe("fixed size", () => {
|
describe("fixed size", () => {
|
||||||
it("should deserialize", () => {
|
it("should deserialize", () => {
|
||||||
const A = new Struct(
|
const A = struct({ value: buffer(10) }, { littleEndian: false });
|
||||||
{ value: buffer(10) },
|
|
||||||
{ littleEndian: false },
|
|
||||||
);
|
|
||||||
const reader: ExactReadable = {
|
const reader: ExactReadable = {
|
||||||
position: 0,
|
position: 0,
|
||||||
readExactly() {
|
readExactly() {
|
||||||
|
@ -25,10 +22,7 @@ describe("buffer", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should throw for not enough data", () => {
|
it("should throw for not enough data", () => {
|
||||||
const A = new Struct(
|
const A = struct({ value: buffer(10) }, { littleEndian: false });
|
||||||
{ value: buffer(10) },
|
|
||||||
{ littleEndian: false },
|
|
||||||
);
|
|
||||||
const reader: ExactReadable = {
|
const reader: ExactReadable = {
|
||||||
position: 0,
|
position: 0,
|
||||||
readExactly() {
|
readExactly() {
|
||||||
|
@ -43,10 +37,7 @@ describe("buffer", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should throw for no data", () => {
|
it("should throw for no data", () => {
|
||||||
const A = new Struct(
|
const A = struct({ value: buffer(10) }, { littleEndian: false });
|
||||||
{ value: buffer(10) },
|
|
||||||
{ littleEndian: false },
|
|
||||||
);
|
|
||||||
const reader: ExactReadable = {
|
const reader: ExactReadable = {
|
||||||
position: 0,
|
position: 0,
|
||||||
readExactly() {
|
readExactly() {
|
||||||
|
|
|
@ -42,14 +42,16 @@ export interface BufferLike {
|
||||||
|
|
||||||
export const EmptyUint8Array = new Uint8Array(0);
|
export const EmptyUint8Array = new Uint8Array(0);
|
||||||
|
|
||||||
export const buffer: BufferLike = ((
|
// This is required for Rollup tree-shaking to work.
|
||||||
|
/* #__NO_SIDE_EFFECTS__ */
|
||||||
|
function _buffer(
|
||||||
lengthOrField:
|
lengthOrField:
|
||||||
| string
|
| string
|
||||||
| number
|
| number
|
||||||
| Field<number, never, unknown>
|
| Field<number, never, unknown>
|
||||||
| BufferLengthConverter<string, unknown>,
|
| BufferLengthConverter<string, unknown>,
|
||||||
converter?: Converter<Uint8Array, unknown>,
|
converter?: Converter<Uint8Array, unknown>,
|
||||||
): Field<unknown, string, Record<string, unknown>> => {
|
): Field<unknown, string, Record<string, unknown>> {
|
||||||
if (typeof lengthOrField === "number") {
|
if (typeof lengthOrField === "number") {
|
||||||
if (converter) {
|
if (converter) {
|
||||||
return {
|
return {
|
||||||
|
@ -226,4 +228,6 @@ export const buffer: BufferLike = ((
|
||||||
return reader.readExactly(length);
|
return reader.readExactly(length);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}) as never;
|
}
|
||||||
|
|
||||||
|
export const buffer: BufferLike = _buffer as never;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import * as assert from "node:assert";
|
import * as assert from "node:assert";
|
||||||
import { describe, it } from "node:test";
|
import { describe, it } from "node:test";
|
||||||
|
|
||||||
import { Struct } from "./index.js";
|
import { struct } from "./index.js";
|
||||||
|
|
||||||
describe("Struct", () => {
|
describe("Struct", () => {
|
||||||
describe("Index", () => {
|
describe("Index", () => {
|
||||||
it("should export default Struct", () => {
|
it("should export default Struct", () => {
|
||||||
assert.ok(Struct);
|
assert.ok(struct);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,15 +25,19 @@ export interface String {
|
||||||
): Field<string, KOmitInit, KS>;
|
): Field<string, KOmitInit, KS>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const string: String = ((
|
// This is required for Rollup tree-shaking to work.
|
||||||
|
/* #__NO_SIDE_EFFECTS__ */
|
||||||
|
function _string(
|
||||||
lengthOrField: string | number | BufferLengthConverter<string, unknown>,
|
lengthOrField: string | number | BufferLengthConverter<string, unknown>,
|
||||||
): Field<string, string, Record<string, unknown>> & {
|
): Field<string, string, Record<string, unknown>> & {
|
||||||
as: <T>(infer: T) => Field<T, string, Record<string, unknown>>;
|
as: <T>(infer: T) => Field<T, string, Record<string, unknown>>;
|
||||||
} => {
|
} {
|
||||||
const field = buffer(lengthOrField as never, {
|
const field = buffer(lengthOrField as never, {
|
||||||
convert: decodeUtf8,
|
convert: decodeUtf8,
|
||||||
back: encodeUtf8,
|
back: encodeUtf8,
|
||||||
});
|
});
|
||||||
(field as never as { as: unknown }).as = () => field;
|
(field as never as { as: unknown }).as = () => field;
|
||||||
return field as never;
|
return field as never;
|
||||||
}) as never;
|
}
|
||||||
|
|
||||||
|
export const string: String = _string as never;
|
||||||
|
|
|
@ -2,11 +2,11 @@ import * as assert from "node:assert";
|
||||||
import { describe, it } from "node:test";
|
import { describe, it } from "node:test";
|
||||||
|
|
||||||
import { u8 } from "./number.js";
|
import { u8 } from "./number.js";
|
||||||
import { Struct } from "./struct.js";
|
import { struct } from "./struct.js";
|
||||||
|
|
||||||
describe("Struct", () => {
|
describe("Struct", () => {
|
||||||
it("serialize", () => {
|
it("serialize", () => {
|
||||||
const A = new Struct({ id: u8 }, { littleEndian: true });
|
const A = struct({ id: u8 }, { littleEndian: true });
|
||||||
assert.deepStrictEqual(A.serialize({ id: 10 }), new Uint8Array([10]));
|
assert.deepStrictEqual(A.serialize({ id: 10 }), new Uint8Array([10]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,7 +29,7 @@ export type StructInit<
|
||||||
export type StructValue<
|
export type StructValue<
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
T extends Struct<any, any, any>,
|
T extends Struct<any, any, any>,
|
||||||
> = ReturnType<Exclude<T["postDeserialize"], undefined>>;
|
> = T extends Struct<any, any, infer P> ? P : never;
|
||||||
|
|
||||||
export class StructDeserializeError extends Error {
|
export class StructDeserializeError extends Error {
|
||||||
constructor(message: string) {
|
constructor(message: string) {
|
||||||
|
@ -55,26 +55,29 @@ export class StructEmptyError extends StructDeserializeError {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export type StructLike<T> = Struct<any, any, T>;
|
export type StructLike<T> = Struct<any, any, T>;
|
||||||
|
|
||||||
export class Struct<
|
export interface Struct<
|
||||||
T extends Record<string, Field<unknown, string, Partial<FieldsType<T>>>>,
|
T extends Record<string, Field<unknown, string, Partial<FieldsType<T>>>>,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
Extra extends Record<PropertyKey, unknown> | undefined = undefined,
|
||||||
Extra extends Record<PropertyKey, unknown> = {},
|
|
||||||
PostDeserialize = FieldsType<T> & Extra,
|
PostDeserialize = FieldsType<T> & Extra,
|
||||||
> {
|
> {
|
||||||
fields: T;
|
fields: T;
|
||||||
size: number;
|
size: number;
|
||||||
|
|
||||||
#fieldList: [string, Field<unknown, string, unknown>][] = [];
|
|
||||||
|
|
||||||
littleEndian: boolean;
|
|
||||||
|
|
||||||
extra: Extra;
|
extra: Extra;
|
||||||
|
|
||||||
postDeserialize?:
|
serialize(runtimeStruct: StructInit<this>): Uint8Array;
|
||||||
| ((fields: FieldsType<T> & Extra) => PostDeserialize)
|
serialize(runtimeStruct: StructInit<this>, buffer: Uint8Array): number;
|
||||||
| undefined;
|
|
||||||
|
|
||||||
constructor(
|
deserialize(reader: ExactReadable): PostDeserialize;
|
||||||
|
deserialize(reader: AsyncExactReadable): MaybePromiseLike<PostDeserialize>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #__NO_SIDE_EFFECTS__ */
|
||||||
|
export function struct<
|
||||||
|
T extends Record<string, Field<unknown, string, Partial<FieldsType<T>>>>,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||||
|
Extra extends Record<PropertyKey, unknown> = {},
|
||||||
|
PostDeserialize = FieldsType<T> & Extra,
|
||||||
|
>(
|
||||||
fields: T,
|
fields: T,
|
||||||
options: {
|
options: {
|
||||||
littleEndian?: boolean;
|
littleEndian?: boolean;
|
||||||
|
@ -84,37 +87,36 @@ export class Struct<
|
||||||
fields: FieldsType<T> & Extra,
|
fields: FieldsType<T> & Extra,
|
||||||
) => PostDeserialize;
|
) => PostDeserialize;
|
||||||
},
|
},
|
||||||
) {
|
): Struct<T, Extra, PostDeserialize> {
|
||||||
this.#fieldList = Object.entries(fields);
|
const fieldList = Object.entries(fields);
|
||||||
this.fields = fields;
|
const size = fieldList.reduce((sum, [, field]) => sum + field.size, 0);
|
||||||
this.size = this.#fieldList.reduce(
|
|
||||||
(sum, [, field]) => sum + field.size,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.littleEndian = !!options.littleEndian;
|
const littleEndian = !!options.littleEndian;
|
||||||
this.extra = options.extra!;
|
const extra = options.extra
|
||||||
this.postDeserialize = options.postDeserialize;
|
? Object.getOwnPropertyDescriptors(options.extra)
|
||||||
}
|
: undefined;
|
||||||
|
|
||||||
serialize(runtimeStruct: StructInit<this>): Uint8Array;
|
return {
|
||||||
serialize(runtimeStruct: StructInit<this>, buffer: Uint8Array): number;
|
fields,
|
||||||
|
size,
|
||||||
|
extra: options.extra,
|
||||||
serialize(
|
serialize(
|
||||||
runtimeStruct: StructInit<this>,
|
runtimeStruct: StructInit<Struct<T, Extra, PostDeserialize>>,
|
||||||
buffer?: Uint8Array,
|
buffer?: Uint8Array,
|
||||||
): Uint8Array | number {
|
): Uint8Array | number {
|
||||||
for (const [key, field] of this.#fieldList) {
|
for (const [key, field] of fieldList) {
|
||||||
if (key in runtimeStruct) {
|
if (key in runtimeStruct) {
|
||||||
field.preSerialize?.(
|
field.preSerialize?.(
|
||||||
runtimeStruct[key as never],
|
runtimeStruct[key as never],
|
||||||
runtimeStruct,
|
runtimeStruct as never,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sizes = this.#fieldList.map(
|
const sizes = fieldList.map(
|
||||||
([key, field]) =>
|
([key, field]) =>
|
||||||
field.dynamicSize?.(runtimeStruct[key as never]) ?? field.size,
|
field.dynamicSize?.(runtimeStruct[key as never]) ??
|
||||||
|
field.size,
|
||||||
);
|
);
|
||||||
const size = sizes.reduce((sum, size) => sum + size, 0);
|
const size = sizes.reduce((sum, size) => sum + size, 0);
|
||||||
|
|
||||||
|
@ -132,9 +134,9 @@ export class Struct<
|
||||||
const context: SerializeContext = {
|
const context: SerializeContext = {
|
||||||
buffer,
|
buffer,
|
||||||
index: 0,
|
index: 0,
|
||||||
littleEndian: this.littleEndian,
|
littleEndian,
|
||||||
};
|
};
|
||||||
for (const [index, [key, field]] of this.#fieldList.entries()) {
|
for (const [index, [key, field]] of fieldList.entries()) {
|
||||||
field.serialize(runtimeStruct[key as never], context);
|
field.serialize(runtimeStruct[key as never], context);
|
||||||
context.index += sizes[index]!;
|
context.index += sizes[index]!;
|
||||||
}
|
}
|
||||||
|
@ -144,12 +146,8 @@ export class Struct<
|
||||||
} else {
|
} else {
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
deserialize: bipedal(function* (
|
||||||
deserialize: {
|
|
||||||
(reader: ExactReadable): PostDeserialize;
|
|
||||||
(reader: AsyncExactReadable): MaybePromiseLike<PostDeserialize>;
|
|
||||||
} = bipedal(function* (
|
|
||||||
this: Struct<T, Extra, PostDeserialize>,
|
this: Struct<T, Extra, PostDeserialize>,
|
||||||
then,
|
then,
|
||||||
reader: AsyncExactReadable,
|
reader: AsyncExactReadable,
|
||||||
|
@ -157,15 +155,17 @@ export class Struct<
|
||||||
const startPosition = reader.position;
|
const startPosition = reader.position;
|
||||||
|
|
||||||
const runtimeStruct = {} as Record<string, unknown>;
|
const runtimeStruct = {} as Record<string, unknown>;
|
||||||
const context: DeserializeContext<unknown> = {
|
const context: DeserializeContext<Partial<FieldsType<T>>> = {
|
||||||
reader,
|
reader,
|
||||||
runtimeStruct,
|
runtimeStruct: runtimeStruct as never,
|
||||||
littleEndian: this.littleEndian,
|
littleEndian: littleEndian,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (const [key, field] of this.#fieldList) {
|
for (const [key, field] of fieldList) {
|
||||||
runtimeStruct[key] = yield* then(field.deserialize(context));
|
runtimeStruct[key] = yield* then(
|
||||||
|
field.deserialize(context),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!(e instanceof ExactReadableEndedError)) {
|
if (!(e instanceof ExactReadableEndedError)) {
|
||||||
|
@ -179,20 +179,18 @@ export class Struct<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.extra) {
|
if (extra) {
|
||||||
Object.defineProperties(
|
Object.defineProperties(runtimeStruct, extra);
|
||||||
runtimeStruct,
|
|
||||||
Object.getOwnPropertyDescriptors(this.extra),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.postDeserialize) {
|
if (options.postDeserialize) {
|
||||||
return this.postDeserialize.call(
|
return options.postDeserialize.call(
|
||||||
runtimeStruct,
|
runtimeStruct as never,
|
||||||
runtimeStruct as never,
|
runtimeStruct as never,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return runtimeStruct as never;
|
return runtimeStruct;
|
||||||
}
|
}
|
||||||
}) as never;
|
}),
|
||||||
|
} as never;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue