ya-webadb/libraries/struct
2025-03-02 18:11:10 +08:00
..
src refactor(scrcpy): rewrite option classes to improve tree-shaking 2024-11-27 14:43:33 +08:00
.npmignore chore: integrate ESLint 2022-12-22 01:42:24 +08:00
CHANGELOG.md chore: version 1.0.0 2024-12-02 10:36:49 +08:00
jest.config.js chore: update dependencies 2023-07-07 18:30:13 +08:00
LICENSE chore: update dependencies, update license year 2025-03-02 18:11:10 +08:00
package.json chore: update dependencies, update license year 2025-03-02 18:11:10 +08:00
README.md refactor(struct): improve tree-shaking 2024-11-01 22:06:18 +08:00
tsconfig.build.json chore: switch to node test 2024-07-23 18:10:40 +08:00
tsconfig.json chore: switch to node test 2024-07-23 18:10:40 +08:00
tsconfig.test.json chore: switch to node test 2024-07-23 18:10:40 +08:00

@yume-chan/struct

license npm type definitions npm version npm bundle size Codecov

A C-style structure serializer and deserializer. Written in TypeScript and highly takes advantage of its type system.

The new API is inspired by TypeGPU which improves DX and tree-shaking.

WARNING: The public API is UNSTABLE. Open a GitHub discussion if you have any questions.

Installation

$ npm i @yume-chan/struct

Quick Start

import { struct, u8, u16, s32, buffer, string } from "@yume-chan/struct";

const Message = struct(
    {
        a: u8,
        b: u16,
        c: s32,
        d: buffer(4), // Fixed length Uint8Array
        e: buffer("b"), // Use value of `b` as length
        f: buffer(u32), // `u32` length prefix
        g: buffer(4, {
            // Custom conversion between `Uint8Array` and other types
            convert(value: Uint8Array) {
                return value[0];
            },
            back(value: number) {
                return new Uint8Array([value, 0, 0, 0]);
            },
        }),
        h: string(64), // `string` is an alias to `buffer` with UTF-8 string conversion
    },
    { littleEndian: true },
);

// Custom reader
const reader = {
    position: 0,
    readExactly(length) {
        const slice = new Uint8Array(100).slice(
            this.position,
            this.position + length,
        );
        this.position += length;
        return slice;
    },
};

const message1 = Message.deserialize(reader); // If `reader.readExactly` is synchronous, `deserialize` is also synchronous
const message2 = await Message.deserialize(reader); // If `reader.readExactly` is asynchronous, so do `deserialize`

const buffer: Uint8Array = Message.serialize(message1);

Custom field types

import { Field, AsyncExactReadable, Struct, u8 } from "@yume-chan/struct";

const MyField: Field<number, never, never> = {
    size: 4, // `0` if dynamically sized,
    dynamicSize(value: number) {
        // Optional, return dynamic size for value
        return 0;
    },
    serialize(
        value: number,
        context: { buffer: Uint8Array; index: number; littleEndian: boolean },
    ) {
        // Serialize value to `context.buffer` at `context.index`
    },
    deserialize(context: {
        reader: AsyncExactReadable;
        littleEndian: boolean;
    }) {
        // Deserialize value from `context.reader`
        return 0;
    },
};

const Message2 = struct({
    a: u8,
    b: MyField,
});

Bipedal

bipedal is a custom async helper that allows the same code to behave synchronously or asynchronously depends on the parameters.

It's inspired by gensync.

The word bipedal refers to animals who walk using two legs.

import { bipedal } from "@yume-chan/struct";

const fn = bipedal(function* (then, name: string | Promise<string>) {
    name = yield* then(name);
    return "Hello, " + name;
});

fn("Simon"); // "Hello, Simon"
await fn(Promise.resolve("Simon")); // "Hello, Simon"