Skip to content

Repository files navigation

pro_binary

pub packageTestsLicense: MIT

High-performance binary serialization and deserialization for Dart. Optimized for high-frequency network protocols, real-time streaming, and fast local storage. Features zero-copy reads, object pooling, and transactional stream parsing.

Table of Contents

Key Features

  • Extreme Performance: Built from the ground up for speed. Leverages Dart Extension Types for zero-overhead abstractions and direct memory manipulation.
  • Zero-Copy Reads: Deserialization operations return Uint8List views instead of allocating new memory arrays, significantly reducing GC (Garbage Collector) pauses.
  • Scatter-Gather (Zero-Copy) Writes: Emit large borrowed payloads (e.g. an HTTP/2 DATA frame body) without copying via writeView, then hand off the ordered segments with takeChunks() / writeTo(sink) — the classic writev/iovec pattern. Lazy: zero overhead when unused.
  • One-Pass String Encoding: Features a highly optimized writeVarString with optimistic size estimation and native memory shifting. Up to ~30% faster than standard utf8.encode.
  • Zero-Allocation Object Pooling: Includes built-in BinaryWriterPool to reuse writer instances. Perfect for high-frequency network packets (e.g., game servers, WebSockets).
  • Compact Encoding: Native support for VarInt and ZigZag encoding to shrink payload sizes for integers.
  • Transactional Stream Parsing: Easily process fragmented asynchronous data chunks using StreamBinaryReader with bookmark() and rollback() capabilities.
  • Cross-Platform: 100% pure Dart. Works seamlessly across Native (AOT/JIT) and Web (WASM/JS) with a consistent, predictable API.

Installation

Add pro_binary to your pubspec.yaml manually:

dependencies:
pro_binary: any

Or add it using the command line:

# For Dart projects
dart pub add pro_binary
# For Flutter projects
flutter pub add pro_binary

Quick Start

import'package:pro_binary/pro_binary.dart';
// Serializefinal writer =BinaryWriter()
..writeUint32(42)
..writeVarString('Dart 🚀')
..writeBool(true);
final bytes = writer.takeBytes(); // takes the buffer and resets the writer// Deserializefinal reader =BinaryReader(bytes);
print(reader.readUint32()); // 42print(reader.readVarString()); // Dart 🚀print(reader.readBool()); // true// From List<int>final bytesList =<int>[0x01, 0x02, 0x03, 0x04];
final reader2 =BinaryReader.fromList(bytesList);

Recipes & Patterns

1. Efficient Object Serialization

classUser {
finalint id;
finalString name;
User(this.id, this.name);
voidencode(BinaryWriter w) => w
..writeVarUint(id) // compact integer encoding
..writeVarString(name); // fast one-pass UTF-8 encodingfactoryUser.decode(BinaryReader r) =>User(
r.readVarUint(), r.readVarString(),
);
}

2. High-Frequency writes (Pooling)

Avoid GC pressure by reusing writer instances.

Recommended (Safe & Concise):

final data =BinaryWriterPool.withWriter((writer) {
writer.writeUint32(1);
writer.writeVarString('Dart Rocks!');
// toBytes(): returns a zero-copy VIEW. Use for immediate processing (e.g. socket.add).// takeBytes(): detaches the buffer and RESETS the writer. Safe for returning data.return writer.takeBytes(); });

Low-level API:

final writer =BinaryWriterPool.acquire();
try {
writer.writeUint32(1);
writer.writeVarString('Dart Rocks!');
final data = writer.toBytes();
socket.add(data); // Process data BEFORE releasing back to the pool
} finally {
BinaryWriterPool.release(writer);
}

3. Stream Parsing (Async Binary Messages)

Process binary data arriving in chunks over a stream.

Custom Transformer:

classMessageParserextendsBinaryStreamTransformer<Message> {
@overrideMessage?parse(StreamBinaryReader reader) {
// Return null when not enough data yetif (!reader.hasBytes(4)) {
returnnull;
}
final id = reader.readUint32();
final name = reader.readVarString();
returnMessage(id, name);
}
}
// Usage:
stream.transform(MessageParser()).listen((msg) =>print(msg));

Manual Chunk Reading:

final reader =StreamBinaryReader();
reader.addChunk(chunk1);
reader.addChunk(chunk2);
reader.bookmark();
try {
final id = reader.readUint32();
final name = reader.readVarString();
reader.commit(); // Success — consumed
} onNotEnoughDataException {
reader.rollback(); // Wait for more data
}

4. Binary Packets (Manual navigation)

final reader =BinaryReader(bytes);
final type = reader[0]; // Absolute peek via operator []
reader.skip(1);
if (reader.hasBytes(4)) {
final payload =reader(4); // Concise call syntax for readBytes.
}

Examples

Explore the example directory for complete, runnable projects:

API Overview

Full API documentation

ComponentDescription
BinaryWriterFast encoder for fixed-width (incl. 24-bit writeUint24), VarInt/ZigZag, and one-pass strings. Features automatic expansion, pooling, in-place buffer manipulation (skip, shiftBytes), and scatter-gather zero-copy output (writeView, takeChunks, writeTo).
BinaryReaderZero-copy decoder for fixed-width (incl. 24-bit readUint24), VarInt/ZigZag, and strings, with advanced navigation (seek, rewind, peek). Optimized for performance.
StreamBinaryReaderHandles async data chunks seamlessly with a transactional bookmark/rollback model for partial data.
BinaryStreamTransformerThe easiest way to parse a Stream<List<int>> into a stream of typed messages or objects.
BinaryWriterPoolObject pool for BinaryWriter to eliminate GC pressure during high-frequency write operations.

Performance

pro_binary is built for extreme performance. Our AOT benchmarks show massive improvements over standard Dart approaches:

String Encoding (One-Pass vs utf8.encode)

Our highly optimized one-pass string encoder is up to 2.7x faster than standard utf8.encode.

Payloadpro_binary (One-Pass)Standard (utf8.encode)Speedup
ASCII0.79 μs2.15 μs2.7x
Mixed UTF-81.15 μs2.62 μs2.28x
Emoji / Complex1.91 μs4.17 μs2.18x

Object Serialization & Deserialization

Extremely low overhead for serializing and deserializing Dart objects.

ScenarioSerializationDeserialization
Simple Message0.31 μs0.14 μs
Complex Profile1.62 μs1.73 μs
10K integers array403.5 μs284.5 μs

Object Pooling

Using BinaryWriterPool reduces allocation overhead and virtually eliminates GC (Garbage Collector) pauses during high-frequency writes (like game servers or real-time trading).


Run these benchmarks yourself to see it in action:

# Serialization (Writer)
dart run benchmark_harness:bench --flavor aot --target performance/serialization_bench.dart
# Deserialization (Reader)
dart run benchmark_harness:bench --flavor aot --target performance/deserialization_bench.dart
# String encoding (One-pass vs Two-pass vs Standard)
dart run benchmark_harness:bench --flavor aot --target performance/strings_bench.dart
# Object Pooling (GC impact mitigation)
dart run benchmark_harness:bench --flavor aot --target performance/pool_bench.dart

Testing

The library is heavily tested with over 200+ unit and integration tests.

# Run all tests
dart test# Run tests with coverage
dart test --coverage=coverage

Contributing

Contributions are welcome! Please ensure that all tests pass and code is formatted before submitting a Pull Request.

# Formatter
dart format .# Analyzer
dart analyze
# Tests
dart test

License

MIT License. See LICENSE for details.

About

This library provides efficient binary reading and writing capabilities.

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages