diff --git a/lib/src/unpacker.dart b/lib/src/unpacker.dart index cd734c2..f2e2cb8 100644 --- a/lib/src/unpacker.dart +++ b/lib/src/unpacker.dart @@ -197,11 +197,11 @@ class Unpacker { return len; } - /// Unpack value if packed value is binary or `null`. + /// Unpack value as Uint8List if packed value is binary or `null`. /// /// Encoded in msgpack packet null unpacks to [List] with 0 length for convenience. /// Throws [FormatException] if value is not a binary. - List unpackBinary() { + Uint8List unpackBinaryUint8() { final b = _d.getUint8(_offset); int len; if (b == 0xc4) { @@ -222,7 +222,15 @@ class Unpacker { final data = Uint8List.view(_list.buffer, _list.offsetInBytes + _offset, len); _offset += len; - return data.toList(); + return data; + } + + /// Unpack value if packed value is binary or `null`. + /// + /// Encoded in msgpack packet null unpacks to [List] with 0 length for convenience. + /// Throws [FormatException] if value is not a binary. + List unpackBinary() { + return unpackBinaryUint8().toList(); } Object? _unpack() { diff --git a/test/messagepack_test.dart b/test/messagepack_test.dart index 3ab41dd..6980210 100644 --- a/test/messagepack_test.dart +++ b/test/messagepack_test.dart @@ -1,5 +1,6 @@ import 'dart:convert'; import 'dart:math'; +import 'dart:typed_data'; import 'package:messagepack/messagepack.dart'; import 'package:test/test.dart'; @@ -72,6 +73,64 @@ final strs = [ 'hi' ]; +/// Example recursive datastruct and one way to pack/unpack. +class MyData { + MyData(this.data) : children = {}; + MyData._new(this.data, this.children); + + static MyData unpack(Uint8List bytes) { + final u = Unpacker(bytes); + return _unpack(u); + } + + static MyData _unpack(Unpacker u) { + final data = u.unpackInt()!; + final children = {}; + final mapLength = u.unpackMapLength(); + for (var i = 0; i < mapLength; ++i) { + final key = u.unpackInt(); + if (key != null) { + children[key] = _unpack(u); + } + } + return MyData._new(data, children); + } + + Uint8List pack() { + final p = Packer(); + _pack(p); + return p.takeBytes(); + } + + void _pack(Packer p) { + p.packInt(data); + p.packMapLength(children.length); + for (final MapEntry entry in children.entries) { + p.packInt(entry.key); + entry.value._pack(p); + } + } + + void add(int key, MyData child) => children[key] = child; + @override + bool operator ==(Object other) { + if (!(other is MyData) || + other.runtimeType != runtimeType || + other.data != data || + other.children.length != children.length) return false; + for (final item in children.entries) { + if (other.children[item.key] != item.value) return false; + } + return true; + } + + @override + int get hashCode => Object.hash(data, children); + + int data; + Map children; +} + void main() { test('int sequentially increasing [independent]', () { for (int v = -65536; v < 65536; v++) { @@ -329,13 +388,21 @@ void main() { p.packBool(true); p.packBinary(bytes2); p.packInt(3); - final u = Unpacker(p.takeBytes()); + final packedBytes = p.takeBytes(); + final u = Unpacker(packedBytes); expect(u.unpackBinary(), equals(empty)); expect(u.unpackBinary(), equals(empty)); expect(u.unpackBinary(), equals(bytes1)); expect(u.unpackBool(), equals(true)); expect(u.unpackBinary(), equals(bytes2)); expect(u.unpackInt(), equals(3)); + final u2 = Unpacker(packedBytes); + expect(u2.unpackBinaryUint8(), equals(empty)); + expect(u2.unpackBinaryUint8(), equals(empty)); + expect(u2.unpackBinaryUint8(), equals(bytes1)); + expect(u2.unpackBool(), equals(true)); + expect(u2.unpackBinaryUint8(), equals(bytes2)); + expect(u2.unpackInt(), equals(3)); }); test('Manual int example [dependent]', () { @@ -413,4 +480,22 @@ void main() { final l = u.unpackList(); print(l); }); + + test('Recursive strutures', () { + final myData = MyData(0); + myData.add(11, MyData(1)); + myData.add(12, MyData(2)..add(33, MyData(4))); + myData.add(13, MyData(3)); + final bytes = myData.pack(); + print('encoded length: ${bytes.lengthInBytes}'); + + final unpackedData = MyData.unpack(bytes); + expect(myData.data, unpackedData.data); + final otherChildren = unpackedData.children; + expect(otherChildren, containsPair(11, MyData(1))); + expect(otherChildren, containsPair(12, MyData(2)..add(33, MyData(4)))); + expect(otherChildren, containsPair(13, MyData(3))); + expect(myData.children.length, otherChildren.length); + expect(myData, equals(unpackedData)); + }); }