byte_span

local byte_span = require 'byte_span'

A span of bytes. In Emilua, they’re used as network buffers.

Plugin authors

This class is intended for network buffers in a proactor-based network API (i.e. true asynchronous IO). A NIC could be writing to this memory region while the program is running. This has the same effect of another thread writing to the same memory region.

If you’re writing state machines, do not construct the state machine on top of the memory region pointed by a byte_span. It’s not safe to store state here as buggy Lua applications could mutate this area in a racy way. Only use the memory region as the result of operations.

A future Emilua release could introduce read-write locks, but as of now I’m unconvinced of their advantages here.

It’s modeled after Golang’s slices. However 1-indexed access is used.

Functions

new(length: integer[, capacity: integer]) → byte_span

Constructor.

When the capacity argument is omitted, it defaults to the specified length.

slice(self[, start: integer, end: integer]) → byte_span

Returns a new byte_span that points to a slice of the same memory region.

The start and end indices are optional; they default to 1 and the byte_span's length respectively.

We can grow a byte_span to its capacity by slicing it again.

Invalid ranges (e.g. start below 1, a byte_span running beyond its capacity, negative indexes, …​) will raise EINVAL.

copy(self, src: byte_span|string) → integer

Copy src into self.

Returns the number of elements copied.

Copying between slices of different lengths is supported (it’ll copy only up to the smaller number of elements). In addition it can handle source and destination spans that share the same underlying memory, handling overlapping spans correctly.

append() → byte_span

function append(self, ...: byte_span|string|nil) -> byte_span (1)
function append(...: byte_span|string|nil) -> byte_span       (2)

Returns a new byte_span by appending trailing arguments into self. If self's capacity is enough to hold all data, the underlying memory is modified in place. Otherwise the returned byte_span will point to newly allocated memory[1].

For the second overload (non-member function), a new byte span is created from scratch.

Functions (string algorithms)

These functions operate in terms of octets/bytes (kinda like an 8-bit ASCII) and have no concept of UTF-8 encoding.

starts_with(self, prefix: string|byte_span) → boolean

Returns whether self begins with prefix.

ends_with(self, suffix: string|byte_span) → boolean

Returns whether self ends with suffix.

find(self, tgt: string|byte_span[, start: integer]) → integer|nil

Finds the first substring equals to tgt and returns its index, or nil if not found.

rfind(self, tgt: string|byte_span[, end_: integer]) → integer|nil

Finds the last substring equals to tgt and returns its index, or nil if not found.

find_first_of(self, strlist: string|byte_span[, start: integer]) → integer|nil

Finds the first octet equals to any of the octets within strlist and returns its index, or nil if not found.

find_last_of(self, strlist: string|byte_span[, end_: integer]) → integer|nil

Finds the last octet equals to any of the octets within strlist and returns its index, or nil if not found.

find_first_not_of(self, strlist: string|byte_span[, start: integer]) → integer|nil

Finds the first octet not equals to any of the octets within strlist and returns its index, or nil if not found.

find_last_not_of(self, strlist: string|byte_span[, end: integer]) → integer|nil

Finds the last octet not equals to any of the octets within strlist and returns its index, or nil if not found.

trimmed(self[, lws: string|byte_span = " \f\n\r\t\v"]) → byte_span

Returns a slice from self that doesn’t start nor ends with any octet from lws.

Functions (primitive types serialization)

These functions operate in terms of bytes, and are endianness-aware. They throw EINVAL if you use a byte_span of the wrong size. Data doesn’t need to be aligned.

get_u16be(self) → integer

Interpret self (must be 2 bytes long) as an unsigned 16-bit integer (big endian order) and return the result.

get_u16le(self) → integer

Interpret self (must be 2 bytes long) as an unsigned 16-bit integer (little endian order) and return the result.

get_u24be(self) → integer

Interpret self (must be 3 bytes long) as an unsigned 24-bit integer (big endian order) and return the result.

get_u24le(self) → integer

Interpret self (must be 3 bytes long) as an unsigned 24-bit integer (little endian order) and return the result.

get_u32be(self) → integer

Interpret self (must be 4 bytes long) as an unsigned 32-bit integer (big endian order) and return the result.

get_u32le(self) → integer

Interpret self (must be 4 bytes long) as an unsigned 32-bit integer (little endian order) and return the result.

get_u40be(self) → integer

Interpret self (must be 5 bytes long) as an unsigned 40-bit integer (big endian order) and return the result.

get_u40le(self) → integer

Interpret self (must be 5 bytes long) as an unsigned 40-bit integer (little endian order) and return the result.

get_u48be(self) → integer

Interpret self (must be 6 bytes long) as an unsigned 48-bit integer (big endian order) and return the result.

get_u48le(self) → integer

Interpret self (must be 6 bytes long) as an unsigned 48-bit integer (little endian order) and return the result.

get_i8(self) → integer

Interpret self (must be 1 byte long) as a signed 8-bit integer and return the result.

get_u8() doesn’t exist as you can just index instead.

get_i16be(self) → integer

Interpret self (must be 2 bytes long) as an signed 16-bit integer (big endian order) and return the result.

get_i16le(self) → integer

Interpret self (must be 2 bytes long) as an signed 16-bit integer (little endian order) and return the result.

get_i24be(self) → integer

Interpret self (must be 3 bytes long) as an signed 24-bit integer (big endian order) and return the result.

get_i24le(self) → integer

Interpret self (must be 3 bytes long) as an signed 24-bit integer (little endian order) and return the result.

get_i32be(self) → integer

Interpret self (must be 4 bytes long) as an signed 32-bit integer (big endian order) and return the result.

get_i32le(self) → integer

Interpret self (must be 4 bytes long) as an signed 32-bit integer (little endian order) and return the result.

get_i40be(self) → integer

Interpret self (must be 5 bytes long) as an signed 40-bit integer (big endian order) and return the result.

get_i40le(self) → integer

Interpret self (must be 5 bytes long) as an signed 40-bit integer (little endian order) and return the result.

get_i48be(self) → integer

Interpret self (must be 6 bytes long) as an signed 48-bit integer (big endian order) and return the result.

get_i48le(self) → integer

Interpret self (must be 6 bytes long) as an signed 48-bit integer (little endian order) and return the result.

get_f32be(self) → number

Interpret self (must be 4 bytes long) as a 32-bit floating point number (big endian order) and return the result.

get_f32le(self) → number

Interpret self (must be 4 bytes long) as a 32-bit floating point number (little endian order) and return the result.

get_f64be(self) → number

Interpret self (must be 8 bytes long) as a 64-bit floating point number (big endian order) and return the result.

get_f64le(self) → number

Interpret self (must be 8 bytes long) as a 64-bit floating point number (little endian order) and return the result.

set_u16be(self, n: integer)

Set the stored byte sequence (must be 2 bytes long) to represent the unsigned 16-bit integer (big endian order) n.

set_u16le(self, n: integer)

Set the stored byte sequence (must be 2 bytes long) to represent the unsigned 16-bit integer (little endian order) n.

set_u24be(self, n: integer)

Set the stored byte sequence (must be 3 bytes long) to represent the unsigned 24-bit integer (big endian order) n.

set_u24le(self, n: integer)

Set the stored byte sequence (must be 3 bytes long) to represent the unsigned 24-bit integer (little endian order) n.

set_u32be(self, n: integer)

Set the stored byte sequence (must be 4 bytes long) to represent the unsigned 32-bit integer (big endian order) n.

set_u32le(self, n: integer)

Set the stored byte sequence (must be 4 bytes long) to represent the unsigned 32-bit integer (little endian order) n.

set_u40be(self, n: integer)

Set the stored byte sequence (must be 5 bytes long) to represent the unsigned 40-bit integer (big endian order) n.

set_u40le(self, n: integer)

Set the stored byte sequence (must be 5 bytes long) to represent the unsigned 40-bit integer (little endian order) n.

set_u48be(self, n: integer)

Set the stored byte sequence (must be 6 bytes long) to represent the unsigned 48-bit integer (big endian order) n.

set_u48le(self, n: integer)

Set the stored byte sequence (must be 6 bytes long) to represent the unsigned 48-bit integer (little endian order) n.

set_i8(self, n: integer)

Set the stored byte sequence (must be 1 bytes long) to represent the signed byte n.

set_u8() doesn’t exist as you can just index instead.

set_i16be(self, n: integer)

Set the stored byte sequence (must be 2 bytes long) to represent the signed 16-bit integer (big endian order) n.

set_i16le(self, n: integer)

Set the stored byte sequence (must be 2 bytes long) to represent the signed 16-bit integer (little endian order) n.

set_i24be(self, n: integer)

Set the stored byte sequence (must be 3 bytes long) to represent the signed 24-bit integer (big endian order) n.

set_i24le(self, n: integer)

Set the stored byte sequence (must be 3 bytes long) to represent the signed 24-bit integer (little endian order) n.

set_i32be(self, n: integer)

Set the stored byte sequence (must be 4 bytes long) to represent the signed 32-bit integer (big endian order) n.

set_i32le(self, n: integer)

Set the stored byte sequence (must be 4 bytes long) to represent the signed 32-bit integer (little endian order) n.

set_i40be(self, n: integer)

Set the stored byte sequence (must be 5 bytes long) to represent the signed 40-bit integer (big endian order) n.

set_i40le(self, n: integer)

Set the stored byte sequence (must be 5 bytes long) to represent the signed 40-bit integer (little endian order) n.

set_i48be(self, n: integer)

Set the stored byte sequence (must be 6 bytes long) to represent the signed 48-bit integer (big endian order) n.

set_i48le(self, n: integer)

Set the stored byte sequence (must be 6 bytes long) to represent the signed 48-bit integer (little endian order) n.

set_f32be(self, n: number)

Set the stored byte sequence (must be 4 bytes long) to represent the 32-bit floating point number (big endian order) n.

set_f32le(self, n: number)

Set the stored byte sequence (must be 4 bytes long) to represent the 32-bit floating point number (little endian order) n.

set_f64be(self, n: number)

Set the stored byte sequence (must be 8 bytes long) to represent the 64-bit floating point number (big endian order) n.

set_f64le(self, n: number)

Set the stored byte sequence (must be 8 bytes long) to represent the 64-bit floating point number (little endian order) n.

Properties

capacity: integer

The capacity.

Metamethods

  • __tostring()

  • __len()

  • __index()

  • __newindex()

  • __eq()

You can index the spans by numerical valued keys and the numerical (ASCII) value for the underlying byte will be returned (or assigned on __newindex()).

1. Allocation strategy (the new byte_span's capacity) is left unspecified and may change among Emilua releases.