EnglishGitHub
Prototyppackages/binary-serializer/src

Binary Serializer

@ralphschuler/binary-serializer

Serialisiert feste Layouts aus vorzeichenlosen Ganzzahlen, Booleans, UTF-8-Strings und Arrays.

binarycodecschema

01 · Problem

Wofür braucht man das?

Binärformate sparen Platz und geben ein exaktes Wire-Layout vor, verlangen dafür aber konsistente Feldreihenfolge, Größenberechnung, Bounds-Prüfung und Versionierung.

02 · Denkmodell

Das mentale Modell

Jeder Datentyp ist ein Codec mit drei Operationen: Größe berechnen, ab Offset schreiben und ab Offset lesen. Strukturen komponieren diese kleinen Codecs in expliziter Reihenfolge.

Im Repository

Serialisiert feste Layouts aus vorzeichenlosen Ganzzahlen, Booleans, UTF-8-Strings und Arrays. Dies ist ein festes Layout ohne Versionskennung. Schema-Reihenfolge und Migration müssen beide Seiten vereinbaren; Decorators folgen dem Legacy-TypeScript-Vertrag.

03 · Kontrollfluss

Was passiert in welcher Reihenfolge?

  1. Schema mit fester Feldreihenfolge und eindeutigem Typ pro Feld definieren.
  2. Exakte Bytezahl vor der Allokation rekursiv berechnen.
  3. Felder schreiben und den Offset nach jeder Operation fortführen.
  4. Beim Lesen Bounds prüfen, Werte rekonstruieren und finalen Offset zurückgeben.
  5. Formatkennung und Version vor Nutzdaten setzen.

04 · Bauteile

Die entscheidenden Verträge

BinarySerializer.serialize / deserializeLiest und schreibt explizite feste Layoutschemas.
Serializable / AsNumber / AsBoolean / AsString / AsArray / SerializedDeklariert Legacy-Decorator-Schemas einschließlich verschachtelter serialisierbarer Felder.

05 · Selbst bauen

Selbst implementieren

Ein explizites Codec-Objekt ist leichter zu testen und zu versionieren als implizite Decorator-Metadaten.

  1. Definiere einen Codec-Vertrag, der Wert und Offset gemeinsam weiterreicht.
  2. Baue Primitive wie u32 und bool mit strikten Bereichsprüfungen.
  3. Komponiere Arrays und Structs, ohne Feldreihenfolge aus Reflection abzuleiten.
Konzeptskizze · kann ausgelassene Helfer verwenden
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 · Verifizieren

Was solltest du testen?

  • encode gefolgt von decode ergibt für jedes gültige Objekt denselben Wert und Endoffset.
  • Zu kurze Buffer, zu große Zahlen und falsche Längen werden vor dem Zugriff abgelehnt.
  • Bekannte Golden Bytes sichern Endianness, Feldreihenfolge und Versionsheader.

Selbst ausprobieren

Formuliere die erste Prüfaussage als fehlschlagenden Test, implementiere die kleinste Korrektur und ergänze einen Grenzfall.

encode gefolgt von decode ergibt für jedes gültige Objekt denselben Wert und Endoffset.

Ansatz vergleichen

Dein Test sollte beim gezielten Verletzen der Invariante fehlschlagen und nach der Korrektur wieder bestehen. Halte den Aufbau deterministisch und prüfe ein beobachtbares Ergebnis.

07 · Grenzen

Kompromisse und Stolperfallen

  • Feste Felder sind schnell, aber schlecht erweiterbar; variable Felder benötigen Längenpräfixe.
  • UTF-8-Längen zählen Bytes, nicht JavaScript-Zeichen.
  • Schemaänderungen ohne Versionsstrategie machen gespeicherte Daten unlesbar.
Wichtig

Dies ist ein festes Layout ohne Versionskennung. Schema-Reihenfolge und Migration müssen beide Seiten vereinbaren; Decorators folgen dem Legacy-TypeScript-Vertrag.

08 · Weiterdenken

Quellcode und verwandte Ideen

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