dart_packstream 1.2.0
dart_packstream: ^1.2.0 copied to clipboard
A Dart library for serializing and deserializing data using the Packstream format.
dart_packstream #
A Dart implementation of the PackStream binary serialization format used by Neo4j's Bolt protocol.
Overview #
PackStream is a binary presentation format for the exchange of richly-typed data. It provides a syntax layer for the Bolt messaging protocol used by Neo4j. This library provides a complete implementation of PackStream version 1, supporting all core data types with strong type safety and efficient serialization.
Features #
- ✅ Complete PackStream v1 implementation
- ✅ All core data types (Null, Boolean, Integer, Float, Bytes, String, List, Dictionary, Structure)
- ✅ Optimized integer representations (TINY_INT, INT_8, INT_16, INT_32, INT_64)
- ✅ Type-safe serialization and deserialization
- ✅ Automatic conversion from Dart types
- ✅ Structure extension mechanism
- ✅ Big-endian byte ordering compliance
- ✅ UTF-8 string encoding
- ✅ Zero-copy ByteData operations
Installation #
Add this to your package's pubspec.yaml file:
dependencies:
dart_packstream: <latest_version>
Then run:
dart pub get
Core Data Types #
| PackStream Type | Dart Class | Description |
|---|---|---|
| Null | PsNull |
Missing or empty value |
| Boolean | PsBoolean |
true or false |
| Integer | PsInt family |
Signed 64-bit integers with optimized representations |
| Float | PsFloat |
64-bit floating point numbers |
| Bytes | PsBytes |
Byte arrays |
| String | PsString |
UTF-8 encoded text |
| List | PsList |
Ordered collection of values |
| Dictionary | PsDictionary |
Collection of key-value entries |
| Structure | PsStructure |
Composite values with type signatures |
Integer Representations #
The library automatically chooses the most compact integer representation:
PsTinyInt- 1 byte for values -16 to 127PsInt8- 2 bytes for values -128 to -17PsInt16- 3 bytes for larger 16-bit valuesPsInt32- 5 bytes for larger 32-bit valuesPsInt64- 9 bytes for full 64-bit range
Usage #
Creating PackStream Values #
import 'package:dart_packstream/dart_packstream.dart';
// Basic types
final nullValue = PsNull();
final boolValue = PsBoolean(true);
final intValue = PsInt.compact(42); // Automatically chooses optimal representation
final floatValue = PsFloat(3.14159);
final stringValue = PsString("Hello, World!");
final bytesValue = PsBytes(Uint8List.fromList([1, 2, 3, 4]));
// Collections
final listValue = PsList([intValue, stringValue, boolValue]);
final dictValue = PsDictionary({
PsString("name"): PsString("Alice"),
PsString("age"): PsInt.compact(30),
});
Automatic Conversion from Dart Types #
// Convert Dart values automatically
final psString = PsDataType.fromValue("Hello"); // -> PsString
final psInt = PsDataType.fromValue(42); // -> optimal PsInt representation
final psList = PsDataType.fromValue([1, "two", true]); // -> PsList
final psDict = PsDataType.fromValue({"key": "value"}); // -> PsDictionary
final psBytes = PsDataType.fromValue(Uint8List.fromList([1, 2, 3])); // -> PsBytes
Serialization and Deserialization #
// Serialize to bytes
final value = PsString("Hello, World!");
final bytes = value.toBytes(); // Uint8List
final byteData = value.toByteData(); // ByteData
// Deserialize from bytes
final parsed = PsDataType.fromPackStreamBytes(ByteData.view(bytes.buffer));
print(parsed.dartValue); // "Hello, World!"
// Access both PackStream and Dart representations
print(value.value); // "Hello, World!" (original)
print(value.dartValue); // "Hello, World!" (converted)
print(value.marker); // 0x85 (PackStream marker byte)
Working with Collections #
// Lists can contain mixed types
final mixedList = PsList([
PsInt.compact(1),
PsString("two"),
PsBoolean(true),
PsFloat(4.0),
]);
// Dictionaries use PsString keys
final person = PsDictionary({
PsString("id"): PsInt.compact(12345),
PsString("name"): PsString("John Doe"),
PsString("active"): PsBoolean(true),
PsString("score"): PsFloat(98.5),
});
// Access values by converting to Dart types
final Map<String, dynamic> dartMap = person.dartValue;
print(dartMap["name"]); // "John Doe"
Working with Structures #
Structures are used for domain-specific data types and require registration:
// Register a structure factory (typically done by consumer libraries)
PsStructureRegistry.register(0x4E, (values) => MyNodeStructure(values));
// Create structures
class MyNodeStructure extends PsStructure {
MyNodeStructure(List<PsDataType> values) : super(0x4E, values);
int get id => values[0].dartValue;
String get label => values[1].dartValue;
}
// Use structures
final structure = MyNodeStructure([
PsInt.compact(1),
PsString("Person")
]);
final bytes = structure.toBytes();
final parsed = PsDataType.fromPackStreamBytes(ByteData.view(bytes.buffer));
Type Safety and Conversion #
All PackStream types provide strong typing and convenient access patterns:
final psValue = PsString("Hello");
// Type-safe access
String stringValue = psValue.value; // Direct access to wrapped value
dynamic dartValue = psValue.dartValue; // Dart-compatible representation
int marker = psValue.marker; // PackStream marker byte
// Pattern matching
switch (psValue.runtimeType) {
case PsString:
print("It's a string: ${psValue.value}");
break;
case PsInt:
print("It's an integer: ${psValue.value}");
break;
// ... other types
}
Performance Considerations #
- Use
PsInt.compact()for automatic optimal integer representation - Prefer
ByteDataoperations for high-performance scenarios - Structure factories are cached for efficient deserialization
- The library uses zero-copy operations where possible
PackStream Specification Compliance #
This library implements PackStream v1 according to the official specification:
- Big-endian byte ordering
- UTF-8 string encoding
- IEEE 754 double-precision floats
- Optimal integer representations
- Variable-length encoding for collections
- Structure extension mechanism
Related Packages #
This library is part of the dart_neo4j ecosystem:
dart_bolt- Neo4j Bolt protocol implementationdart_neo4j- Complete Neo4j driver
Contributing #
Contributions are welcome! Please read the contributing guidelines and submit pull requests to the GitHub repository.
License #
This project is licensed under the GNU General Public License v3.0 (GPL-3.0).