decode method
Decode a buffer produced by encode.
Implementation
Fugue<String> decode(Uint8List bytes) {
final r = _Reader(bytes);
final version = r.u8();
if (version != 1) {
throw FormatException('Unsupported Fugue binary version: $version');
}
final replicaCount = r.varint();
final dict = <String>[
for (var i = 0; i < replicaCount; i++) utf8.decode(r.take(r.varint())),
];
final blockCount = r.varint();
final blocks = <(Dot, Dot, Side, List<String>, List<int>)>[];
for (var i = 0; i < blockCount; i++) {
final startReplica = dict[r.varint()];
final startCounter = r.varint();
final flags = r.u8();
final side = (flags & 1) == 1 ? Side.right : Side.left;
final origin = (flags & 0x80) != 0;
final Dot parent;
if (origin) {
parent = Dot.origin;
} else {
final parentReplica = dict[r.varint()];
final parentCounter = r.varint();
parent = Dot(parentCounter, parentReplica);
}
final text = utf8.decode(r.take(r.varint()));
final elementCount = r.varint();
final values = <String>[
for (final rune in text.runes) String.fromCharCode(rune),
];
// The run is recovered by rune-splitting, which only round-trips when
// every element was a single Unicode scalar (the codec's assumption).
// A multi-rune element (e.g. an emoji grapheme cluster) would split
// into several runes here, silently shifting every later element's dot.
// Cross-check against the stored count to fail loudly instead.
if (values.length != elementCount) {
throw FormatException(
'element count mismatch: block encoded $elementCount elements '
'but decoded ${values.length} runes — values must be single '
'Unicode scalars',
);
}
final delCount = r.varint();
final del = <int>[for (var j = 0; j < delCount * 2; j++) r.varint()];
blocks.add((Dot(startCounter, startReplica), parent, side, values, del));
}
return Fugue.fromRawBlocks<String>(blocks);
}