packStream static method
Emits entries as one sequential pack stream — the streaming counterpart
of pack, for piping straight into an AEAD writer so the plaintext pack
never exists on disk. Bounded memory: one chunk in flight at a time.
Implementation
static Stream<List<int>> packStream(
List<PqPackEntry> entries, {
int chunkSize = 1 << 20,
}) async* {
for (final entry in entries) {
_requireSafeRelativePath(entry.relativePath);
final pathBytes = PqBytes.utf8Bytes(entry.relativePath);
if (pathBytes.length > maxPathBytes) {
throw PqForgeException(
'Pack entry path too long: ${entry.relativePath}',
);
}
final source = File(entry.sourcePath);
final length = await source.length();
yield (BytesBuilder(copy: false)
..add(PqBytes.uint32(pathBytes.length))
..add(pathBytes)
..add(PqBytes.uint64(length)))
.toBytes();
final reader = await source.open();
try {
var remaining = length;
while (remaining > 0) {
final want = remaining < chunkSize ? remaining : chunkSize;
// Fresh buffer per chunk: the consumer may hold it across awaits.
final chunk = Uint8List(want);
var offset = 0;
while (offset < want) {
final n = await reader.readInto(chunk, offset, want);
if (n <= 0) {
throw PqForgeException(
'Short read packing ${entry.relativePath}',
);
}
offset += n;
}
remaining -= want;
yield chunk;
}
} finally {
await reader.close();
}
}
}