refactor(struct): improve tree-shaking

This commit is contained in:
Simon Chan 2024-11-10 17:37:31 +08:00
parent 70b0d3e5d8
commit c1dc802364
No known key found for this signature in database
GPG key ID: A8B69F750B9BCEDD
15 changed files with 102 additions and 93 deletions

View file

@ -34,7 +34,7 @@ export type AdbShellProtocolId =
// This packet format is used in both directions. // This packet format is used in both directions.
export const AdbShellProtocolPacket = struct( export const AdbShellProtocolPacket = struct(
{ {
id: u8.as<AdbShellProtocolId>(), id: u8<AdbShellProtocolId>(),
data: buffer(u32), data: buffer(u32),
}, },
{ littleEndian: true }, { littleEndian: true },

View file

@ -115,7 +115,7 @@ export interface AdbSyncPushV2Options extends AdbSyncPushV1Options {
} }
export const AdbSyncSendV2Request = struct( export const AdbSyncSendV2Request = struct(
{ id: u32, mode: u32, flags: u32.as<AdbSyncSendV2Flags>() }, { id: u32, mode: u32, flags: u32<AdbSyncSendV2Flags>() },
{ littleEndian: true }, { littleEndian: true },
); );

View file

@ -77,18 +77,17 @@ export const AdbSyncStatErrorCode = {
export type AdbSyncStatErrorCode = export type AdbSyncStatErrorCode =
(typeof AdbSyncStatErrorCode)[keyof typeof AdbSyncStatErrorCode]; (typeof AdbSyncStatErrorCode)[keyof typeof AdbSyncStatErrorCode];
const AdbSyncStatErrorName = const AdbSyncStatErrorName = /* #__PURE__ */ (() =>
/* #__PURE__ */
Object.fromEntries( Object.fromEntries(
Object.entries(AdbSyncStatErrorCode).map(([key, value]) => [ Object.entries(AdbSyncStatErrorCode).map(([key, value]) => [
value, value,
key, key,
]), ]),
); ))();
export const AdbSyncStatResponse = struct( export const AdbSyncStatResponse = struct(
{ {
error: u32.as<AdbSyncStatErrorCode>(), error: u32<AdbSyncStatErrorCode>(),
dev: u64, dev: u64,
ino: u64, ino: u64,
mode: u32, mode: u32,

View file

@ -209,10 +209,10 @@ export enum AndroidKeyCode {
export const ScrcpyInjectKeyCodeControlMessage = struct( export const ScrcpyInjectKeyCodeControlMessage = struct(
{ {
type: u8, type: u8,
action: u8.as<AndroidKeyEventAction>(), action: u8<AndroidKeyEventAction>(),
keyCode: u32.as<AndroidKeyCode>(), keyCode: u32<AndroidKeyCode>(),
repeat: u32, repeat: u32,
metaState: u32.as<AndroidKeyEventMeta>(), metaState: u32<AndroidKeyEventMeta>(),
}, },
{ littleEndian: false }, { littleEndian: false },
); );

View file

@ -11,7 +11,7 @@ export type AndroidScreenPowerMode =
(typeof AndroidScreenPowerMode)[keyof typeof AndroidScreenPowerMode]; (typeof AndroidScreenPowerMode)[keyof typeof AndroidScreenPowerMode];
export const ScrcpySetScreenPowerModeControlMessage = struct( export const ScrcpySetScreenPowerModeControlMessage = struct(
{ type: u8, mode: u8.as<AndroidScreenPowerMode>() }, { type: u8, mode: u8<AndroidScreenPowerMode>() },
{ littleEndian: false }, { littleEndian: false },
); );

View file

@ -34,7 +34,7 @@ export const SCRCPY_MEDIA_PACKET_FLAG_CONFIG = 1n << 63n;
export const ScrcpyInjectTouchControlMessage1_16 = struct( export const ScrcpyInjectTouchControlMessage1_16 = struct(
{ {
type: u8, type: u8,
action: u8.as<AndroidMotionEventAction>(), action: u8<AndroidMotionEventAction>(),
pointerId: u64, pointerId: u64,
pointerX: u32, pointerX: u32,
pointerY: u32, pointerY: u32,

View file

@ -1,7 +1,6 @@
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";
export interface ScrcpyScrollController { export interface ScrcpyScrollController {
serializeScrollMessage( serializeScrollMessage(
@ -11,7 +10,7 @@ export interface ScrcpyScrollController {
export const ScrcpyInjectScrollControlMessage1_16 = struct( export const ScrcpyInjectScrollControlMessage1_16 = struct(
{ {
type: u8.as(ScrcpyControlMessageType.InjectScroll as const), type: u8,
pointerX: u32, pointerX: u32,
pointerY: u32, pointerY: u32,
screenWidth: u16, screenWidth: u16,

View file

@ -48,7 +48,7 @@ export interface ScrcpyOptionsInit1_18
export const ScrcpyBackOrScreenOnControlMessage1_18 = struct( export const ScrcpyBackOrScreenOnControlMessage1_18 = struct(
/* #__PURE__ */ (() => ({ /* #__PURE__ */ (() => ({
...ScrcpyBackOrScreenOnControlMessage1_16.fields, ...ScrcpyBackOrScreenOnControlMessage1_16.fields,
action: u8.as<AndroidKeyEventAction>(), action: u8<AndroidKeyEventAction>(),
}))(), }))(),
{ littleEndian: false }, { littleEndian: false },
); );

View file

@ -28,7 +28,7 @@ export const ScrcpySetClipboardControlMessage1_21 = struct(
{ {
type: u8, type: u8,
sequence: u64, sequence: u64,
paste: u8.as<boolean>(), paste: u8<boolean>(),
content: string(u32), content: string(u32),
}, },
{ littleEndian: false }, { littleEndian: false },

View file

@ -3,7 +3,6 @@ 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 type { ScrcpyScrollController } from "../1_16/index.js"; import type { ScrcpyScrollController } from "../1_16/index.js";
import { clamp } from "../1_16/index.js"; import { clamp } from "../1_16/index.js";
@ -25,7 +24,7 @@ export const ScrcpySignedFloat: Field<number, never, never> = {
export const ScrcpyInjectScrollControlMessage1_25 = struct( export const ScrcpyInjectScrollControlMessage1_25 = struct(
{ {
type: u8.as(ScrcpyControlMessageType.InjectScroll as const), type: u8,
pointerX: u32, pointerX: u32,
pointerY: u32, pointerY: u32,
screenWidth: u16, screenWidth: u16,

View file

@ -33,7 +33,7 @@ import { ScrcpyOptions } from "./types.js";
export const ScrcpyInjectTouchControlMessage2_0 = struct( export const ScrcpyInjectTouchControlMessage2_0 = struct(
{ {
type: u8, type: u8,
action: u8.as<AndroidMotionEventAction>(), action: u8<AndroidMotionEventAction>(),
pointerId: u64, pointerId: u64,
pointerX: u32, pointerX: u32,
pointerY: u32, pointerY: u32,

View file

@ -12,10 +12,10 @@ interface GlobalExtension {
// `createTask` allows browser DevTools to track the call stack across async boundaries. // `createTask` allows browser DevTools to track the call stack across async boundaries.
const { console } = globalThis as unknown as GlobalExtension; const { console } = globalThis as unknown as GlobalExtension;
export const createTask: (name: string) => Task = export const createTask: (name: string) => Task = /* #__PURE__ */ (() =>
console?.createTask?.bind(console) ?? console?.createTask?.bind(console) ??
(() => ({ (() => ({
run(callback) { run(callback) {
return callback(); return callback();
}, },
})); })))();

View file

@ -42,7 +42,7 @@ export interface BufferLike {
export const EmptyUint8Array = new Uint8Array(0); export const EmptyUint8Array = new Uint8Array(0);
// This is required for Rollup tree-shaking to work. // Rollup doesn't support `/* #__NO_SIDE_EFFECTS__ */ export const a = () => {}
/* #__NO_SIDE_EFFECTS__ */ /* #__NO_SIDE_EFFECTS__ */
function _buffer( function _buffer(
lengthOrField: lengthOrField:
@ -54,16 +54,27 @@ function _buffer(
): Field<unknown, string, Record<string, unknown>> { ): Field<unknown, string, Record<string, unknown>> {
if (typeof lengthOrField === "number") { if (typeof lengthOrField === "number") {
if (converter) { if (converter) {
if (lengthOrField === 0) {
return {
size: 0,
serialize: () => {},
deserialize: () => converter.convert(EmptyUint8Array),
};
}
return { return {
size: lengthOrField, size: lengthOrField,
serialize: (value, { buffer, index }) => { serialize: (value, { buffer, index }) => {
buffer.set(converter.back(value), index); buffer.set(
converter.back(value).slice(0, lengthOrField),
index,
);
}, },
deserialize: bipedal(function* (then, { reader }) { deserialize: bipedal(function* (then, { reader }) {
const value = yield* then( const array = yield* then(
reader.readExactly(lengthOrField), reader.readExactly(lengthOrField),
); );
return converter.convert(value); return converter.convert(array);
}), }),
}; };
} }
@ -79,13 +90,21 @@ function _buffer(
return { return {
size: lengthOrField, size: lengthOrField,
serialize: (value, { buffer, index }) => { serialize: (value, { buffer, index }) => {
buffer.set(value as Uint8Array, index); buffer.set(
(value as Uint8Array).slice(0, lengthOrField),
index,
);
}, },
deserialize: ({ reader }) => reader.readExactly(lengthOrField), deserialize: ({ reader }) => reader.readExactly(lengthOrField),
}; };
} }
if (typeof lengthOrField === "object" && "serialize" in lengthOrField) { // Some Field type might be `function`s
if (
(typeof lengthOrField === "object" ||
typeof lengthOrField === "function") &&
"serialize" in lengthOrField
) {
if (converter) { if (converter) {
return { return {
size: 0, size: 0,
@ -108,10 +127,10 @@ function _buffer(
const length = yield* then( const length = yield* then(
lengthOrField.deserialize(context), lengthOrField.deserialize(context),
); );
const value = yield* then( const array = yield* then(
context.reader.readExactly(length), context.reader.readExactly(length),
); );
return converter.convert(value); return converter.convert(array);
}), }),
}; };
} }

View file

@ -17,114 +17,107 @@ import {
import { bipedal } from "./bipedal.js"; import { bipedal } from "./bipedal.js";
import type { Field } from "./field.js"; import type { Field } from "./field.js";
export const u8: Field<number, never, never> & { export interface NumberField<T> extends Field<T, never, never> {
as: <T>(infer?: T) => Field<T, never, never>; <U>(infer?: T): Field<U, never, never>;
} = { }
size: 1,
serialize(value, { buffer, index }) { /* #__NO_SIDE_EFFECTS__ */
function number<T>(
size: number,
serialize: Field<T, never, never>["serialize"],
deserialize: Field<T, never, never>["deserialize"],
): NumberField<T> {
const result = () => result;
result.size = size;
result.serialize = serialize;
result.deserialize = deserialize;
return result as never;
}
export const u8 = number<number>(
1,
(value, { buffer, index }) => {
buffer[index] = value; buffer[index] = value;
}, },
deserialize: bipedal(function* (then, { reader }) { bipedal(function* (then, { reader }) {
const data = yield* then(reader.readExactly(1)); const data = yield* then(reader.readExactly(1));
return data[0]!; return data[0]!;
}), }),
as: () => u8 as never, );
};
export const s8: Field<number, never, never> & { export const s8 = number<number>(
as: <T>(infer?: T) => Field<T, never, never>; 1,
} = { (value, { buffer, index }) => {
size: 1,
serialize(value, { buffer, index }) {
buffer[index] = value; buffer[index] = value;
}, },
deserialize: bipedal(function* (then, { reader }) { bipedal(function* (then, { reader }) {
const data = yield* then(reader.readExactly(1)); const data = yield* then(reader.readExactly(1));
return getInt8(data, 0); return getInt8(data, 0);
}), }),
as: () => s8 as never, );
};
export const u16: Field<number, never, never> & { export const u16 = number<number>(
as: <T>(infer?: T) => Field<T, never, never>; 2,
} = { (value, { buffer, index, littleEndian }) => {
size: 2,
serialize(value, { buffer, index, littleEndian }) {
setUint16(buffer, index, value, littleEndian); setUint16(buffer, index, value, littleEndian);
}, },
deserialize: bipedal(function* (then, { reader, littleEndian }) { bipedal(function* (then, { reader, littleEndian }) {
const data = yield* then(reader.readExactly(2)); const data = yield* then(reader.readExactly(2));
return getUint16(data, 0, littleEndian); return getUint16(data, 0, littleEndian);
}), }),
as: () => u16 as never, );
};
export const s16: Field<number, never, never> & { export const s16 = number<number>(
as: <T>(infer?: T) => Field<T, never, never>; 2,
} = { (value, { buffer, index, littleEndian }) => {
size: 2,
serialize(value, { buffer, index, littleEndian }) {
setInt16(buffer, index, value, littleEndian); setInt16(buffer, index, value, littleEndian);
}, },
deserialize: bipedal(function* (then, { reader, littleEndian }) { bipedal(function* (then, { reader, littleEndian }) {
const data = yield* then(reader.readExactly(2)); const data = yield* then(reader.readExactly(2));
return getInt16(data, 0, littleEndian); return getInt16(data, 0, littleEndian);
}), }),
as: () => s16 as never, );
};
export const u32: Field<number, never, never> & { export const u32 = number<number>(
as: <T>(infer?: T) => Field<T, never, never>; 4,
} = { (value, { buffer, index, littleEndian }) => {
size: 4,
serialize(value, { buffer, index, littleEndian }) {
setUint32(buffer, index, value, littleEndian); setUint32(buffer, index, value, littleEndian);
}, },
deserialize: bipedal(function* (then, { reader, littleEndian }) { bipedal(function* (then, { reader, littleEndian }) {
const data = yield* then(reader.readExactly(4)); const data = yield* then(reader.readExactly(4));
return getUint32(data, 0, littleEndian); return getUint32(data, 0, littleEndian);
}), }),
as: () => u32 as never, );
};
export const s32: Field<number, never, never> & { export const s32 = number<number>(
as: <T>(infer?: T) => Field<T, never, never>; 4,
} = { (value, { buffer, index, littleEndian }) => {
size: 4,
serialize(value, { buffer, index, littleEndian }) {
setInt32(buffer, index, value, littleEndian); setInt32(buffer, index, value, littleEndian);
}, },
deserialize: bipedal(function* (then, { reader, littleEndian }) { bipedal(function* (then, { reader, littleEndian }) {
const data = yield* then(reader.readExactly(4)); const data = yield* then(reader.readExactly(4));
return getInt32(data, 0, littleEndian); return getInt32(data, 0, littleEndian);
}), }),
as: () => s32 as never, );
};
export const u64: Field<bigint, never, never> & { export const u64 = number<bigint>(
as: <T>(infer?: T) => Field<T, never, never>; 8,
} = { (value, { buffer, index, littleEndian }) => {
size: 8,
serialize(value, { buffer, index, littleEndian }) {
setUint64(buffer, index, value, littleEndian); setUint64(buffer, index, value, littleEndian);
}, },
deserialize: bipedal(function* (then, { reader, littleEndian }) { bipedal(function* (then, { reader, littleEndian }) {
const data = yield* then(reader.readExactly(8)); const data = yield* then(reader.readExactly(8));
return getUint64(data, 0, littleEndian); return getUint64(data, 0, littleEndian);
}), }),
as: () => u64 as never, );
};
export const s64: Field<bigint, never, never> & { export const s64 = number<bigint>(
as: <T>(infer?: T) => Field<T, never, never>; 8,
} = { (value, { buffer, index, littleEndian }) => {
size: 8,
serialize(value, { buffer, index, littleEndian }) {
setInt64(buffer, index, value, littleEndian); setInt64(buffer, index, value, littleEndian);
}, },
deserialize: bipedal(function* (then, { reader, littleEndian }) { bipedal(function* (then, { reader, littleEndian }) {
const data = yield* then(reader.readExactly(8)); const data = yield* then(reader.readExactly(8));
return getInt64(data, 0, littleEndian); return getInt64(data, 0, littleEndian);
}), }),
as: () => s64 as never, );
};

View file

@ -25,7 +25,7 @@ export interface String {
): Field<string, KOmitInit, KS>; ): Field<string, KOmitInit, KS>;
} }
// This is required for Rollup tree-shaking to work. // Rollup doesn't support `/* #__NO_SIDE_EFFECTS__ */ export const a = () => {}
/* #__NO_SIDE_EFFECTS__ */ /* #__NO_SIDE_EFFECTS__ */
function _string( function _string(
lengthOrField: string | number | BufferLengthConverter<string, unknown>, lengthOrField: string | number | BufferLengthConverter<string, unknown>,