d_bincode 3.2.0 copy "d_bincode: ^3.2.0" to clipboard
d_bincode: ^3.2.0 copied to clipboard

A performant Dart implementation of the Bincode binary serialization format. Requires manual implementation for encoding/decoding custom types.

example/d_bincode_example.dart

import 'dart:typed_data';

import 'package:collection/collection.dart';
import 'package:d_bincode/d_bincode.dart';

class NestedData implements BincodeCodable {
  int nestedId = 0;
  String nestedName = "Default Nested";
  NestedData();
  NestedData.create(this.nestedId, this.nestedName);
  @override
  void encode(BincodeWriter w) {
    w.writeI32(nestedId);
    w.writeString(nestedName);
  }

  @override
  void decode(BincodeReader r) {
    nestedId = r.readI32();
    nestedName = r.readString();
  }

  @override
  bool operator ==(Object other) =>
      other is NestedData &&
      nestedId == other.nestedId &&
      nestedName == other.nestedName;
  @override
  int get hashCode => nestedId.hashCode ^ nestedName.hashCode;
  @override
  String toString() => 'NestedData(id: $nestedId, name: "$nestedName")';
}

class FixedStruct implements BincodeCodable {
  int valueA = 0;
  double valueB = 0.0;
  bool flagC = false;
  FixedStruct();
  FixedStruct.create(this.valueA, this.valueB, this.flagC);
  @override
  void encode(BincodeWriter w) {
    w.writeI32(valueA);
    w.writeF64(valueB);
    w.writeBool(flagC);
  }

  @override
  void decode(BincodeReader r) {
    valueA = r.readI32();
    valueB = r.readF64();
    flagC = r.readBool();
  }

  @override
  bool operator ==(Object other) =>
      other is FixedStruct &&
      valueA == other.valueA &&
      valueB == other.valueB &&
      flagC == other.flagC;
  @override
  int get hashCode => valueA.hashCode ^ valueB.hashCode ^ flagC.hashCode;
  @override
  String toString() => 'Fixed(A:$valueA, B:$valueB, C:$flagC)';
}

class MyData implements BincodeCodable {
  int myU8 = 0;
  int myU16 = 0;
  int myU32 = 0;
  int myU64 = 0;
  int myI8 = 0;
  int myI16 = 0;
  int myI32 = 0;
  int myI64 = 0;
  double myF32 = 0.0;
  double myF64 = 0.0;
  bool myBool = false;
  String myChar = '';

  int? myOptionU8;
  int? myOptionU16;
  int? myOptionU32;
  int? myOptionU64;
  int? myOptionI8;
  int? myOptionI16;
  int? myOptionI32;
  int? myOptionI64;
  double? myOptionF32;
  double? myOptionF64;
  bool? myOptionBool;
  String? myOptionChar;

  String myString = "";
  String myFixedString = "";
  String myCleanFixedString = "";
  String? myOptionString;
  String? myOptionFixedString;
  String? myCleanOptionFixedString;

  List<int> myGenericList = [];
  Map<String, bool> myGenericMap = {};
  List<int> myFixedU16Array = [];
  Set<String> myStringSet = {};

  List<int> myInt8List = [];
  List<int> myInt16List = [];
  List<int> myInt32List = [];
  List<int> myInt64List = [];
  List<int> myUint8List = [];
  List<int> myUint16List = [];
  List<int> myUint32List = [];
  List<int> myUint64List = [];
  List<double> myFloat32List = [];
  List<double> myFloat64List = [];

  NestedData myNestedCollection = NestedData();
  NestedData? myOptionalNestedCollection;
  FixedStruct myFixedStructInstance = FixedStruct();
  FixedStruct? myOptionalFixedStructInstance;
  List<FixedStruct> myListOfFixedStructs = [];

  int myEnumDiscriminant = 0;
  int? myOptionEnumDiscriminant;
  Duration myDuration = Duration.zero;
  Duration? myOptionDuration;

  @override
  void encode(BincodeWriter writer) {
    writer.writeU8(myU8);
    writer.writeU16(myU16);
    writer.writeU32(myU32);
    writer.writeU64(myU64);
    writer.writeI8(myI8);
    writer.writeI16(myI16);
    writer.writeI32(myI32);
    writer.writeI64(myI64);
    writer.writeF32(myF32);
    writer.writeF64(myF64);
    writer.writeBool(myBool);
    writer.writeChar(myChar);
    writer.writeOptionU8(myOptionU8);
    writer.writeOptionU16(myOptionU16);
    writer.writeOptionU32(myOptionU32);
    writer.writeOptionU64(myOptionU64);
    writer.writeOptionI8(myOptionI8);
    writer.writeOptionI16(myOptionI16);
    writer.writeOptionI32(myOptionI32);
    writer.writeOptionI64(myOptionI64);
    writer.writeOptionF32(myOptionF32);
    writer.writeOptionF64(myOptionF64);
    writer.writeOptionBool(myOptionBool);
    writer.writeOptionChar(myOptionChar);
    writer.writeString(myString);
    writer.writeFixedString(myFixedString, 32);
    writer.writeFixedString(myCleanFixedString, 16);
    writer.writeOptionString(myOptionString);
    writer.writeOptionFixedString(myOptionFixedString, 20);
    writer.writeOptionFixedString(myCleanOptionFixedString, 24);
    writer.writeList<int>(myGenericList, (v) => writer.writeU32(v));
    writer.writeMap<String, bool>(
        myGenericMap, (k) => writer.writeString(k), (v) => writer.writeBool(v));
    writer.writeFixedArray<int>(myFixedU16Array, 3, writer.writeU16);
    writer.writeSet<String>(myStringSet, writer.writeString);
    writer.writeInt8List(myInt8List);
    writer.writeInt16List(myInt16List);
    writer.writeInt32List(myInt32List);
    writer.writeInt64List(myInt64List);
    writer.writeUint8List(myUint8List);
    writer.writeUint16List(myUint16List);
    writer.writeUint32List(myUint32List);
    writer.writeUint64List(myUint64List);
    writer.writeFloat32List(myFloat32List);
    writer.writeFloat64List(myFloat64List);
    writer.writeNestedValueForCollection(myNestedCollection);
    writer.writeOptionNestedValueForCollection(myOptionalNestedCollection);
    writer.writeNestedValueForFixed(myFixedStructInstance);
    writer.writeOptionNestedValueForFixed(myOptionalFixedStructInstance);
    writer.writeList<FixedStruct>(
        myListOfFixedStructs, (item) => writer.writeNestedValueForFixed(item));
    writer.writeEnumDiscriminant(myEnumDiscriminant);
    writer.writeOptionEnumDiscriminant(myOptionEnumDiscriminant);
    writer.writeDuration(myDuration);
    writer.writeOptionDuration(myOptionDuration);
  }

  @override
  void decode(BincodeReader reader) {
    myU8 = reader.readU8();
    myU16 = reader.readU16();
    myU32 = reader.readU32();
    myU64 = reader.readU64();
    myI8 = reader.readI8();
    myI16 = reader.readI16();
    myI32 = reader.readI32();
    myI64 = reader.readI64();
    myF32 = reader.readF32();
    myF64 = reader.readF64();
    myBool = reader.readBool();
    myChar = reader.readChar();
    myOptionU8 = reader.readOptionU8();
    myOptionU16 = reader.readOptionU16();
    myOptionU32 = reader.readOptionU32();
    myOptionU64 = reader.readOptionU64();
    myOptionI8 = reader.readOptionI8();
    myOptionI16 = reader.readOptionI16();
    myOptionI32 = reader.readOptionI32();
    myOptionI64 = reader.readOptionI64();
    myOptionF32 = reader.readOptionF32();
    myOptionF64 = reader.readOptionF64();
    myOptionBool = reader.readOptionBool();
    myOptionChar = reader.readOptionChar();
    myString = reader.readString();
    myFixedString = reader.readFixedString(32);
    myCleanFixedString = reader.readCleanFixedString(16);
    myOptionString = reader.readOptionString();
    myOptionFixedString = reader.readOptionFixedString(20);
    myCleanOptionFixedString = reader.readCleanOptionFixedString(24);
    myGenericList = reader.readList<int>(() => reader.readU32());
    myGenericMap = reader.readMap<String, bool>(
        () => reader.readString(), () => reader.readBool());
    myFixedU16Array = reader.readFixedArray<int>(3, reader.readU16);
    myStringSet = reader.readSet<String>(reader.readString);
    myInt8List = reader.readInt8List();
    myInt16List = reader.readInt16List();
    myInt32List = reader.readInt32List();
    myInt64List = reader.readInt64List();
    myUint8List = reader.readUint8List();
    myUint16List = reader.readUint16List();
    myUint32List = reader.readUint32List();
    myUint64List = reader.readUint64List();
    myFloat32List = reader.readFloat32List();
    myFloat64List = reader.readFloat64List();
    myNestedCollection =
        reader.readNestedObjectForCollection<NestedData>(NestedData());
    myOptionalNestedCollection = reader
        .readOptionNestedObjectForCollection<NestedData>(() => NestedData());
    myFixedStructInstance =
        reader.readNestedObjectForFixed<FixedStruct>(FixedStruct());
    myOptionalFixedStructInstance =
        reader.readOptionNestedObjectForFixed<FixedStruct>(() => FixedStruct());
    myListOfFixedStructs = reader.readList<FixedStruct>(
        () => reader.readNestedObjectForFixed<FixedStruct>(FixedStruct()));
    myEnumDiscriminant = reader.readEnumDiscriminant();
    myOptionEnumDiscriminant = reader.readOptionEnumDiscriminant();
    myDuration = reader.readDuration();
    myOptionDuration = reader.readOptionDuration();
  }

  @override
  String toString() {
    return """
MyData {
  Primitives: u8=$myU8, u16=$myU16, u32=$myU32, u64=$myU64, i8=$myI8, i16=$myI16, i32=$myI32, i64=$myI64, f32=$myF32, f64=$myF64, bool=$myBool, char='$myChar',
  Optionals: optU8=$myOptionU8, optU16=$myOptionU16, optU32=$myOptionU32, optU64=$myOptionU64, optI8=$myOptionI8, optI16=$myOptionI16, optI32=$myOptionI32, optI64=$myOptionI64, optF32=$myOptionF32, optF64=$myOptionF64, optBool=$myOptionBool, optChar=$myOptionChar,
  Strings: str="$myString", fixedStr="$myFixedString", cleanFixedStr="$myCleanFixedString", optStr=$myOptionString, optFixedStr=$myOptionFixedString, optCleanFixedStr=$myCleanOptionFixedString,
  Collections: genericList=$myGenericList, genericMap=$myGenericMap, fixedU16Array=$myFixedU16Array, stringSet=$myStringSet,
  NumericLists: i8=[${myInt8List.length}], i16=[${myInt16List.length}], i32=[${myInt32List.length}], i64=[${myInt64List.length}], u8=[${myUint8List.length}], u16=[${myUint16List.length}], u32=[${myUint32List.length}], u64=[${myUint64List.length}], f32=[${myFloat32List.length}], f64=[${myFloat64List.length}],
  NestedDynamic: nestedCollection=$myNestedCollection, optNestedCollection=$myOptionalNestedCollection,
  NestedFixed: fixedStructInstance=$myFixedStructInstance, optFixedStructInstance=$myOptionalFixedStructInstance,
  ListOfFixed: [${myListOfFixedStructs.length} items],
  Custom/Enum: enumDiscriminant=$myEnumDiscriminant, optEnumDiscriminant=$myOptionEnumDiscriminant, duration=$myDuration, optDuration=$myOptionDuration
}
""";
  }
}

void main() {
  final listEquality = ListEquality();
  final setEquality = SetEquality();
  final mapEquality = MapEquality();

  final originalData = MyData()
    ..myU8 = 250
    ..myU16 = 65000
    ..myU32 = 4000000000
    ..myU64 = 0xFEDCBA9876543210
    ..myI8 = -100
    ..myI16 = -30000
    ..myI32 = -2000000000
    ..myI64 = -0x7EDCBA9876543210
    ..myF32 = 1.234567e-20
    ..myF64 = -9.87654321e30
    ..myBool = true
    ..myChar = '€'
    ..myOptionU8 = 123
    ..myOptionI16 = null
    ..myOptionF64 = 1.0
    ..myOptionBool = false
    ..myOptionChar = null
    ..myString = "Test String with Unicode 😊"
    ..myFixedString = "Fixed Len"
    ..myCleanFixedString = "Padded\x00\x00"
    ..myOptionString = null
    ..myOptionFixedString = "OptionalFixed"
    ..myCleanOptionFixedString = "Clean\x00Opt\x00Fixed"
    ..myGenericList = [11, 22, 33]
    ..myGenericMap = {"active": true, "ready": false}
    ..myFixedU16Array = [500, 600, 700]
    ..myStringSet = {'apple', 'orange'}
    ..myInt8List = [-10, 0, 10]
    ..myInt32List = Int32List.fromList([-100, 0, 100, 200])
    ..myUint8List = Uint8List.fromList([1, 2, 3, 4, 5])
    ..myFloat64List = [0.1, 0.2, 0.3]
    ..myNestedCollection = NestedData.create(55, "Dynamic Nested Example")
    ..myOptionalNestedCollection = null
    ..myFixedStructInstance = FixedStruct.create(123, -456.789, true)
    ..myOptionalFixedStructInstance = FixedStruct.create(9, 8.0, false)
    ..myListOfFixedStructs = [
      FixedStruct.create(1, 1.0, false),
      FixedStruct.create(2, 2.0, true),
    ]
    ..myEnumDiscriminant = 2
    ..myOptionEnumDiscriminant = 0
    ..myDuration = Duration(minutes: -90, seconds: 15, milliseconds: 500)
    ..myOptionDuration = Duration(days: 1, hours: 1);

  print("Original Data: $originalData");
  final writer = BincodeWriter();
  originalData.encode(writer);
  final raw = writer.toBytes();
  print("\nSerialized ${raw.length} bytes: ${BincodeWriter.toHex(raw)}");

  final reader = BincodeReader(raw);
  final decodedData = MyData()..decode(reader);
  print("\nDecoded Data: $decodedData");

  print("\nRemaining bytes after decode: ${reader.remainingBytes}");
  assert(reader.remainingBytes == 0, "Reader did not consume all bytes!");

  print("\nVerification Start:");

  assert(decodedData.myU8 == originalData.myU8, 'myU8 mismatch');
  assert(decodedData.myU16 == originalData.myU16, 'myU16 mismatch');
  assert(decodedData.myU32 == originalData.myU32, 'myU32 mismatch');
  assert(decodedData.myU64 == originalData.myU64, 'myU64 mismatch');
  assert(decodedData.myI8 == originalData.myI8, 'myI8 mismatch');
  assert(decodedData.myI16 == originalData.myI16, 'myI16 mismatch');
  assert(decodedData.myI32 == originalData.myI32, 'myI32 mismatch');
  assert(decodedData.myI64 == originalData.myI64, 'myI64 mismatch');
  assert(
      (decodedData.myF32 - originalData.myF32).abs() < 1e-25, 'myF32 mismatch');
  assert(
      (decodedData.myF64 - originalData.myF64).abs() < 1e-15, 'myF64 mismatch');
  assert(decodedData.myBool == originalData.myBool, 'myBool mismatch');
  assert(decodedData.myChar == originalData.myChar, 'myChar mismatch');

  assert(
      decodedData.myOptionU8 == originalData.myOptionU8, 'myOptionU8 mismatch');
  assert(decodedData.myOptionI16 == originalData.myOptionI16,
      'myOptionI16 mismatch');
  assert(decodedData.myOptionF64 == originalData.myOptionF64,
      'myOptionF64 mismatch');
  assert(decodedData.myOptionBool == originalData.myOptionBool,
      'myOptionBool mismatch');
  assert(decodedData.myOptionChar == originalData.myOptionChar,
      'myOptionChar mismatch');

  assert(decodedData.myString == originalData.myString, 'myString mismatch');
  assert(decodedData.myFixedString.startsWith("Fixed Len"),
      'myFixedString mismatch');
  assert(decodedData.myCleanFixedString == "Padded",
      'myCleanFixedString mismatch');
  assert(decodedData.myOptionString == originalData.myOptionString,
      'myOptionString mismatch');
  assert(
      decodedData.myOptionFixedString?.replaceAll('\x00', '') ==
          originalData.myOptionFixedString,
      'myOptionFixedString content mismatch');
  assert(decodedData.myCleanOptionFixedString == "CleanOptFixed",
      'myCleanOptionFixedString mismatch');

  assert(
      listEquality.equals(
          decodedData.myGenericList, originalData.myGenericList),
      'myGenericList mismatch');
  assert(
      mapEquality.equals(decodedData.myGenericMap, originalData.myGenericMap),
      'myGenericMap mismatch');
  assert(
      listEquality.equals(
          decodedData.myFixedU16Array, originalData.myFixedU16Array),
      'myFixedU16Array mismatch');
  assert(setEquality.equals(decodedData.myStringSet, originalData.myStringSet),
      'myStringSet mismatch');

  assert(listEquality.equals(decodedData.myInt8List, originalData.myInt8List),
      'myInt8List mismatch');
  assert(listEquality.equals(decodedData.myInt32List, originalData.myInt32List),
      'myInt32List mismatch');
  assert(listEquality.equals(decodedData.myUint8List, originalData.myUint8List),
      'myUint8List mismatch');
  assert(
      listEquality.equals(
          decodedData.myFloat64List, originalData.myFloat64List),
      'myFloat64List mismatch');

  assert(decodedData.myNestedCollection == originalData.myNestedCollection,
      'myNestedCollection mismatch');
  assert(
      decodedData.myOptionalNestedCollection ==
          originalData.myOptionalNestedCollection,
      'myOptionalNestedCollection mismatch');
  assert(
      decodedData.myFixedStructInstance == originalData.myFixedStructInstance,
      'myFixedStructInstance mismatch');
  assert(
      decodedData.myOptionalFixedStructInstance ==
          originalData.myOptionalFixedStructInstance,
      'myOptionalFixedStructInstance mismatch');
  assert(
      listEquality.equals(
          decodedData.myListOfFixedStructs, originalData.myListOfFixedStructs),
      'myListOfFixedStructs mismatch');

  assert(decodedData.myEnumDiscriminant == originalData.myEnumDiscriminant,
      'myEnumDiscriminant mismatch');
  assert(
      decodedData.myOptionEnumDiscriminant ==
          originalData.myOptionEnumDiscriminant,
      'myOptionEnumDiscriminant mismatch');
  assert(
      decodedData.myDuration == originalData.myDuration, 'myDuration mismatch');
  assert(decodedData.myOptionDuration == originalData.myOptionDuration,
      'myOptionDuration mismatch');

  print("\nVerification successful!");
}
0
likes
160
points
58
downloads

Publisher

unverified uploader

Weekly Downloads

A performant Dart implementation of the Bincode binary serialization format. Requires manual implementation for encoding/decoding custom types.

Repository (GitHub)
View/report issues

Topics

#serialization #bincode #binary #dart

Documentation

Documentation
API reference

License

MIT (license)

More

Packages that depend on d_bincode