@yume-chan/struct v1.0.0
@yume-chan/struct
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"
7 months ago
7 months ago
7 months ago
10 months ago
1 year ago
12 months ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
2 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago