DeutschGitHub
prototypepackages/binary-serializer/src

Binary Serializer

@ralphschuler/binary-serializer

Round-trips fixed-layout unsigned integers, booleans, UTF-8 strings and arrays.

binarycodecschema

01 · Problem

What is it for?

A binary format needs fixed widths, byte order and bounds; JavaScript objects do not provide a wire layout.

02 · Mental model

How should you think about it?

A schema is a cursor program: each field consumes a documented number of bytes in a deterministic order.

In this repository

Round-trips fixed-layout unsigned integers, booleans, UTF-8 strings and arrays. This is a versionless fixed-layout format. Schema ordering and migration must be agreed by both endpoints; decorators use the legacy TypeScript contract.

03 · Control flow

What happens in which order?

  1. Define field order and byte widths.
  2. Allocate the required buffer.
  3. Write fields and advance the cursor.
  4. Read using the same schema and bounds.

04 · Building blocks

The important contracts

BinarySerializer.serialize / deserializeRead and write explicit fixed-layout schemas.
Serializable / AsNumber / AsBoolean / AsString / AsArray / SerializedDeclare legacy decorator schemas, including nested serializable fields.

05 · Build it yourself

Implement a small core

Start with this small independent implementation, then use the steps below to make its contract explicit.

  1. Define field order and byte widths.
  2. Allocate the required buffer.
  3. Write fields and advance the cursor.
  4. Read using the same schema and bounds.
Concept sketch · may reference omitted helpers
type Decoded<T> = { value: T; offset: number };

interface Codec<T> {
  size(value: T): number;
  encode(view: DataView, offset: number, value: T): number;
  decode(view: DataView, offset: number): Decoded<T>;
}

const u32: Codec<number> = {
  size: () => 4,
  encode: (view, at, value) => (view.setUint32(at, value, true), at + 4),
  decode: (view, at) => ({ value: view.getUint32(at, true), offset: at + 4 }),
};

06 · Verify

What should you test?

  • Assert exact bytes as well as round-trip values.
  • Test truncated buffers and oversized strings.
  • Check nested schemas and UTF-8 byte boundaries.

Try it yourself

Turn the first verification claim into a failing test, implement the smallest fix, then add a boundary case.

Assert exact bytes as well as round-trip values.

Compare your approach

Your check should fail when the stated invariant is deliberately broken, and pass again after the fix. Keep setup deterministic and assert an observable result.

07 · Limits

Trade-offs and failure modes

  • Numbers currently use unsigned 32-bit little-endian encoding.
  • Schema evolution requires an explicit version.
  • Decorator insertion order alone is a fragile wire contract.
Important

This is a versionless fixed-layout format. Schema ordering and migration must be agreed by both endpoints; decorators use the legacy TypeScript contract.

08 · Keep exploring

Source code and related ideas

yarn tsx packages/binary-serializer/examples/basic.ts