As long as each individual buffer is written in one thread and read in one thread, multiple
threads can read and write the stream concurrently, "e.g."
while thread "A" reads from buffer "X" of a stream, thread "B" can read from
buffer "Y" of the same stream.
Each buffer is stored as a chain of blocks. When a write exceeds a buffer's current capacity, another block
is allocated and added to the end of the chain. Effectively, expanding the buffer never requires copying the existing
data (unlike, for example, with NativeList<T0>).
All writing to a stream should be completed before the stream is first read. Do not write to a stream after the first read.
Writing is done with Writer, and reading is done with Reader.
An individual reader or writer cannot be used concurrently across threads. Each thread must use its own.
The data written to an individual buffer can be heterogeneous in type, and the data written
to different buffers of a stream can be entirely different in type, number, and order. Just make sure
that the code reading from a particular buffer knows what to expect to read from it.