chore: fix review comments

This commit is contained in:
Simon Chan 2025-09-10 19:04:38 +08:00
parent e6ad77f672
commit b423c79755
No known key found for this signature in database
GPG key ID: A8B69F750B9BCEDD
29 changed files with 447 additions and 242 deletions

View file

@ -0,0 +1,7 @@
---
"@yume-chan/scrcpy": major
---
Convert `ScrcpyOptionsX\_YY.prototype.controlMessageTypes` to a map between internal control message types to version-specific values.
Generally, you would use `ScrcpyControlMessageSerializer`, `ScrcpyControlMessageWriter`, or `AdbScrcpyClient.prototype.controller` to send control messages to device, instead of using `controlMessageTypes` directly.

View file

@ -37,7 +37,7 @@ export class ScrcpyOptions1_15 implements ScrcpyOptions<Init> {
readonly value: Required<Init>; readonly value: Required<Init>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }

View file

@ -44,7 +44,7 @@ export class ScrcpyOptions1_17
readonly value: Required<Init>; readonly value: Required<Init>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }

View file

@ -44,7 +44,7 @@ export class ScrcpyOptions1_18
readonly value: Required<Init>; readonly value: Required<Init>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }

View file

@ -43,7 +43,7 @@ export class ScrcpyOptions1_21
readonly value: Required<Init>; readonly value: Required<Init>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -121,7 +121,21 @@ export class ScrcpyOptions1_21
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -43,7 +43,7 @@ export class ScrcpyOptions1_22
readonly value: Required<Init>; readonly value: Required<Init>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -121,7 +121,21 @@ export class ScrcpyOptions1_22
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -43,7 +43,7 @@ export class ScrcpyOptions1_23
readonly value: Required<Init>; readonly value: Required<Init>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -121,7 +121,21 @@ export class ScrcpyOptions1_23
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -43,7 +43,7 @@ export class ScrcpyOptions1_24
readonly value: Required<Init>; readonly value: Required<Init>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -121,7 +121,21 @@ export class ScrcpyOptions1_24
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -43,7 +43,7 @@ export class ScrcpyOptions1_25
readonly value: Required<Init>; readonly value: Required<Init>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -121,7 +121,21 @@ export class ScrcpyOptions1_25
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -5,7 +5,7 @@ export const Defaults = {
...{ ...{
...PrevImpl.Defaults, ...PrevImpl.Defaults,
// Remove obsolete values // Remove obsolete values
// replies on minifier to flatten the nested spread // relies on the minifier to flatten the nested spread
bitRate: undefined, bitRate: undefined,
codecOptions: undefined, codecOptions: undefined,
encoderName: undefined, encoderName: undefined,

View file

@ -44,7 +44,7 @@ export class ScrcpyOptions2_0
readonly value: Required<Init>; readonly value: Required<Init>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -128,7 +128,21 @@ export class ScrcpyOptions2_0
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -44,7 +44,7 @@ export class ScrcpyOptions2_1<TVideo extends boolean>
readonly value: Required<Init<TVideo>>; readonly value: Required<Init<TVideo>>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -128,7 +128,21 @@ export class ScrcpyOptions2_1<TVideo extends boolean>
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -44,7 +44,7 @@ export class ScrcpyOptions2_2<TVideo extends boolean>
readonly value: Required<Init<TVideo>>; readonly value: Required<Init<TVideo>>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -132,7 +132,21 @@ export class ScrcpyOptions2_2<TVideo extends boolean>
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -44,7 +44,7 @@ export class ScrcpyOptions2_3<TVideo extends boolean>
readonly value: Required<Init<TVideo>>; readonly value: Required<Init<TVideo>>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -132,7 +132,21 @@ export class ScrcpyOptions2_3<TVideo extends boolean>
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -48,7 +48,7 @@ export class ScrcpyOptions2_4<TVideo extends boolean>
readonly value: Required<Init<TVideo>>; readonly value: Required<Init<TVideo>>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -149,7 +149,21 @@ export class ScrcpyOptions2_4<TVideo extends boolean>
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -48,7 +48,7 @@ export class ScrcpyOptions2_6<TVideo extends boolean>
readonly value: Required<Init<TVideo>>; readonly value: Required<Init<TVideo>>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -153,7 +153,21 @@ export class ScrcpyOptions2_6<TVideo extends boolean>
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -48,7 +48,7 @@ export class ScrcpyOptions2_7<TVideo extends boolean>
readonly value: Required<Init<TVideo>>; readonly value: Required<Init<TVideo>>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -153,7 +153,21 @@ export class ScrcpyOptions2_7<TVideo extends boolean>
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -5,7 +5,7 @@ export const Defaults = {
...{ ...{
...PrevImpl.Defaults, ...PrevImpl.Defaults,
// Remove obsolete values // Remove obsolete values
// replies on minifier to flatten the nested spread // relies on the minifier to flatten the nested spread
lockVideoOrientation: undefined, lockVideoOrientation: undefined,
}, },

View file

@ -48,7 +48,7 @@ export class ScrcpyOptions3_0<TVideo extends boolean>
readonly value: Required<Init<TVideo>>; readonly value: Required<Init<TVideo>>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -153,7 +153,21 @@ export class ScrcpyOptions3_0<TVideo extends boolean>
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -48,7 +48,7 @@ export class ScrcpyOptions3_1<TVideo extends boolean>
readonly value: Required<Init<TVideo>>; readonly value: Required<Init<TVideo>>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -153,7 +153,21 @@ export class ScrcpyOptions3_1<TVideo extends boolean>
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -48,7 +48,7 @@ export class ScrcpyOptions3_2<TVideo extends boolean>
readonly value: Required<Init<TVideo>>; readonly value: Required<Init<TVideo>>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -153,7 +153,21 @@ export class ScrcpyOptions3_2<TVideo extends boolean>
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -48,7 +48,7 @@ export class ScrcpyOptions3_3_1<TVideo extends boolean>
readonly value: Required<Init<TVideo>>; readonly value: Required<Init<TVideo>>;
get controlMessageTypes() { get controlMessageTypes(): typeof ControlMessageTypes {
return ControlMessageTypes; return ControlMessageTypes;
} }
@ -153,7 +153,21 @@ export class ScrcpyOptions3_3_1<TVideo extends boolean>
serializeSetClipboardControlMessage( serializeSetClipboardControlMessage(
message: ScrcpySetClipboardControlMessage, message: ScrcpySetClipboardControlMessage,
): Uint8Array | [Uint8Array, Promise<void>] { ): Uint8Array | [Uint8Array, Promise<void>] {
return this.#ackClipboardHandler!.serializeSetClipboardControlMessage( if (!this.#ackClipboardHandler) {
if (!this.value.control) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `control: true`",
);
} else if (!this.value.clipboardAutosync) {
throw new Error(
"`serializeSetClipboardControlMessage` requires `clipboardAutosync: true`",
);
} else {
throw new Error("unreachable");
}
}
return this.#ackClipboardHandler.serializeSetClipboardControlMessage(
message, message,
); );
} }

View file

@ -24,7 +24,7 @@ export type BipedalGenerator<This, T, A extends unknown[]> = (
this: This, this: This,
then: <U>(value: MaybePromiseLike<U>) => Iterable<unknown, U, unknown>, then: <U>(value: MaybePromiseLike<U>) => Iterable<unknown, U, unknown>,
...args: A ...args: A
) => Generator<unknown, T, unknown>; ) => Generator<unknown, MaybePromiseLike<T>, unknown>;
/* #__NO_SIDE_EFFECTS__ */ /* #__NO_SIDE_EFFECTS__ */
export function bipedal<This, T, A extends unknown[]>( export function bipedal<This, T, A extends unknown[]>(

View file

@ -1,22 +1,26 @@
import type { Field } from "./field/index.js"; import type {
BipedalFieldDeserializer,
ByobFieldSerializer,
Field,
} from "./field/index.js";
import { field } from "./field/index.js"; import { field } from "./field/index.js";
export const EmptyUint8Array = new Uint8Array(0); export const EmptyUint8Array = new Uint8Array(0);
function copyMaybeDifferentLength( function copyMaybeDifferentLength(
dist: Uint8Array, dest: Uint8Array,
source: Uint8Array, source: Uint8Array,
index: number, index: number,
length: number, length: number,
) { ) {
if (source.length < length) { if (source.length < length) {
dist.set(source, index); dest.set(source, index);
// Clear trailing bytes // Clear trailing bytes
dist.fill(0, index + source.length, index + length); dest.fill(0, index + source.length, index + length);
} else if (source.length === length) { } else if (source.length === length) {
dist.set(source, index); dest.set(source, index);
} else { } else {
dist.set(source.subarray(0, length), index); dest.set(source.subarray(0, length), index);
} }
} }
@ -129,67 +133,47 @@ export function buffer(
): Field<unknown, string, Record<string, unknown>, Uint8Array> { ): Field<unknown, string, Record<string, unknown>, Uint8Array> {
// Fixed length // Fixed length
if (typeof lengthOrField === "number") { if (typeof lengthOrField === "number") {
let serialize: ByobFieldSerializer<Uint8Array>;
let deserialize: BipedalFieldDeserializer<
unknown,
Record<string, unknown>
>;
let init: ((value: unknown) => Uint8Array) | undefined;
if (lengthOrField === 0) {
serialize = () => {};
if (converter) { if (converter) {
if (lengthOrField === 0) {
return field(
0,
"byob",
() => {},
// eslint-disable-next-line require-yield // eslint-disable-next-line require-yield
function* () { deserialize = function* () {
return converter.convert(EmptyUint8Array); return converter.convert(EmptyUint8Array);
}, };
); } else {
}
return field(
lengthOrField,
"byob",
(value, { buffer, index }) => {
copyMaybeDifferentLength(
buffer,
value,
index,
lengthOrField,
);
},
function* (then, reader) {
const array = yield* then(
reader.readExactly(lengthOrField),
);
return converter.convert(array);
},
{
init(value) {
return converter.back(value);
},
},
);
}
if (lengthOrField === 0) {
return field(
0,
"byob",
() => {},
// eslint-disable-next-line require-yield // eslint-disable-next-line require-yield
function* () { deserialize = function* () {
return EmptyUint8Array; return EmptyUint8Array;
}, };
); }
} else {
serialize = (value, { buffer, index }) =>
copyMaybeDifferentLength(buffer, value, index, lengthOrField);
if (converter) {
deserialize = function* (then, reader) {
const array = reader.readExactly(lengthOrField);
return converter.convert(yield* then(array));
};
init = (value) => converter.back(value);
} else {
// eslint-disable-next-line require-yield
deserialize = function* (_then, reader) {
const array = reader.readExactly(lengthOrField);
return array;
};
}
} }
return field( return field(lengthOrField, "byob", serialize, deserialize, { init });
lengthOrField,
"byob",
(value, { buffer, index }) => {
copyMaybeDifferentLength(buffer, value, index, lengthOrField);
},
// eslint-disable-next-line require-yield
function* (_then, reader) {
return reader.readExactly(lengthOrField);
},
);
} }
// Declare length field // Declare length field
@ -199,48 +183,31 @@ export function buffer(
typeof lengthOrField === "function") && typeof lengthOrField === "function") &&
"serialize" in lengthOrField "serialize" in lengthOrField
) { ) {
let deserialize: BipedalFieldDeserializer<
unknown,
Record<string, unknown>
>;
let init: ((value: unknown) => Uint8Array) | undefined;
if (converter) { if (converter) {
return field( deserialize = function* (then, reader, context) {
lengthOrField.size,
"default",
(value, { littleEndian }) => {
if (lengthOrField.type === "default") {
const lengthBuffer = lengthOrField.serialize(
value.length,
{ littleEndian },
);
const result = new Uint8Array(
lengthBuffer.length + value.length,
);
result.set(lengthBuffer, 0);
result.set(value, lengthBuffer.length);
return result;
} else {
const result = new Uint8Array(
lengthOrField.size + value.length,
);
lengthOrField.serialize(value.length, {
buffer: result,
index: 0,
littleEndian,
});
result.set(value, lengthOrField.size);
return result;
}
},
function* (then, reader, context) {
const length = yield* then( const length = yield* then(
lengthOrField.deserialize(reader, context), lengthOrField.deserialize(reader, context),
); );
const array = yield* then(reader.readExactly(length)); const array =
return converter.convert(array); length !== 0 ? reader.readExactly(length) : EmptyUint8Array;
}, return converter.convert(yield* then(array));
{ };
init(value) { init = (value) => converter.back(value);
return converter.back(value); } else {
}, deserialize = function* (then, reader, context) {
}, const length = yield* then(
lengthOrField.deserialize(reader, context),
); );
const array =
length !== 0 ? reader.readExactly(length) : EmptyUint8Array;
return array;
};
} }
return field( return field(
@ -251,6 +218,11 @@ export function buffer(
const lengthBuffer = lengthOrField.serialize(value.length, { const lengthBuffer = lengthOrField.serialize(value.length, {
littleEndian, littleEndian,
}); });
if (value.length === 0) {
return lengthBuffer;
}
const result = new Uint8Array( const result = new Uint8Array(
lengthBuffer.length + value.length, lengthBuffer.length + value.length,
); );
@ -270,112 +242,91 @@ export function buffer(
return result; return result;
} }
}, },
function* (then, reader, context) { deserialize,
const length = yield* then( { init },
lengthOrField.deserialize(reader, context),
);
return yield* then(reader.readExactly(length));
},
); );
} }
// Reference exiting length field // Reference existing length field
if (typeof lengthOrField === "string") { if (typeof lengthOrField === "string") {
if (converter) { let deserialize: BipedalFieldDeserializer<
return field( unknown,
0, Record<string, unknown>
"default", >;
(source) => source, let init: (
// eslint-disable-next-line require-yield value: unknown,
function* (_then, reader, { dependencies }) { dependencies: Record<string, unknown>,
const length = dependencies[lengthOrField] as number; ) => Uint8Array;
if (length === 0) {
return EmptyUint8Array;
}
return reader.readExactly(length); if (converter) {
}, deserialize = function* (then, reader, { dependencies }) {
{ const length = dependencies[lengthOrField] as number;
init(value, dependencies) { const array =
length !== 0 ? reader.readExactly(length) : EmptyUint8Array;
return converter.convert(yield* then(array));
};
init = (value, dependencies) => {
const array = converter.back(value); const array = converter.back(value);
dependencies[lengthOrField] = array.length; dependencies[lengthOrField] = array.length;
return array; return array;
}, };
}, } else {
);
}
return field(
0,
"default",
(source) => source,
// eslint-disable-next-line require-yield // eslint-disable-next-line require-yield
function* (_then, reader, { dependencies }) { deserialize = function* (_then, reader, { dependencies }) {
const length = dependencies[lengthOrField] as number; const length = dependencies[lengthOrField] as number;
if (length === 0) { const array =
return EmptyUint8Array; length !== 0 ? reader.readExactly(length) : EmptyUint8Array;
return array;
};
init = (value, dependencies) => {
const array = value as Uint8Array;
dependencies[lengthOrField] = array.length;
return array;
};
} }
return reader.readExactly(length); return field(0, "default", (source) => source, deserialize, { init });
},
{
init(value, dependencies) {
dependencies[lengthOrField] = (value as Uint8Array).length;
return undefined;
},
},
);
} }
// Reference existing length field + converter let deserialize: BipedalFieldDeserializer<unknown, Record<string, unknown>>;
let init: (
value: unknown,
dependencies: Record<string, unknown>,
) => Uint8Array;
// Reference existing length field + length converter
if (converter) { if (converter) {
return field( deserialize = function* (then, reader, { dependencies }) {
0,
"default",
(source) => source,
// eslint-disable-next-line require-yield
function* (_then, reader, { dependencies }) {
const rawLength = dependencies[lengthOrField.field]; const rawLength = dependencies[lengthOrField.field];
const length = lengthOrField.convert(rawLength); const length = lengthOrField.convert(rawLength);
if (length === 0) { const array =
return EmptyUint8Array; length !== 0 ? reader.readExactly(length) : EmptyUint8Array;
} return converter.convert(yield* then(array));
};
return reader.readExactly(length); init = (value, dependencies) => {
},
{
init(value, dependencies) {
const array = converter.back(value); const array = converter.back(value);
dependencies[lengthOrField.field] = lengthOrField.back( dependencies[lengthOrField.field] = lengthOrField.back(
array.length, array.length,
); );
return array; return array;
}, };
}, } else {
);
}
return field(
0,
"default",
(source) => source,
// eslint-disable-next-line require-yield // eslint-disable-next-line require-yield
function* (_then, reader, { dependencies }) { deserialize = function* (_then, reader, { dependencies }) {
const rawLength = dependencies[lengthOrField.field]; const rawLength = dependencies[lengthOrField.field];
const length = lengthOrField.convert(rawLength); const length = lengthOrField.convert(rawLength);
if (length === 0) { const array =
return EmptyUint8Array; length !== 0 ? reader.readExactly(length) : EmptyUint8Array;
return array;
};
init = (value, dependencies) => {
const array = value as Uint8Array;
dependencies[lengthOrField.field] = lengthOrField.back(
array.length,
);
return array;
};
} }
return reader.readExactly(length); return field(0, "default", (source) => source, deserialize, { init });
},
{
init(value, dependencies) {
dependencies[lengthOrField.field] = lengthOrField.back(
(value as Uint8Array).length,
);
return undefined;
},
},
);
} }

View file

@ -25,7 +25,10 @@ export interface Field<T, OmitInit extends string, D, Raw = T>
FieldDeserializer<T, D> { FieldDeserializer<T, D> {
omitInit: OmitInit | undefined; omitInit: OmitInit | undefined;
init?(value: T, dependencies: D): Raw | undefined; /**
* A function to convert deserialized value back to raw value for serialization.
*/
init?(value: T, dependencies: D): Raw;
} }
export interface FieldDeserializeContext<D> { export interface FieldDeserializeContext<D> {
@ -44,5 +47,8 @@ export interface FieldDeserializer<T, D> {
export interface FieldOptions<T, OmitInit extends string, D, Raw = T> { export interface FieldOptions<T, OmitInit extends string, D, Raw = T> {
omitInit?: OmitInit; omitInit?: OmitInit;
dependencies?: D; dependencies?: D;
init?: (value: T, dependencies: D) => Raw | undefined; /**
* A function to convert deserialized value back to raw value for serialization.
*/
init?: ((value: T, dependencies: D) => Raw) | undefined;
} }

View file

@ -132,11 +132,9 @@ export function struct<
for (const [key, field] of fieldList) { for (const [key, field] of fieldList) {
if (key in temp && "init" in field) { if (key in temp && "init" in field) {
const result = field.init?.(temp[key], temp as never); const result = field.init?.(temp[key], temp as never);
if (result !== undefined) {
temp[key] = result; temp[key] = result;
} }
} }
}
const sizes = new Array<number>(fieldList.length); const sizes = new Array<number>(fieldList.length);
const buffers = new Array<Uint8Array | undefined>(fieldList.length); const buffers = new Array<Uint8Array | undefined>(fieldList.length);

View file

@ -1,12 +1,23 @@
import { writeFileSync } from "node:fs"; import { writeFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
async function generateTest(packageName, filename) { async function generateTest(packageName, filename) {
const exports = await import(packageName); const exports = await import(packageName);
const names = Object.keys(exports); const names = Object.keys(exports)
.filter(
(name) =>
name !== "default" && name !== "__esModule" && name !== "then",
)
.sort();
writeFileSync( writeFileSync(
filename, resolve(dirname(fileURLToPath(import.meta.url)), filename),
` `
// Generated by toolchain/side-effect-test/generate.mjs
// DO NOT MODIFY THIS FILE MANUALLY
/* eslint-disable */
import { ${names.join(", ")} } from "${packageName}"; import { ${names.join(", ")} } from "${packageName}";
export default () => { export default () => {

View file

@ -1,4 +1,8 @@
// Generated by toolchain/side-effect-test/generate.mjs
// DO NOT MODIFY THIS FILE MANUALLY
/* eslint-disable */
import { ADB_DAEMON_DEFAULT_INITIAL_PAYLOAD_SIZE, ADB_DAEMON_VERSION_OMIT_CHECKSUM, ADB_SYNC_MAX_PACKET_SIZE, ASN1_NULL, ASN1_OCTET_STRING, ASN1_OID, ASN1_SEQUENCE, Adb, AdbAuthType, AdbBanner, AdbBannerKey, AdbCommand, AdbDaemonSocket, AdbDaemonSocketController, AdbDaemonTransport, AdbDefaultAuthenticator, AdbDeviceFeatures, AdbFeature, AdbFrameBufferError, AdbFrameBufferForbiddenError, AdbFrameBufferUnsupportedVersionError, AdbFrameBufferV1, AdbFrameBufferV2, AdbNoneProtocolProcessImpl, AdbNoneProtocolPtyProcess, AdbNoneProtocolSubprocessService, AdbPacket, AdbPacketDispatcher, AdbPacketHeader, AdbPacketSerializeStream, AdbPower, AdbReverseError, AdbReverseNotSupportedError, AdbReverseService, AdbServerClient, AdbServerDeviceObserverOwner, AdbServerStream, AdbServerTransport, AdbServiceBase, AdbShellProtocolId, AdbShellProtocolPacket, AdbShellProtocolProcessImpl, AdbShellProtocolPtyProcess, AdbShellProtocolSubprocessService, AdbSubprocessService, AdbSync, AdbSyncDataResponse, AdbSyncEntry2Response, AdbSyncEntryResponse, AdbSyncError, AdbSyncFailResponse, AdbSyncLstatResponse, AdbSyncNumberRequest, AdbSyncOkResponse, AdbSyncRequestId, AdbSyncResponseId, AdbSyncSendV2Flags, AdbSyncSendV2Request, AdbSyncSocket, AdbSyncSocketLocked, AdbSyncStatErrorCode, AdbSyncStatResponse, AdbTcpIpService, AutoResetEvent, FAIL, LinuxFileType, NOOP, Ref, SHA1_DIGEST_INFO, SHA1_DIGEST_LENGTH, ToArrayStream, adbGeneratePublicKey, adbGetPublicKeySize, adbNoneProtocolSpawner, adbShellProtocolSpawner, adbSyncLstat, adbSyncOpenDir, adbSyncOpenDirV1, adbSyncOpenDirV2, adbSyncPull, adbSyncPullGenerator, adbSyncPush, adbSyncPushV1, adbSyncPushV2, adbSyncReadResponse, adbSyncReadResponses, adbSyncStat, adbSyncWriteRequest, calculateBase64EncodedLength, calculateChecksum, createLazyPromise, decodeBase64, decodeUtf8, decodeUtf8Chunked, dirname, encodeBase64, encodeUtf8, escapeArg, framebuffer, getBigUint, hexToNumber, modInverse, powMod, raceSignal, rsaParsePrivateKey, rsaSign, sequenceEqual, setBigUint, splitCommand, toLocalUint8Array, unorderedRemove, unreachable, write4HexDigits } from "@yume-chan/adb"; import { ADB_DAEMON_DEFAULT_INITIAL_PAYLOAD_SIZE, ADB_DAEMON_VERSION_OMIT_CHECKSUM, ADB_SYNC_MAX_PACKET_SIZE, ASN1_NULL, ASN1_OCTET_STRING, ASN1_OID, ASN1_SEQUENCE, Adb, AdbAuthType, AdbBanner, AdbBannerKey, AdbCommand, AdbDaemonSocket, AdbDaemonSocketController, AdbDaemonTransport, AdbDefaultAuthenticator, AdbDeviceFeatures, AdbFeature, AdbFrameBufferError, AdbFrameBufferForbiddenError, AdbFrameBufferUnsupportedVersionError, AdbFrameBufferV1, AdbFrameBufferV2, AdbNoneProtocolProcessImpl, AdbNoneProtocolPtyProcess, AdbNoneProtocolSubprocessService, AdbPacket, AdbPacketDispatcher, AdbPacketHeader, AdbPacketSerializeStream, AdbPower, AdbReverseError, AdbReverseNotSupportedError, AdbReverseService, AdbServerClient, AdbServerDeviceObserverOwner, AdbServerStream, AdbServerTransport, AdbServiceBase, AdbShellProtocolId, AdbShellProtocolPacket, AdbShellProtocolProcessImpl, AdbShellProtocolPtyProcess, AdbShellProtocolSubprocessService, AdbSubprocessService, AdbSync, AdbSyncDataResponse, AdbSyncEntry2Response, AdbSyncEntryResponse, AdbSyncError, AdbSyncFailResponse, AdbSyncLstatResponse, AdbSyncNumberRequest, AdbSyncOkResponse, AdbSyncRequestId, AdbSyncResponseId, AdbSyncSendV2Flags, AdbSyncSendV2Request, AdbSyncSocket, AdbSyncSocketLocked, AdbSyncStatErrorCode, AdbSyncStatResponse, AdbTcpIpService, AutoResetEvent, FAIL, LinuxFileType, NOOP, Ref, SHA1_DIGEST_INFO, SHA1_DIGEST_LENGTH, ToArrayStream, adbGeneratePublicKey, adbGetPublicKeySize, adbNoneProtocolSpawner, adbShellProtocolSpawner, adbSyncLstat, adbSyncOpenDir, adbSyncOpenDirV1, adbSyncOpenDirV2, adbSyncPull, adbSyncPullGenerator, adbSyncPush, adbSyncPushV1, adbSyncPushV2, adbSyncReadResponse, adbSyncReadResponses, adbSyncStat, adbSyncWriteRequest, calculateBase64EncodedLength, calculateChecksum, createLazyPromise, decodeBase64, decodeUtf8, decodeUtf8Chunked, dirname, encodeBase64, encodeUtf8, escapeArg, framebuffer, getBigUint, hexToNumber, modInverse, powMod, raceSignal, rsaParsePrivateKey, rsaSign, sequenceEqual, setBigUint, splitCommand, toLocalUint8Array, unorderedRemove, unreachable, write4HexDigits } from "@yume-chan/adb";
export default () => { export default () => {

View file

@ -1,4 +1,8 @@
// Generated by toolchain/side-effect-test/generate.mjs
// DO NOT MODIFY THIS FILE MANUALLY
/* eslint-disable */
import { AndroidAvcLevel, AndroidAvcProfile, AndroidHevcLevel, AndroidHevcProfile, AndroidKeyCode, AndroidKeyEventAction, AndroidKeyEventMeta, AndroidKeyNames, AndroidMotionEventAction, AndroidMotionEventButton, AndroidScreenPowerMode, DefaultServerPath, EmptyControlMessage, ScrcpyAudioCodec, ScrcpyBackOrScreenOnControlMessage, ScrcpyCaptureOrientation, ScrcpyCodecOptions, ScrcpyControlMessageSerializer, ScrcpyControlMessageType, ScrcpyControlMessageWriter, ScrcpyCrop, ScrcpyDeviceMessageParsers, ScrcpyInjectKeyCodeControlMessage, ScrcpyInjectScrollControlMessage, ScrcpyInjectTextControlMessage, ScrcpyInjectTouchControlMessage, ScrcpyInstanceId, ScrcpyLockOrientation, ScrcpyNewDisplay, ScrcpyOptions1_15, ScrcpyOptions1_15_1, ScrcpyOptions1_16, ScrcpyOptions1_17, ScrcpyOptions1_18, ScrcpyOptions1_19, ScrcpyOptions1_20, ScrcpyOptions1_21, ScrcpyOptions1_22, ScrcpyOptions1_23, ScrcpyOptions1_24, ScrcpyOptions1_25, ScrcpyOptions2_0, ScrcpyOptions2_1, ScrcpyOptions2_1_1, ScrcpyOptions2_2, ScrcpyOptions2_3, ScrcpyOptions2_3_1, ScrcpyOptions2_4, ScrcpyOptions2_5, ScrcpyOptions2_6, ScrcpyOptions2_6_1, ScrcpyOptions2_7, ScrcpyOptions3_0, ScrcpyOptions3_0_1, ScrcpyOptions3_0_2, ScrcpyOptions3_1, ScrcpyOptions3_2, ScrcpyOptions3_3, ScrcpyOptions3_3_1, ScrcpyOptions3_3_2, ScrcpyOptionsLatest, ScrcpyOrientation, ScrcpyPointerId, ScrcpySetClipboardControlMessage, ScrcpySetDisplayPowerControlMessage, ScrcpyUHidCreateControlMessage, ScrcpyUHidOutputDeviceMessage, ScrcpyVideoCodecId, ScrcpyVideoCodecNameMap, ScrcpyVideoSizeImpl, clamp, isScrcpyOptionValue, omit, toScrcpyOptionValue } from "@yume-chan/scrcpy"; import { AndroidAvcLevel, AndroidAvcProfile, AndroidHevcLevel, AndroidHevcProfile, AndroidKeyCode, AndroidKeyEventAction, AndroidKeyEventMeta, AndroidKeyNames, AndroidMotionEventAction, AndroidMotionEventButton, AndroidScreenPowerMode, DefaultServerPath, EmptyControlMessage, ScrcpyAudioCodec, ScrcpyBackOrScreenOnControlMessage, ScrcpyCaptureOrientation, ScrcpyCodecOptions, ScrcpyControlMessageSerializer, ScrcpyControlMessageType, ScrcpyControlMessageWriter, ScrcpyCrop, ScrcpyDeviceMessageParsers, ScrcpyInjectKeyCodeControlMessage, ScrcpyInjectScrollControlMessage, ScrcpyInjectTextControlMessage, ScrcpyInjectTouchControlMessage, ScrcpyInstanceId, ScrcpyLockOrientation, ScrcpyNewDisplay, ScrcpyOptions1_15, ScrcpyOptions1_15_1, ScrcpyOptions1_16, ScrcpyOptions1_17, ScrcpyOptions1_18, ScrcpyOptions1_19, ScrcpyOptions1_20, ScrcpyOptions1_21, ScrcpyOptions1_22, ScrcpyOptions1_23, ScrcpyOptions1_24, ScrcpyOptions1_25, ScrcpyOptions2_0, ScrcpyOptions2_1, ScrcpyOptions2_1_1, ScrcpyOptions2_2, ScrcpyOptions2_3, ScrcpyOptions2_3_1, ScrcpyOptions2_4, ScrcpyOptions2_5, ScrcpyOptions2_6, ScrcpyOptions2_6_1, ScrcpyOptions2_7, ScrcpyOptions3_0, ScrcpyOptions3_0_1, ScrcpyOptions3_0_2, ScrcpyOptions3_1, ScrcpyOptions3_2, ScrcpyOptions3_3, ScrcpyOptions3_3_1, ScrcpyOptions3_3_2, ScrcpyOptionsLatest, ScrcpyOrientation, ScrcpyPointerId, ScrcpySetClipboardControlMessage, ScrcpySetDisplayPowerControlMessage, ScrcpyUHidCreateControlMessage, ScrcpyUHidOutputDeviceMessage, ScrcpyVideoCodecId, ScrcpyVideoCodecNameMap, ScrcpyVideoSizeImpl, clamp, isScrcpyOptionValue, omit, toScrcpyOptionValue } from "@yume-chan/scrcpy";
export default () => { export default () => {