Skip to content

buffer

The complete buffer library: fixed-size mutable byte arrays, separate from strings (which are immutable in Luau). Ideal for binary structure parsing and packing.

Allocates a zero-filled buffer of size bytes.

local b = buffer.create(8)
print(buffer.len(b)) --> 8

Size in bytes.

print(buffer.len(buffer.create(64))) --> 64

Wraps a string’s bytes as a buffer (copies).

local b = buffer.fromstring("po")
print(buffer.readu8(b, 0)) --> 112 ('p')

Copies the buffer into a string.

local s = buffer.tostring(buffer.fromstring("still bytes"))
print(s) --> still bytes

Writes value (a byte) into size bytes starting at offset.

local b = buffer.create(4)
buffer.fill(b, 0, 4, 0xFF)
print(buffer.readu32(b, 0)) --> 4294967295

buffer.copy(dst, dstOffset, src, srcOffset, size)

Section titled “buffer.copy(dst, dstOffset, src, srcOffset, size)”

Copies bytes between buffers (regions may overlap — behaves like memmove).

local a, b = buffer.create(4), buffer.create(4)
buffer.writeu32(a, 0, 400)
buffer.copy(b, 0, a, 0, 4)
print(buffer.readu32(b, 0)) --> 400

All reads take (b, offset); all writes take (b, offset, value). Offsets are in bytes, zero-based. Little-endian.

Signed reads sign-extend; unsigned don’t. f32/f64 are IEEE floats.

buffer.readu8(b, offset) / buffer.writeu8(b, offset, value)

Section titled “buffer.readu8(b, offset) / buffer.writeu8(b, offset, value)”
local b = buffer.create(1)
buffer.writeu8(b, 0, 200)
print(buffer.readu8(b, 0)) --> 200

buffer.readi8(b, offset) / buffer.writei8(b, offset, value)

Section titled “buffer.readi8(b, offset) / buffer.writei8(b, offset, value)”
buffer.writei8(b, 0, -56)
print(buffer.readi8(b, 0)) --> -56

buffer.readu16 / buffer.writeu16, buffer.readi16 / buffer.writei16

Section titled “buffer.readu16 / buffer.writeu16, buffer.readi16 / buffer.writei16”
local b = buffer.create(2)
buffer.writeu16(b, 0, 0xBEEF)
print(buffer.readu16(b, 0)) --> 48879

buffer.readu32 / buffer.writeu32, buffer.readi32 / buffer.writei32

Section titled “buffer.readu32 / buffer.writeu32, buffer.readi32 / buffer.writei32”
local b = buffer.create(4)
buffer.writeu32(b, 0, 400) -- the Portal appid fits
print(buffer.readu32(b, 0)) --> 400
print(buffer.readi32(b, 0)) --> 400
buffer.writeu32(b, 0, 0xFFFFFFFF)
print(buffer.readi32(b, 0)) --> -1 (sign-extended view)

buffer.readf32(b, offset) / buffer.writef32(b, offset, value)

Section titled “buffer.readf32(b, offset) / buffer.writef32(b, offset, value)”

Single precision.

local b = buffer.create(4)
buffer.writef32(b, 0, 0.5)
print(buffer.readf32(b, 0)) --> 0.5

Double precision.

local b = buffer.create(8)
buffer.writef64(b, 0, 1/3)
print(buffer.readf64(b, 0)) --> 0.33333333333333

buffer.readbits(b, bitOffset, width) / buffer.writebits(b, bitOffset, width, value)

Section titled “buffer.readbits(b, bitOffset, width) / buffer.writebits(b, bitOffset, width, value)”

Read/write a width-bit field (1..32) at a bit offset — no byte alignment needed.

local b = buffer.create(1)
buffer.writebits(b, 0, 4, 0b1010) -- low nibble
buffer.writebits(b, 4, 4, 0b0101) -- high nibble
print(buffer.readu8(b, 0)) --> 90 (0x5A)
print(buffer.readbits(b, 0, 4)) --> 10

buffer.readstring(b, offset, count) / buffer.writestring(b, offset, s, count?)

Section titled “buffer.readstring(b, offset, count) / buffer.writestring(b, offset, s, count?)”

writestring copies count bytes (default: full string); readstring reads exactly count bytes as a string.

local b = buffer.create(8)
buffer.writestring(b, 0, "pozo", 4)
print(buffer.readstring(b, 0, 2)) --> po
print(buffer.readstring(b, 2, 2)) --> zo

Buffers shine for binary layouts — say a future engine API needs a fixed-size record:

local function pack_record(id, hp, ratio)
local b = buffer.create(8)
buffer.writeu16(b, 0, id) -- +0: u16 id
buffer.writeu16(b, 2, hp) -- +2: u16 hp
buffer.writef32(b, 4, ratio) -- +4: f32 ratio
return b
end
local rec = pack_record(7, 100, 0.25)
print(buffer.readu16(rec, 2)) --> 100
print(buffer.readf32(rec, 4)) --> 0.25