bufferAdded by Luau 0.601.
LuauAdded by Luwu: buffer.unpack*, buffer.pack*, buffer.memcmp, buffer.isfrozen
Changed by Luwu: buffer.write*, buffer.writestring, buffer.writebits, buffer.writeinteger, buffer.pack*, buffer.copy, buffer.fill
Luwu
buffer.unpack*, buffer.pack*, buffer.memcmp, buffer.isfrozenbuffer.write*, buffer.writestring, buffer.writebits, buffer.writeinteger, buffer.pack*, buffer.copy, buffer.fillA buffer is a fixed-size block of mutable memory. Scripts use buffers to build and parse binary formats like files and network packets, and to store large arrays of numbers in less memory than a table needs.
An external buffer is a buffer whose backing memory is actually owned by the embedder. External buffers can be modified just like buffers owned by the Luwu VM.
A frozen buffer can only be created by embedders and is immutable. Attempting to write to a frozen buffer raises a runtime error; use buffer.isfrozen to check if a buffer is frozen or not.
Most buffer library functions take an offset of bytes from the start of the buffer. Offsets, counts and sizes should be whole non-negative numbers. Offsets starts at byte 0. A read or write outside the buffer throws buffer access out of bounds. Multi-byte values are stored in little endian byte order on every platform.
Summary
Creating and converting
function buffer.create(size: number): bufferbuffer.createAdded by Luau 0.601.
Luau- Creates a zero-filled buffer of a given size
function buffer.fromstring(str: string): bufferbuffer.fromstringAdded by Luau 0.601.
Luau- Creates a buffer holding a copy of a string's bytes
function buffer.tostring(b: buffer): stringbuffer.tostringAdded by Luau 0.601.
Luau- Returns a string holding a copy of a buffer's bytes
function buffer.len(b: buffer): numberbuffer.lenAdded by Luau 0.601.
Luau- Returns the size of a buffer in bytes
Reading and writing numbers
function buffer.readi8(b: buffer, offset: number): number function buffer.readu8(b: buffer, offset: number): number function buffer.readi16(b: buffer, offset: number): number function buffer.readu16(b: buffer, offset: number): number function buffer.readi32(b: buffer, offset: number): number function buffer.readu32(b: buffer, offset: number): number function buffer.readf32(b: buffer, offset: number): number function buffer.readf64(b: buffer, offset: number): numberbuffer.read*Added by Luau 0.601.
Luau- Reads the number at an offset as the type the suffix names
function buffer.writei8(b: buffer, offset: number, value: number) function buffer.writeu8(b: buffer, offset: number, value: number) function buffer.writei16(b: buffer, offset: number, value: number) function buffer.writeu16(b: buffer, offset: number, value: number) function buffer.writei32(b: buffer, offset: number, value: number) function buffer.writeu32(b: buffer, offset: number, value: number) function buffer.writef32(b: buffer, offset: number, value: number) function buffer.writef64(b: buffer, offset: number, value: number)buffer.write*Added by Luau 0.601.
LuauChanged by Luwu: Errors on a frozen buffer.
Luwu- Writes a number at an offset as the type the suffix names
Strings
function buffer.readstring(b: buffer, offset: number, count: number): stringbuffer.readstringAdded by Luau 0.601.
Luau- Returns a string of the bytes starting at an offset
function buffer.writestring(b: buffer, offset: number, value: string, count: number?)buffer.writestringAdded by Luau 0.601.
LuauChanged by Luwu: Errors on a frozen buffer.
Luwu- Writes a string's bytes at an offset
Bits
function buffer.readbits(b: buffer, bit_offset: number, bit_count: number): numberbuffer.readbitsAdded by Luau 0.656.
Luau- Reads up to 32 bits at a bit offset as an unsigned integer
function buffer.writebits(b: buffer, bit_offset: number, bit_count: number, value: number)buffer.writebitsAdded by Luau 0.656.
LuauChanged by Luwu: Errors on a frozen buffer.
Luwu- Writes the low bits of a value at a bit offset
Integers
function buffer.readinteger(b: buffer, offset: number): integerbuffer.readintegerAdded by Luau 0.715.
Luau- Reads 8 bytes at an offset as a signed 64-bit integer
function buffer.writeinteger(b: buffer, offset: number, value: integer)buffer.writeintegerAdded by Luau 0.715.
LuauChanged by Luwu: Errors on a frozen buffer.
Luwu- Writes an integer as a signed 64-bit value at an offset
Batched reads and writes
function buffer.unpacki8(b: buffer, offset: number, count: number): ...number function buffer.unpacku8(b: buffer, offset: number, count: number): ...number function buffer.unpacki16(b: buffer, offset: number, count: number): ...number function buffer.unpacku16(b: buffer, offset: number, count: number): ...number function buffer.unpacki32(b: buffer, offset: number, count: number): ...number function buffer.unpacku32(b: buffer, offset: number, count: number): ...number function buffer.unpackf32(b: buffer, offset: number, count: number): ...number function buffer.unpackf64(b: buffer, offset: number, count: number): ...numberbuffer.unpack*Added by Luwu.
LuwuAvailable in luwu/integration and gated by an FFlag. We anticipate this feature to be released and enabled by default in 0.1.0.
Needs the
flaggedLuwuBufferBatchedFFlag.- Reads several consecutive values of one type in one call
function buffer.packi8(b: buffer, offset: number, ...: number) function buffer.packu8(b: buffer, offset: number, ...: number) function buffer.packi16(b: buffer, offset: number, ...: number) function buffer.packu16(b: buffer, offset: number, ...: number) function buffer.packi32(b: buffer, offset: number, ...: number) function buffer.packu32(b: buffer, offset: number, ...: number) function buffer.packf32(b: buffer, offset: number, ...: number) function buffer.packf64(b: buffer, offset: number, ...: number)buffer.pack*Added by Luwu.
Changed by Luwu: Errors on a frozen buffer.
LuwuAvailable in luwu/integration and gated by an FFlag. We anticipate this feature to be released and enabled by default in 0.1.0.
Needs the
flaggedLuwuBufferBatchedFFlag.- Writes several values of one type one after another
Copying and comparing
function buffer.copy( target: buffer, target_offset: number, source: buffer, source_offset: number?, count: number? )buffer.copyAdded by Luau 0.601.
LuauChanged by Luwu: Errors on a frozen buffer.
Luwu- Copies bytes from one buffer into another
function buffer.fill(b: buffer, offset: number, value: number, count: number?)buffer.fillAdded by Luau 0.601.
LuauChanged by Luwu: Errors on a frozen buffer.
Luwu- Sets a range of bytes to one value
function buffer.memcmp( b1: buffer, b2: buffer, offset1: number?, offset2: number?, count: number? ): numberbuffer.memcmpAdded by Luwu.
LuwuAvailable in luwu/integration and gated by an FFlag. We anticipate this feature to be released and enabled by default in 0.1.0.
Needs the
flaggedLuwuBufferMemcmpFFlag.- Compares the bytes of two buffers
Frozen buffers
function buffer.isfrozen(b: buffer): booleanbuffer.isfrozenAdded by Luwu.
LuwuAvailable in luwu/integration and gated by an FFlag. We anticipate this feature to be released and enabled by default in 0.1.0.
Needs the
flaggedLuwuBufferIsFrozenFFlag.- Checks whether a buffer is a read-only external buffer
Creating and converting
buffer.createAdded by Luau 0.601.
Luau
function buffer.create(size: number): bufferCreates a buffer of size bytes with every byte set to 0. The size limit is 1 GiB (1,073,741,824 bytes) and a negative size is an error.
const packet = buffer.create(4)
buffer.writeu16(packet, 0, 513)
print(buffer.readu8(packet, 0))
print(buffer.readu8(packet, 1))
print(buffer.len(packet))1 2 4
513 is 0x0201. Little endian order puts its low byte first.
buffer.fromstringAdded by Luau 0.601.
Luau
function buffer.fromstring(str: string): bufferCreates a buffer that holds a copy of the bytes of str. Its size is the string's length in bytes.
buffer.tostringAdded by Luau 0.601.
Luau
function buffer.tostring(b: buffer): stringReturns a string holding a copy of every byte in the buffer.
buffer.lenAdded by Luau 0.601.
Luau
function buffer.len(b: buffer): numberReturns the size of the buffer in bytes.
Reading and writing numbers
buffer.read*Added by Luau 0.601.
Luau
function buffer.readi8(b: buffer, offset: number): number
function buffer.readu8(b: buffer, offset: number): number
function buffer.readi16(b: buffer, offset: number): number
function buffer.readu16(b: buffer, offset: number): number
function buffer.readi32(b: buffer, offset: number): number
function buffer.readu32(b: buffer, offset: number): number
function buffer.readf32(b: buffer, offset: number): number
function buffer.readf64(b: buffer, offset: number): numberReads the bytes at offset as the type the suffix names and returns them as a number. Integers use two's complement and floating-point numbers use IEEE 754:
| Suffix | Type | Range |
|---|---|---|
i8 | signed 8-bit integer | -128 to 127 |
u8 | unsigned 8-bit integer | 0 to 255 |
i16 | signed 16-bit integer | -32,768 to 32,767 |
u16 | unsigned 16-bit integer | 0 to 65,535 |
i32 | signed 32-bit integer | -2,147,483,648 to 2,147,483,647 |
u32 | unsigned 32-bit integer | 0 to 4,294,967,295 |
f32 | 32-bit floating-point number | single-precision IEEE 754 |
f64 | 64-bit floating-point number | double-precision IEEE 754 |
A floating-point value whose bits are a NaN may come back as a different quiet NaN.
buffer.write*Added by Luau 0.601.
LuauChanged by Luwu: Errors on a frozen buffer.
Luwu
function buffer.writei8(b: buffer, offset: number, value: number)
function buffer.writeu8(b: buffer, offset: number, value: number)
function buffer.writei16(b: buffer, offset: number, value: number)
function buffer.writeu16(b: buffer, offset: number, value: number)
function buffer.writei32(b: buffer, offset: number, value: number)
function buffer.writeu32(b: buffer, offset: number, value: number)
function buffer.writef32(b: buffer, offset: number, value: number)
function buffer.writef64(b: buffer, offset: number, value: number)Converts value to the type the suffix names and writes its bytes at offset. The ranges are in the table under buffer.read*.
Integer writes convert the number by the same rules as the bit32 library. A value out of range keeps only its low bits: writing 43,981 (0xabcd) with writei8 stores 0xcd and reads back as -51. Converting infinity or NaN to an integer gives a platform-specific result.
const bytes = buffer.create(1)
buffer.writei8(bytes, 0, 0xabcd)
print(buffer.readi8(bytes, 0))
print(buffer.readu8(bytes, 0))-51 205
Strings
buffer.readstringAdded by Luau 0.601.
Luau
function buffer.readstring(b: buffer, offset: number, count: number): stringReturns a string of the count bytes starting at offset.
buffer.writestringAdded by Luau 0.601.
LuauChanged by Luwu: Errors on a frozen buffer.
Luwu
function buffer.writestring(b: buffer, offset: number, value: string, count: number?)Writes the bytes of value at offset. When count is given, only the first count bytes are written. A count larger than the string's length throws string length overflow.
const header = buffer.create(8)
buffer.writestring(header, 0, "LUWU")
buffer.writestring(header, 4, "v1.0", 2)
print(buffer.readstring(header, 0, 6))LUWUv1
Bits
buffer.readbitsAdded by Luau 0.656.
Luau
function buffer.readbits(b: buffer, bit_offset: number, bit_count: number): numberReads bit_count bits starting at bit bit_offset and returns them as an unsigned integer. Bit 0 is the lowest bit of the first byte. bit_count must be between 0 and 32.
buffer.writebitsAdded by Luau 0.656.
LuauChanged by Luwu: Errors on a frozen buffer.
Luwu
function buffer.writebits(b: buffer, bit_offset: number, bit_count: number, value: number)Writes the low bit_count bits of value starting at bit bit_offset. The bits around them don't change. bit_count must be between 0 and 32.
const flags = buffer.create(1)
buffer.writebits(flags, 2, 3, 0b101)
print(buffer.readu8(flags, 0))
print(buffer.readbits(flags, 2, 3))20 5
Integers
buffer.readintegerAdded by Luau 0.715.
Luau
function buffer.readinteger(b: buffer, offset: number): integerReads the 8 bytes at offset as a signed 64-bit integer and returns it as an integer.
The type checker only declares it when LuauIntegerType2 is on as well.
buffer.writeintegerAdded by Luau 0.715.
LuauChanged by Luwu: Errors on a frozen buffer.
Luwu
function buffer.writeinteger(b: buffer, offset: number, value: integer)Writes value as a signed 64-bit integer to the 8 bytes at offset. It takes an integer and a number is an error.
const ids = buffer.create(8)
buffer.writeinteger(ids, 0, integer.maxsigned)
print(buffer.readinteger(ids, 0) == integer.maxsigned) --> trueThe type checker only declares it when LuauIntegerType2 is on as well.
Batched reads and writes
buffer.unpack*Added by Luwu.
LuwuAvailable in luwu/integration and gated by an FFlag. We anticipate this feature to be released and enabled by default in 0.1.0.
Needs the LuwuBufferBatched FFlag.
flagged
LuwuBufferBatched FFlag.function buffer.unpacki8(b: buffer, offset: number, count: number): ...number
function buffer.unpacku8(b: buffer, offset: number, count: number): ...number
function buffer.unpacki16(b: buffer, offset: number, count: number): ...number
function buffer.unpacku16(b: buffer, offset: number, count: number): ...number
function buffer.unpacki32(b: buffer, offset: number, count: number): ...number
function buffer.unpacku32(b: buffer, offset: number, count: number): ...number
function buffer.unpackf32(b: buffer, offset: number, count: number): ...number
function buffer.unpackf64(b: buffer, offset: number, count: number): ...numberReads count consecutive values of the type the suffix names, starting at offset, and returns all of them. It is one call where buffer.read* would need one call per value. count must be at least 1.
The whole batch is bounds checked before the first read. A batch that runs past the end of the buffer throws and returns nothing. A batch larger than the VM's stack allows throws too many values to unpack.
When count is a whole number literal from 1 to 4096, the type checker gives the call exactly that many number results. The values can then go straight into a function with a fixed parameter list:
const points = buffer.create(24)
buffer.packf32(points, 0, 1, 2, 3, 4, 5, 6)
const first = vector.create(buffer.unpackf32(points, 0, 3))
const second = vector.create(buffer.unpackf32(points, 12, 3))
print(`{first}`)
print(`{second}`)1, 2, 3 4, 5, 6
buffer.pack*Added by Luwu.
Changed by Luwu: Errors on a frozen buffer.
LuwuAvailable in luwu/integration and gated by an FFlag. We anticipate this feature to be released and enabled by default in 0.1.0.
Needs the LuwuBufferBatched FFlag.
flagged
LuwuBufferBatched FFlag.function buffer.packi8(b: buffer, offset: number, ...: number)
function buffer.packu8(b: buffer, offset: number, ...: number)
function buffer.packi16(b: buffer, offset: number, ...: number)
function buffer.packu16(b: buffer, offset: number, ...: number)
function buffer.packi32(b: buffer, offset: number, ...: number)
function buffer.packu32(b: buffer, offset: number, ...: number)
function buffer.packf32(b: buffer, offset: number, ...: number)
function buffer.packf64(b: buffer, offset: number, ...: number)Writes every value after offset as the type the suffix names, one after another. The number of values sets the batch size, and passing none writes nothing. Each value is converted the way buffer.write* converts it.
Nothing is written unless the whole batch fits in the buffer and every value is a number. A failed call never leaves a half-written batch behind.
Combined with an unpack function, it converts values from one width to another:
const wide = buffer.create(12)
buffer.packu32(wide, 0, 10, 300, 65)
const narrow = buffer.create(3)
buffer.packu8(narrow, 0, buffer.unpacku32(wide, 0, 3))
print(buffer.readu8(narrow, 0))
print(buffer.readu8(narrow, 1))
print(buffer.readu8(narrow, 2))10 44 65
300 doesn't fit in a byte. packu8 writes its low 8 bits, 44.
Copying and comparing
buffer.copyAdded by Luau 0.601.
LuauChanged by Luwu: Errors on a frozen buffer.
Luwu
function buffer.copy(
target: buffer,
target_offset: number,
source: buffer,
source_offset: number?,
count: number?
)Copies count bytes from source at source_offset into target at target_offset. source_offset defaults to 0. When count is omitted, everything from source_offset to the end of source is copied.
source and target can be the same buffer. An overlapping copy behaves as if the source bytes went through a temporary buffer first:
const text = buffer.fromstring("abcdef")
buffer.copy(text, 2, text, 0, 4)
print(buffer.tostring(text))ababcd
buffer.fillAdded by Luau 0.601.
LuauChanged by Luwu: Errors on a frozen buffer.
Luwu
function buffer.fill(b: buffer, offset: number, value: number, count: number?)Sets count bytes starting at offset to value. Only the low 8 bits of value are used. When count is omitted, every byte from offset to the end of the buffer is set.
buffer.memcmpAdded by Luwu.
LuwuAvailable in luwu/integration and gated by an FFlag. We anticipate this feature to be released and enabled by default in 0.1.0.
Needs the LuwuBufferMemcmp FFlag.
flagged
LuwuBufferMemcmp FFlag.function buffer.memcmp(
b1: buffer,
b2: buffer,
offset1: number?,
offset2: number?,
count: number?
): numberCompares count bytes of b1 starting at offset1 with the bytes of b2 starting at offset2. Both offsets default to 0. When count is omitted, it is the smaller of the two remaining lengths.
Bytes compare as unsigned values in order, and the result is always -1, 0 or 1:
- -1 when the first differing byte is smaller in
b1. - 1 when the first differing byte is larger in
b1. - 0 when every compared byte is equal.
It compares without a loop of reads in the script and without turning the buffers into strings first. The ordering also makes it usable as a sort key.
const a = buffer.fromstring("abc")
const b = buffer.fromstring("abd")
const tagged = buffer.fromstring("id:abc")
print(buffer.memcmp(a, b))
print(buffer.memcmp(b, a))
print(buffer.memcmp(a, tagged, 0, 3))-1 1 0
Frozen buffers
buffer.isfrozenAdded by Luwu.
LuwuAvailable in luwu/integration and gated by an FFlag. We anticipate this feature to be released and enabled by default in 0.1.0.
Needs the LuwuBufferIsFrozen FFlag.
flagged
LuwuBufferIsFrozen FFlag.function buffer.isfrozen(b: buffer): booleanReturns true when the buffer is frozen. A frozen buffer is a read-only external buffer that the host created. Every function that writes to it throws buffer is immutable.
Buffers made by buffer.create and buffer.fromstring are never frozen:
const bytes = buffer.create(8)
print(buffer.isfrozen(bytes))false