std/buffer
A Buffer builds bytes from pieces, and a ByteReader reads them back in
order, as binary file formats and network protocols need:
import "std/buffer"
Buffer out = buffer()
write_u16_be(out, 0xCAFE)
write_uleb128(out, 300)
append_str(out, "hi")
bytes message = build(out) // b"\xca\xfe\xac\x02hi"
ByteReader input = reader(message)
u16 tag = read_u16_be(input)?
u64 size = read_uleb128(input)?
bytes rest = read_exact(input, 2)?Building:
| Function | Result |
|---|---|
buffer(), buffer_with_capacity(n) |
an empty buffer; the second has room for n bytes before it grows |
append(buf, data) |
adds bytes |
append_byte(buf, byte) |
adds one byte, from 0 to 255 |
append_str(buf, text) |
adds the UTF-8 bytes of text |
buffer_length(buf) |
how many bytes it holds |
build(buf) |
the bytes so far; the buffer can go on growing |
Numbers of fixed size are written with write_u8, write_i8, and for 16,
32, and 64 bits write_u16_le, write_u16_be, write_i16_le,
write_i16_be, and so on, and floats with write_f32_le, write_f32_be,
write_f64_le, and write_f64_be. _le puts the least significant byte
first (little-endian) and _be the most significant (big-endian, the order
of network protocols). Floats are stored in their IEEE 754 form.
Numbers of variable size take fewer bytes when they are small:
| Function | Form |
|---|---|
write_uleb128(buf, n) |
unsigned LEB128, seven bits a byte, the lowest first |
write_sleb128(buf, n) |
signed LEB128 |
write_quic_varint(buf, n) |
a QUIC variable-length integer (RFC 9000): 1, 2, 4, or 8 bytes, up to QUIC_VARINT_MAX, 2^62 - 1 |
Reading, from reader(data):
| Function | Result |
|---|---|
read_u8(r), read_u16_be(r), ..., read_f64_le(r) |
the number, as written by the matching write_ |
read_uleb128(r), read_sleb128(r), read_quic_varint(r) |
a number of variable size |
read_exact(r, n) |
the next n bytes, shared with the data |
read_until(r, byte) |
the bytes before the next byte, which is read too |
peek(r) |
the next byte, which stays to be read |
remaining(r), at_end(r) |
how many bytes are left, and whether none are |
Each read returns a Result: when the bytes run out it gives an ERROR of
kind "end_of_data" and leaves the position where it was, and a LEB128
number too long for 64 bits gives one of kind "invalid_data".
A Buffer is a Writer and a
ByteReader a Reader, so functions written for those work with them too.