On this page
  1. tecs.io
  2. Module contents
    1. Submodules
    2. Constructors
    3. Types
    4. Functions
  3. Constructors
    1. newBase64DecodeReader
    2. newBase64EncodeWriter
    3. newBuffer
    4. newByteReader
    5. newByteStream
    6. newDeflateWriter
    7. newEmptyStream
    8. newFileStream
    9. newHandleStream
    10. newHexDecodeReader
    11. newHexEncodeWriter
    12. newInflateReader
    13. newStringReader
    14. newStringStream
    15. newTranscodeReader
    16. newTranscodeWriter
  4. Types
    1. Address
    2. Buffer
    3. ByteView
    4. DeflateWriterOptions
    5. InflateReaderOptions
    6. ReadableStream
    7. Reader
    8. ReadWriteStream
    9. Seekable
    10. SeekableReader
    11. SeekableWriter
    12. Stream
    13. TCPListener
    14. TCPSocket
    15. UDPPacket
    16. UDPSocket
    17. WritableStream
    18. Writer
  5. Functions
    1. bind
    2. connect
    3. init
    4. listen
    5. pending
    6. poll
    7. resolve
    8. shutdown
    9. transfer

tecs.io

Input, output, and nonblocking network transport.

A Stream describes binary storage without keeping a cursor. A Reader and Writer are the caller-owned directional endpoints opened from it. Strings, buffers, borrowed bytes, paths, and handles all use that one descriptor contract.

A Lua FILE is also a basic reader and writer. transfer accepts files directly and uses readInto or writeFrom accelerators when an endpoint provides them. Transform constructors take ownership of either a Tecs endpoint or a file and close it with the wrapper.

Whole-source operations run synchronously and return their result directly. They return nil and a reason when an endpoint cannot be opened, read, written, flushed, or closed:

tecs.scoped(function(scope: tecs.Scope)
    local save <const> = scope:own(tecs.io.newFileStream("save.bin"))
    local bytes <const> = assert(save:transferToBuffer())
    scope:own(bytes)

    print(bytes:length())
end)

TCP is an ordered byte stream: one write may take several reads to receive, several writes may arrive in one read, and message framing belongs to the caller. UDP preserves one send as one datagram, but the network may lose, duplicate, or reorder it. General immutable URIs live under tecs.io.URI; HTTP and HTTPS live under tecs.io.http; the MCP debug server lives under tecs.io.mcp.

Hot TCP loops can reuse a Buffer. TCPSocket:readInto lets the native socket fill its FFI allocation directly, and TCPSocket:writeFrom queues a buffer range without constructing an intermediate Lua string. Buffer:view retains an immutable zero-copy snapshot. writeView on sockets, writers, and writable streams consumes that retained range directly, while ByteView:newStream gives it replayable stream behavior without copying payload bytes.

Transform readers and writers compose those endpoints without materializing a whole source. newInflateReader, newBase64DecodeReader, newHexDecodeReader, and newTranscodeReader pull transformed bytes as their consumer asks. The corresponding deflate, encode, and transcode writers push transformed chunks toward a destination and finish format trailers or partial character state on close. Each wrapper owns the endpoint it wraps. Memory endpoints lend source pointers and reserve destination ranges directly; other endpoints reuse pooled chunks, so a warmed transfer allocates no intermediate payload storage.

Ownership is explicit at construction boundaries. A stream over a buffer or Lua file handle borrows that resource and never closes it. A stream over a byte view retains its own immutable view. Transform readers and writers take ownership of the endpoint they wrap and close it with themselves. Opening a buffer or byte-view reader retains an immutable snapshot that outlives later closure; opening a buffer writer borrows the mutable buffer, clears its logical length, and requires it to remain open through the writer's close.

Resolution and client connection return asynchronous Future values. An Application polls runtime once per iteration, so a game waits on status without driving I/O itself:

local address <const> = tecs.io.resolve("game.example")

local function update()
    if address.status == "ready" then
        print(address.value.text)
    end
end

An Application calls tecs.runtime.poll automatically once per host iteration. Game systems and update functions must not drive either pump. A headless program normally calls tecs.runtime.poll once per manual loop; tecs.io.poll remains the narrower operation for code deliberately driving only generic network futures. A future's bounded wait is available when blocking is the honest operation. Stream transfers already block until their bytes have moved. Listening, accepting, reading, writing, and receiving are nonblocking.

Every address, TCP socket, listener, UDP socket, and UDP packet owns a resource. Close it explicitly. A GC finalizer releases an abandoned network handle as a last resort, but cannot report a close error. Closing is idempotent; using a closed value returns a failure.

Naming tecs.io loads none of its children. Reading files, http, mcp, Path, Process, URI, or watcher loads only that child.

Declares the directional binary interfaces published by tecs.io.

This module is the cycle-safe home of Reader, Writer, and the stream descriptor interfaces. It is not a second public namespace: tecs.io re-exports the contracts, while resource modules require them without requiring their public parent.

Module contents

Submodules

Submodule Description
tecs.io.Path Immutable UTF-8 filesystem paths with platform-native semantics.
tecs.io.Process Streaming child processes with backpressured standard I/O.
tecs.io.URI Immutable absolute URIs with component-aware modification.
tecs.io.files Asset, persistent, and cache paths plus synchronous file operations
tecs.io.http Asynchronous HTTP requests, streaming bodies, connection pools, and ECS request entities
tecs.io.mcp MCP server setup, world inspection, safe mutation, custom tools, and transport
tecs.io.watcher Development-time polling and reload dispatch for loaded content

Constructors

Constructor Description
newBase64DecodeReader Creates a reader that incrementally decodes RFC 4648 Base64 text.
newBase64EncodeWriter Creates a writer that incrementally encodes bytes as RFC 4648 Base64.
newBuffer Creates an owned growable byte buffer.
newByteReader Creates a reader over borrowed FFI memory.
newByteStream Creates a replayable read-only stream over borrowed FFI bytes.
newDeflateWriter Creates a writer that incrementally deflates bytes into a destination.
newEmptyStream Creates a replayable readable empty stream.
newFileStream Creates a replayable file stream.
newHandleStream Creates a one-shot stream over a borrowed Lua file handle.
newHexDecodeReader Creates a reader that incrementally decodes hexadecimal text.
newHexEncodeWriter Creates a writer that incrementally encodes bytes as lowercase hexadecimal text.
newInflateReader Creates a reader that incrementally inflates a compressed source.
newStringReader Creates a reader over an immutable Lua string.
newStringStream Creates a replayable read-only string stream.
newTranscodeReader Creates a reader that incrementally converts character encodings.
newTranscodeWriter Creates a writer that incrementally converts character encodings.

Types

Type Kind Description
Address record An Address owns one resolved network address.
Buffer interface A Buffer is owned growable FFI-backed byte storage.
ByteView interface A ByteView retains an immutable zero-copy range from a buffer.
DeflateWriterOptions record Options control an incremental deflate writer.
InflateReaderOptions record Options control an incremental inflate reader.
ReadableStream interface A ReadableStream opens readers and supplies whole-source transfers.
Reader interface A Reader supplies bytes in order and releases its owned state on close.
ReadWriteStream interface A ReadWriteStream supports both directional interfaces.
Seekable interface Seekable supplies random-access cursor operations shared by readers and writers.
SeekableReader interface A SeekableReader supplies bytes through a repositionable cursor.
SeekableWriter interface A SeekableWriter patches a destination through a repositionable cursor.
Stream interface A Stream describes binary storage without retaining a cursor.
TCPListener record A TCPListener listens for TCP clients.
TCPSocket record A TCPSocket owns one connected TCP byte stream.
UDPPacket record A UDPPacket owns one received UDP datagram and its source address.
UDPSocket record A UDPSocket sends and receives UDP packets.
WritableStream interface A WritableStream opens writers and supplies whole-destination transfers.
Writer interface A Writer accepts bytes in order and finishes its destination on close.

Functions

Function Kind Description
bind Static Binds a UDP socket.
connect Static Begins connecting to a resolved address.
init Static Starts networking for this module.
listen Static Binds a TCP listener.
pending Static Returns the number of pending resolution or connection futures.
poll Static Advances pending I/O in a headless loop without waiting.
resolve Static Begins resolving a hostname.
shutdown Static Stops this module's networking instance.
transfer Static Transfers every remaining byte between directional endpoints.

Constructors

tecs.io.newBase64DecodeReader Static

Creates a reader that incrementally decodes RFC 4648 Base64 text.

The reader owns source and retains at most one undecoded quantum between source reads.

function tecs.io.newBase64DecodeReader(
    source: types.Reader | FILE
): types.Reader

Arguments

Name Type Description
source types.Reader | FILE The caller supplies the reader of Base64 text.

Returns

Type Description
types.Reader Returns a caller-owned reader of decoded bytes.

Examples

tecs.scoped(function(scope: tecs.Scope)
    local reader <const> = scope:own(
        tecs.io.newBase64DecodeReader(
            tecs.io.newStringReader("c25hcHNob3QgYnl0ZXM=")
        )
    )
    local decoded <const>, reason = reader:read(1024)

    assert(decoded, reason)
    assert(decoded == "snapshot bytes")
end)

tecs.io.newBase64EncodeWriter Static

Creates a writer that incrementally encodes bytes as RFC 4648 Base64.

The writer owns destination. close emits padding for the final partial quantum before closing the destination.

function tecs.io.newBase64EncodeWriter(
    destination: types.Writer | FILE
): types.Writer

Arguments

Name Type Description
destination types.Writer | FILE The caller supplies the writer receiving Base64 text.

Returns

Type Description
types.Writer Returns a caller-owned writer that accepts unencoded bytes.

Examples

tecs.scoped(function(scope: tecs.Scope)
    local encoded <const> = scope:own(tecs.io.newBuffer())
    local writer <const> = scope:own(
        tecs.io.newBase64EncodeWriter(encoded:newWriter())
    )

    assert(writer:write("snapshot bytes"))
    assert(writer:close())
    assert(encoded:getString() == "c25hcHNob3QgYnl0ZXM=")
end)

tecs.io.newBuffer Static

Creates an owned growable byte buffer.

function tecs.io.newBuffer(initial: integer | string): IOBuffer

Arguments

Name Type Description
initial integer | string The caller supplies a non-negative zero-filled logical length, a string to copy, or nil for an empty buffer.

Returns

Type Description
IOBuffer Returns a caller-owned buffer.

Examples

local bytes <const> = tecs.io.newBuffer("save data")
print(bytes:length())

bytes:close()

tecs.io.newByteReader Static

Creates a reader over borrowed FFI memory.

The reader never frees or modifies the allocation. The caller keeps its owner reachable and the bytes unchanged until the reader closes.

function tecs.io.newByteReader(
    pointer: loader.CValue, length: integer
): types.Reader

Arguments

Name Type Description
pointer loader.CValue The caller supplies the first readable byte.
length integer The caller supplies the non-negative readable byte count.

Returns

Type Description
types.Reader Returns a caller-owned reader whose cursor starts at zero.

Examples

local ffi <const> = require("ffi")

local bytes <const> = "borrowed bytes"
local pointer <const> = ffi.cast("const uint8_t *", bytes)
local reader <const> = tecs.io.newByteReader(pointer as any, #bytes)

assert(reader:read(1024) == bytes)

reader:close()

tecs.io.newByteStream Static

Creates a replayable read-only stream over borrowed FFI bytes.

Closing the stream or its readers never frees the allocation.

function tecs.io.newByteStream(
    pointer: loader.CValue, length: integer, contentType: string
): types.ReadableStream

Arguments

Name Type Description
pointer loader.CValue The caller keeps the backing allocation alive and unchanged until every reader closes and every transfer returns.
length integer The caller supplies the non-negative byte count.
contentType string The caller supplies optional media type metadata.

Returns

Type Description
types.ReadableStream Returns a readable stream.

Examples

local ffi <const> = require("ffi")

local bytes <const> = "borrowed bytes"
local pointer <const> = ffi.cast("const uint8_t *", bytes)
local source <const> = tecs.io.newByteStream(pointer as any, #bytes)
print(source:readAll())

source:close()

tecs.io.newDeflateWriter Static

Creates a writer that incrementally deflates bytes into a destination.

The writer owns destination. flush emits a synchronization point without ending the compressed stream, and close emits its trailer before closing the destination.

function tecs.io.newDeflateWriter(
    destination: types.Writer | FILE,
    options: types.DeflateWriterOptions
): types.Writer

Arguments

Name Type Description
destination types.Writer | FILE The caller supplies the writer receiving compressed bytes.
options types.DeflateWriterOptions The caller selects raw framing and a compression level or omits it for zlib framing and zlib's default level.

Returns

Type Description
types.Writer Returns a caller-owned writer that accepts uncompressed bytes.

Examples

tecs.scoped(function(scope: tecs.Scope)
    local compressed <const> = scope:own(tecs.io.newBuffer())
    local writer <const> = scope:own(
        tecs.io.newDeflateWriter(compressed:newWriter())
    )

    assert(writer:write("snapshot "))
    assert(writer:write("bytes"))
    assert(writer:close())
    assert(compressed:length() > 0)
end)

tecs.io.newEmptyStream Static

Creates a replayable readable empty stream.

function tecs.io.newEmptyStream(
    contentType: string
): types.ReadableStream

Arguments

Name Type Description
contentType string The caller supplies optional media type metadata.

Returns

Type Description
types.ReadableStream Returns a source whose length is zero.

Examples

local source <const> = tecs.io.newEmptyStream(
    "application/octet-stream"
)
print(source:readAll())

source:close()

tecs.io.newFileStream Static

Creates a replayable file stream.

Readers open the current path through tecs.io.files; writers replace it. A descriptor keeps no open file between endpoints.

function tecs.io.newFileStream(
    path: string | Path, contentType: string
): types.ReadWriteStream

Arguments

Name Type Description
path string | Path The caller supplies the source or destination as a string or Path.
contentType string The caller supplies optional media type metadata.

Returns

Type Description
types.ReadWriteStream Returns a readable and writable stream.

Examples

local path <const> = tecs.io.Path.new("save.bin")
local save <const> = tecs.io.newFileStream(
    path, "application/octet-stream"
)

assert(save:writeAll("save data"))
print(save:readAll())

save:close()

tecs.io.newHandleStream Static

Creates a one-shot stream over a borrowed Lua file handle.

The first reader or writer claims its current cursor. Closing the stream or endpoint does not close the caller's handle.

function tecs.io.newHandleStream(
    handle: FILE, length: integer, contentType: string
): types.ReadWriteStream

Arguments

Name Type Description
handle FILE The caller keeps the Lua file handle open through the endpoint's close.
length integer The caller supplies the remaining byte count when known.
contentType string The caller supplies optional media type metadata.

Returns

Type Description
types.ReadWriteStream Returns a non-replayable readable and writable stream.

Examples

local handle <const> = assert(io.open("save.bin", "rb"))
local source <const> = tecs.io.newHandleStream(handle)
print(source:readAll())

source:close()
handle:close()

tecs.io.newHexDecodeReader Static

Creates a reader that incrementally decodes hexadecimal text.

The reader owns source and carries one unmatched nibble across source reads.

function tecs.io.newHexDecodeReader(
    source: types.Reader | FILE
): types.Reader

Arguments

Name Type Description
source types.Reader | FILE The caller supplies the reader of hexadecimal text.

Returns

Type Description
types.Reader Returns a caller-owned reader of decoded bytes.

Examples

tecs.scoped(function(scope: tecs.Scope)
    local reader <const> = scope:own(
        tecs.io.newHexDecodeReader(tecs.io.newStringReader("73617665"))
    )
    local decoded <const>, reason = reader:read(1024)

    assert(decoded, reason)
    assert(decoded == "save")
end)

tecs.io.newHexEncodeWriter Static

Creates a writer that incrementally encodes bytes as lowercase hexadecimal text.

The writer owns destination and forwards each encoded chunk without retaining input bytes.

function tecs.io.newHexEncodeWriter(
    destination: types.Writer | FILE
): types.Writer

Arguments

Name Type Description
destination types.Writer | FILE The caller supplies the writer receiving hexadecimal text.

Returns

Type Description
types.Writer Returns a caller-owned writer that accepts unencoded bytes.

Examples

tecs.scoped(function(scope: tecs.Scope)
    local encoded <const> = scope:own(tecs.io.newBuffer())
    local writer <const> = scope:own(
        tecs.io.newHexEncodeWriter(encoded:newWriter())
    )

    assert(writer:write("save"))
    assert(writer:close())
    assert(encoded:getString() == "73617665")
end)

tecs.io.newInflateReader Static

Creates a reader that incrementally inflates a compressed source.

The reader owns source and closes it when the wrapper closes. Reads retain only bounded compressed and decompressed chunks. A raw stream has no zlib header, trailer, or checksum.

function tecs.io.newInflateReader(
    source: types.Reader | FILE, options: types.InflateReaderOptions
): types.Reader

Arguments

Name Type Description
source types.Reader | FILE The caller supplies the reader of compressed bytes.
options types.InflateReaderOptions The caller selects raw framing and an output ceiling or omits it for a zlib stream and the default ceiling.

Returns

Type Description
types.Reader Returns a caller-owned reader of decompressed bytes.

Examples

tecs.scoped(function(scope: tecs.Scope)
    local compressed <const> = scope:own(tecs.io.newBuffer())
    local restored <const> = scope:own(tecs.io.newBuffer())
    local compressor <const> = scope:own(
        tecs.io.newDeflateWriter(compressed:newWriter())
    )

    assert(compressor:write("snapshot bytes"))
    assert(compressor:close())

    local reader <const> = scope:own(
        tecs.io.newInflateReader(compressed:newReader())
    )
    local sink <const> = scope:own(restored:newWriter())
    local count <const>, reason = tecs.io.transfer(reader, sink)

    assert(count, reason)
    assert(restored:getString() == "snapshot bytes")
end)

tecs.io.newStringReader Static

Creates a reader over an immutable Lua string.

The reader retains bytes without copying it. Closing the reader drops that retained reference; there is no separate resource to close.

function tecs.io.newStringReader(bytes: string): types.Reader

Arguments

Name Type Description
bytes string The caller supplies complete binary contents.

Returns

Type Description
types.Reader Returns a caller-owned reader whose cursor starts at zero.

Examples

local reader <const> = tecs.io.newStringReader("snapshot bytes")

assert(reader:read(1024) == "snapshot bytes")

reader:close()

tecs.io.newStringStream Static

Creates a replayable read-only string stream.

The stream retains the immutable string without copying it.

function tecs.io.newStringStream(
    bytes: string, contentType: string
): types.ReadableStream

Arguments

Name Type Description
bytes string The caller supplies complete binary contents.
contentType string The caller supplies optional media type metadata.

Returns

Type Description
types.ReadableStream Returns a readable stream.

Examples

local source <const> = tecs.io.newStringStream("hello", "text/plain")
print(source:readAll())

source:close()

tecs.io.newTranscodeReader Static

Creates a reader that incrementally converts character encodings.

The reader owns source. It preserves conversion state and carries an incomplete multibyte character across source reads.

function tecs.io.newTranscodeReader(
    source: types.Reader | FILE,
    fromEncoding: string,
    toEncoding: string
): types.Reader

Arguments

Name Type Description
source types.Reader | FILE The caller supplies the reader of encoded text.
fromEncoding string The caller supplies an SDL iconv source encoding name such as UTF-8.
toEncoding string The caller supplies an SDL iconv destination encoding name such as UTF-16LE.

Returns

Type Description
types.Reader Returns a caller-owned reader of converted text.

Examples

tecs.scoped(function(scope: tecs.Scope)
    local reader <const> = scope:own(
        tecs.io.newTranscodeReader(
            tecs.io.newStringReader("A\0\233\0"), "UTF-16LE", "UTF-8"
        )
    )
    local utf8 <const>, reason = reader:read(1024)

    assert(utf8, reason)
    assert(utf8 == "A\195\169")
end)

tecs.io.newTranscodeWriter Static

Creates a writer that incrementally converts character encodings.

The writer owns destination. It preserves conversion state and carries an incomplete multibyte character across writes; close rejects a truncated final character and emits any target shift state.

function tecs.io.newTranscodeWriter(
    destination: types.Writer | FILE,
    fromEncoding: string,
    toEncoding: string
): types.Writer

Arguments

Name Type Description
destination types.Writer | FILE The caller supplies the writer receiving converted text.
fromEncoding string The caller supplies an SDL iconv source encoding name such as UTF-8.
toEncoding string The caller supplies an SDL iconv destination encoding name such as UTF-16LE.

Returns

Type Description
types.Writer Returns a caller-owned writer that accepts bytes in fromEncoding.

Examples

tecs.scoped(function(scope: tecs.Scope)
    local utf16 <const> = scope:own(tecs.io.newBuffer())
    local writer <const> = scope:own(
        tecs.io.newTranscodeWriter(
            utf16:newWriter(), "UTF-8", "UTF-16LE"
        )
    )

    assert(writer:write("A\195"))
    assert(writer:write("\169"))
    assert(writer:close())
    assert(utf16:getString() == "A\0\233\0")
end)

Types

tecs.io.Address record

An Address owns one resolved network address. Closing it releases the address and remains safe to repeat.

record tecs.io.Address is Closeable
    host: string
    text: string

    close: function(self): boolean, string
    isClosed: function(self): boolean
end

Interfaces

Interface
Closeable

tecs.io.Address.host field

Read-only. Networking sets host at resolution or peer lookup. It contains the requested hostname or numeric peer address.

tecs.io.Address.host: string

tecs.io.Address.text field

Read-only. Networking sets text to the printable numeric address when it creates the object.

tecs.io.Address.text: string

tecs.io.Address:close Instance

function tecs.io.Address.close(self): boolean, string
Arguments
Name Type Description
self Address
Returns
Type Description
boolean
string

tecs.io.Address:isClosed Instance

Returns whether close has released this address.

function tecs.io.Address.isClosed(self): boolean
Arguments
Name Type Description
self Address
Returns
Type Description
boolean Returns true after close.

tecs.io.Buffer interface

A Buffer is owned growable FFI-backed byte storage.

interface tecs.io.Buffer is Closeable
    interface WriteRange is Closeable
        capacity: function(self): integer
        commit: function(self, used: integer)
        getFFIPointer: function(self): loader.BytePointer
    end

    capacity: function(self): integer
    clear: function(self)
    ensureCapacity: function(self, minimum: integer)
    getFFIPointer: function(self): loader.BytePointer
    getString: function(self, offset: integer, count: integer): string
    isReleased: function(self): boolean
    length: function(self): integer
    newReader: function(self): Reader
    newStream: function(self, contentType: string): ReadWriteStream
    newWriter: function(self): Writer
    reserveRange: function(
        self, offset: integer, minimum: integer
    ): WriteRange
    resize: function(self, length: integer)
    setString: function(self, bytes: string, offset: integer)
    view: function(self, offset: integer, count: integer): ByteView
end

Interfaces

Interface
Closeable

tecs.io.Buffer.WriteRange interface

An exclusive, zero-copy writable range reserved from a Buffer. Closing abandons the range without changing the buffer's logical length.

interface tecs.io.Buffer.WriteRange is Closeable
    capacity: function(self): integer
    commit: function(self, used: integer)
    getFFIPointer: function(self): loader.BytePointer
end
Interfaces
Interface
Closeable

tecs.io.Buffer.WriteRange:capacity Instance

Returns the maximum byte count the native writer may fill.

function tecs.io.Buffer.WriteRange.capacity(self): integer
Arguments
Name Type Description
self WriteRange The open range to inspect.
Returns
Type Description
integer Returns the reserved byte capacity.

tecs.io.Buffer.WriteRange:commit Instance

Commits bytes written through the borrowed pointer.

The call closes the range. A gap before the committed bytes is zero-filled.

function tecs.io.Buffer.WriteRange.commit(self, used: integer)
Arguments
Name Type Description
self WriteRange The open range to commit.
used integer The caller supplies the written count up to capacity.
Returns

None.

tecs.io.Buffer.WriteRange:getFFIPointer Instance

Borrows the reserved range's writable address.

function tecs.io.Buffer.WriteRange.getFFIPointer(
    self
): loader.BytePointer
Arguments
Name Type Description
self WriteRange The open range whose storage to borrow.
Returns
Type Description
loader.BytePointer Returns a pointer valid until commit or close.

tecs.io.Buffer:capacity Instance

Returns the allocated byte capacity.

function tecs.io.Buffer.capacity(self): integer
Arguments
Name Type Description
self Buffer The buffer to inspect.
Returns
Type Description
integer Returns the byte count available without reallocating.

Examples

local bytes <const> = tecs.io.newBuffer("data")

assert(bytes:capacity() >= bytes:length())

bytes:close()

tecs.io.Buffer:clear Instance

Removes every logical byte without releasing the allocation.

function tecs.io.Buffer.clear(self)
Arguments
Name Type Description
self Buffer The buffer to clear.
Returns

None.

Examples

local bytes <const> = tecs.io.newBuffer("reusable")
local capacity <const> = bytes:capacity()
bytes:clear()

assert(bytes:length() == 0)
assert(bytes:capacity() == capacity)

bytes:close()

tecs.io.Buffer:ensureCapacity Instance

Ensures at least minimum bytes fit without another allocation.

Growth is geometric. A call at or below the current capacity leaves pointers returned by getFFIPointer valid.

function tecs.io.Buffer.ensureCapacity(self, minimum: integer)
Arguments
Name Type Description
self Buffer The buffer to grow.
minimum integer The caller supplies a non-negative byte count.
Returns

None.

Examples

local bytes <const> = tecs.io.newBuffer("data")
bytes:ensureCapacity(1024)

assert(bytes:capacity() >= 1024)
assert(bytes:length() == 4)

bytes:close()

tecs.io.Buffer:getFFIPointer Instance

Borrows the address of the first byte.

The pointer is invalid after capacity grows or close runs. The buffer must remain reachable for the whole native call that uses it.

function tecs.io.Buffer.getFFIPointer(self): loader.BytePointer
Arguments
Name Type Description
self Buffer The buffer whose storage to borrow.
Returns
Type Description
loader.BytePointer Returns a mutable FFI byte pointer.

Examples

local bytes <const> = tecs.io.newBuffer("native bytes")
local pointer <const> = bytes:getFFIPointer()
print(pointer)

bytes:close()

tecs.io.Buffer:getString Instance

Copies a range into a Lua string.

function tecs.io.Buffer.getString(
    self, offset: integer, count: integer
): string
Arguments
Name Type Description
self Buffer The source buffer.
offset integer The caller supplies a zero-based offset or omits it for zero.
count integer The caller supplies a byte count or omits it for the remainder.
Returns
Type Description
string Returns a fresh binary string.

Examples

local bytes <const> = tecs.io.newBuffer("headerpayload")
print(bytes:getString(6, 7))

bytes:close()

tecs.io.Buffer:isReleased Instance

Returns whether close has given up the allocation.

function tecs.io.Buffer.isReleased(self): boolean
Arguments
Name Type Description
self Buffer The buffer to inspect.
Returns
Type Description
boolean Returns true after close.

Examples

local bytes <const> = tecs.io.newBuffer()

assert(not bytes:isReleased())

bytes:close()

assert(bytes:isReleased())

tecs.io.Buffer:length Instance

Returns the number of logical bytes.

function tecs.io.Buffer.length(self): integer
Arguments
Name Type Description
self Buffer The buffer to inspect.
Returns
Type Description
integer Returns the bytes visible to getString.

Examples

local bytes <const> = tecs.io.newBuffer("four")
print(bytes:length())

bytes:close()

tecs.io.Buffer:newReader Instance

Opens a reader over an immutable snapshot of the current bytes.

The reader retains the allocation independently, so the caller may close or mutate the buffer after this call. Its cursor starts at zero.

function tecs.io.Buffer.newReader(self): Reader
Arguments
Name Type Description
self Buffer The open source buffer.
Returns
Type Description
Reader Returns a caller-owned reader.

Examples

local bytes <const> = tecs.io.newBuffer("snapshot")
local reader <const> = bytes:newReader()

bytes:close()

assert(reader:read(1024) == "snapshot")

reader:close()

tecs.io.Buffer:newStream Instance

Creates a stream sharing this buffer.

The stream borrows this buffer. The caller keeps it open while using the stream and closes it separately. Closing the stream never closes the buffer. transferToBuffer returns this same borrowed object without transferring ownership.

function tecs.io.Buffer.newStream(
    self, contentType: string
): ReadWriteStream
Arguments
Name Type Description
self Buffer The open buffer the stream borrows.
contentType string The caller supplies optional media type metadata.
Returns
Type Description
ReadWriteStream Returns a caller-owned readable and writable stream.

Examples

local bytes <const> = tecs.io.newBuffer("old")
local stream <const> = bytes:newStream()

assert(stream:writeAll("new"))
print(bytes:getString())

stream:close()
bytes:close()

tecs.io.Buffer:newWriter Instance

Opens a writer that replaces the current bytes.

The call clears the logical length while retaining capacity. The caller keeps the buffer open until the writer closes.

function tecs.io.Buffer.newWriter(self): Writer
Arguments
Name Type Description
self Buffer The open destination buffer.
Returns
Type Description
Writer Returns a caller-owned writer.

Examples

local bytes <const> = tecs.io.newBuffer("old")
local writer <const> = bytes:newWriter()

assert(writer:write("new"))
assert(writer:close())
assert(bytes:getString() == "new")

bytes:close()

tecs.io.Buffer:reserveRange Instance

Reserves an exclusive range for a native writer without an intermediate string.

The buffer detaches from retained views before exposing mutable storage.

function tecs.io.Buffer.reserveRange(
    self, offset: integer, minimum: integer
): WriteRange
Arguments
Name Type Description
self Buffer The open buffer to reserve.
offset integer The caller supplies a zero-based write offset.
minimum integer The caller supplies the minimum writable capacity.
Returns
Type Description
WriteRange Returns a caller-owned exclusive range.

tecs.io.Buffer:resize Instance

Changes the logical length.

Expansion fills every newly visible byte with zero. Shrinking keeps the allocation for reuse.

function tecs.io.Buffer.resize(self, length: integer)
Arguments
Name Type Description
self Buffer The buffer to resize.
length integer The caller supplies a non-negative byte count.
Returns

None.

Examples

local bytes <const> = tecs.io.newBuffer("data")
bytes:resize(6)

assert(bytes:getString() == "data\0\0")
bytes:resize(2)

assert(bytes:getString() == "da")

bytes:close()

tecs.io.Buffer:setString Instance

Copies a Lua string into the buffer.

The write extends the logical length as needed. A gap between the old end and offset is zero-filled.

function tecs.io.Buffer.setString(self, bytes: string, offset: integer)
Arguments
Name Type Description
self Buffer The destination buffer.
bytes string The caller supplies a binary string.
offset integer The caller supplies a zero-based offset or omits it for zero.
Returns

None.

Examples

local bytes <const> = tecs.io.newBuffer("abcdefgh")
bytes:setString("XY", 3)

assert(bytes:getString() == "abcXYfgh")
bytes:setString("!", 10)

assert(bytes:getString(8, 3) == "\0\0!")

bytes:close()

tecs.io.Buffer:view Instance

Returns a zero-copy immutable snapshot of a byte range.

function tecs.io.Buffer.view(
    self, offset: integer, count: integer
): ByteView
Arguments
Name Type Description
self Buffer The open buffer to retain.
offset integer The caller supplies a zero-based offset or omits it for zero.
count integer The caller supplies a byte count or omits it for the remainder.
Returns
Type Description
ByteView Returns a caller-owned retained view.

tecs.io.ByteView interface

A ByteView retains an immutable zero-copy range from a buffer.

interface tecs.io.ByteView is Closeable
    getFFIPointer: function(self): loader.BytePointer
    getString: function(self): string
    isReleased: function(self): boolean
    length: function(self): integer
    newReader: function(self): Reader
    newStream: function(self, contentType: string): ReadableStream
    view: function(self, offset: integer, count: integer): ByteView
end

Interfaces

Interface
Closeable

tecs.io.ByteView:getFFIPointer Instance

Borrows the retained range's read-only address.

LuaJIT FFI cannot enforce constness. Writing through a cast pointer is unsafe and breaks the snapshot guarantee.

function tecs.io.ByteView.getFFIPointer(self): loader.BytePointer
Arguments
Name Type Description
self ByteView The open view whose storage to borrow.
Returns
Type Description
loader.BytePointer Returns a pointer valid until close.

tecs.io.ByteView:getString Instance

Copies the retained range into a Lua string.

function tecs.io.ByteView.getString(self): string
Arguments
Name Type Description
self ByteView The open view to copy.
Returns
Type Description
string Returns a fresh binary string.

tecs.io.ByteView:isReleased Instance

Returns whether the view has released its retained allocation.

function tecs.io.ByteView.isReleased(self): boolean
Arguments
Name Type Description
self ByteView The view to inspect.
Returns
Type Description
boolean Returns true after close.

tecs.io.ByteView:length Instance

Returns the retained range's byte length.

function tecs.io.ByteView.length(self): integer
Arguments
Name Type Description
self ByteView The open view to inspect.
Returns
Type Description
integer Returns the number of readable bytes.

tecs.io.ByteView:newReader Instance

Opens a reader over this immutable range.

The reader retains the allocation independently, so the caller may close this view immediately after the call. Its cursor starts at zero.

function tecs.io.ByteView.newReader(self): Reader
Arguments
Name Type Description
self ByteView The open source view.
Returns
Type Description
Reader Returns a caller-owned reader.

Examples

local bytes <const> = tecs.io.newBuffer("headerpayload")
local payload <const> = bytes:view(6)
local reader <const> = payload:newReader()

payload:close()
bytes:close()

assert(reader:read(1024) == "payload")

reader:close()

tecs.io.ByteView:newStream Instance

Creates a replayable read-only stream retaining this view.

The stream retains its own view, so the caller may close this view immediately after construction. Closing the stream closes its retained view after already-open readers close theirs.

function tecs.io.ByteView.newStream(
    self, contentType: string
): ReadableStream
Arguments
Name Type Description
self ByteView The open immutable byte view.
contentType string The caller supplies optional media type metadata.
Returns
Type Description
ReadableStream Returns a caller-owned readable stream.

Examples

local bytes <const> = tecs.io.newBuffer("headerpayload")
local payload <const> = bytes:view(6)
local source <const> = payload:newStream("application/octet-stream")

payload:close()
bytes:close()

assert(source:readAll() == "payload")

source:close()

tecs.io.ByteView:view Instance

Retains a zero-copy subrange.

function tecs.io.ByteView.view(
    self, offset: integer, count: integer
): ByteView
Arguments
Name Type Description
self ByteView The open source view.
offset integer The caller supplies a zero-based offset or omits it for zero.
count integer The caller supplies a byte count or omits it for the remainder.
Returns
Type Description
ByteView Returns a caller-owned view retaining the same allocation.

tecs.io.DeflateWriterOptions record

Options control an incremental deflate writer.

record tecs.io.DeflateWriterOptions
    raw: boolean
    level: integer
end

tecs.io.DeflateWriterOptions.raw field

Caller-writable. Selects raw DEFLATE when true and zlib framing when false or omitted.

tecs.io.DeflateWriterOptions.raw: boolean

tecs.io.DeflateWriterOptions.level field

Caller-writable. Sets zlib's compression level from minus one through nine or uses its default when omitted.

tecs.io.DeflateWriterOptions.level: integer

tecs.io.InflateReaderOptions record

Options control an incremental inflate reader.

record tecs.io.InflateReaderOptions
    raw: boolean
    maxBytes: integer
end

tecs.io.InflateReaderOptions.raw field

Caller-writable. Selects raw DEFLATE when true and zlib framing when false or omitted.

tecs.io.InflateReaderOptions.raw: boolean

tecs.io.InflateReaderOptions.maxBytes field

Caller-writable. Sets the hard decompressed-byte ceiling or uses 268,435,456 bytes when omitted.

tecs.io.ReadableStream interface

A ReadableStream opens readers and supplies whole-source transfers.

interface tecs.io.ReadableStream is Stream, Closeable
    discard: function(self): integer, string
    newReader: function(self): Reader, string
    readAll: function(self, maxBytes: integer): string, string
    transferTo: function(
        self, destination: WritableStream
    ): integer, string
    transferToBuffer: function(self, maxBytes: integer): Buffer, string
    transferToFile: function(self, path: string): integer, string
end

Interfaces

Interface
Stream
Closeable

tecs.io.ReadableStream:discard Instance

Reads and discards every source byte.

The operation opens, consumes, and closes one reader. On a non-replayable stream, this claims its one endpoint.

function tecs.io.ReadableStream.discard(self): integer, string
Arguments
Name Type Description
self ReadableStream The readable descriptor.
Returns
Type Description
integer Returns the bytes discarded.
string Returns the source's reason when the first return is nil.

Examples

local source <const> = tecs.io.newFileStream("download.tmp")
local count <const> = source:discard()
print(count)

source:close()

tecs.io.ReadableStream:newReader Instance

Opens a reader with a new cursor.

function tecs.io.ReadableStream.newReader(self): Reader, string
Arguments
Name Type Description
self ReadableStream The readable descriptor.
Returns
Type Description
Reader Returns a caller-owned reader, or nil when unavailable.
string Returns the reason when the first return is nil.

Examples

local source <const> = tecs.io.newStringStream("data")
local reader <const> = assert(source:newReader())
print(reader:read(4))

reader:close()
source:close()

tecs.io.ReadableStream:readAll Instance

Reads the complete source into a Lua string.

The operation opens, consumes, and closes one reader. On a non-replayable stream, this claims its one endpoint.

function tecs.io.ReadableStream.readAll(
    self, maxBytes: integer
): string, string
Arguments
Name Type Description
self ReadableStream The readable descriptor.
maxBytes integer The caller supplies a non-negative limit or omits it for no explicit limit.
Returns
Type Description
string Returns the complete bytes.
string Returns the source's reason when the first return is nil.

Examples

local source <const> = tecs.io.newStringStream("data")
local bytes <const> = source:readAll(1024)
print(bytes)

source:close()

tecs.io.ReadableStream:transferTo Instance

Copies every source byte into destination.

The operation opens and closes one source reader and one destination writer. Either non-replayable descriptor is claimed by the call.

function tecs.io.ReadableStream.transferTo(
    self, destination: WritableStream
): integer, string
Arguments
Name Type Description
self ReadableStream The readable descriptor.
destination WritableStream The caller supplies an available writable stream.
Returns
Type Description
integer Returns the bytes written.
string Returns the source or destination reason when the first return is nil.

Examples

local source <const> = tecs.io.newStringStream("data")
local output <const> = tecs.io.newBuffer()
local destination <const> = output:newStream()
local count <const> = source:transferTo(destination)
print(count, output:getString())

source:close()
destination:close()
output:close()

tecs.io.ReadableStream:transferToBuffer Instance

Transfers the complete source into an owned buffer.

A stream created by Buffer:newStream returns that same borrowed buffer without copying and does not transfer ownership. Other streams return a newly allocated buffer owned by the caller. The operation opens, consumes, and closes one reader when it must copy. On a non-replayable stream, this claims its one endpoint.

function tecs.io.ReadableStream.transferToBuffer(
    self, maxBytes: integer
): Buffer, string
Arguments
Name Type Description
self ReadableStream The readable descriptor.
maxBytes integer The caller supplies a non-negative limit or omits it for no explicit limit.
Returns
Type Description
Buffer Returns a caller-owned buffer.
string Returns the source's reason when the first return is nil.

Examples

local source <const> = tecs.io.newFileStream("save.bin")
local bytes <const> = source:transferToBuffer(1024 * 1024)
print(bytes:length())

bytes:close()
source:close()

tecs.io.ReadableStream:transferToFile Instance

Copies every source byte into a file.

The operation opens and closes one source reader. On a non-replayable stream, this claims its one endpoint.

function tecs.io.ReadableStream.transferToFile(
    self, path: string
): integer, string
Arguments
Name Type Description
self ReadableStream The readable descriptor.
path string The caller supplies the destination path to replace.
Returns
Type Description
integer Returns the bytes written.
string Returns the source or file reason when the first return is nil.

Examples

local source <const> = tecs.io.newStringStream("save data")
local count <const> = source:transferToFile("save.bin")
print(count)

source:close()

tecs.io.Reader interface

A Reader supplies bytes in order and releases its owned state on close.

interface tecs.io.Reader is Closeable
    read: function(self, count: integer): string, string
    readInto: function(
        self, destination: Buffer, offset: integer, count: integer
    ): integer, string
end

Interfaces

Interface
Closeable

tecs.io.Reader:read Instance

Caller-writable. Supplies the operation that reads the next bytes.

function tecs.io.Reader.read(self, count: integer): string, string
Arguments
Name Type Description
self Reader The reader whose cursor advances.
count integer The maximum number of bytes to return when positive. Zero and negative counts are treated as one so the reader makes progress.
Returns
Type Description
string Returns up to max(1, count) bytes, fewer at the end, or an empty string after the source is exhausted.
string Returns the source's reason when the first return is nil.

Examples

local source <const> = tecs.io.newStringStream("abcdefgh")
local reader <const> = assert(source:newReader())
local chunk <const>, reason = reader:read(4)

assert(chunk, reason)
print(chunk)

reader:close()
source:close()

tecs.io.Reader:readInto Instance

Reads bytes directly into a buffer and advances the cursor.

The operation grows the destination as needed and preserves bytes outside the written range. It returns zero after the source is exhausted.

function tecs.io.Reader.readInto(
    self, destination: Buffer, offset: integer, count: integer
): integer, string
Arguments
Name Type Description
self Reader The open reader whose cursor advances.
destination Buffer The caller supplies an open destination buffer and keeps ownership of it.
offset integer The caller supplies a non-negative zero-based destination offset or omits it for zero.
count integer The caller supplies the maximum non-negative byte count or omits it for 16,384.
Returns
Type Description
integer Returns the number of bytes written into the destination.
string Returns the source's reason when the first return is nil.

Examples

local source <const> = tecs.io.newStringStream("abcdefgh")
local reader <const> = assert(source:newReader())
local bytes <const> = tecs.io.newBuffer("prefix:")
local count <const>, reason = reader:readInto(bytes, bytes:length(), 4)

assert(count, reason)
print(bytes:getString())

reader:close()
source:close()
bytes:close()

tecs.io.ReadWriteStream interface

A ReadWriteStream supports both directional interfaces.

interface tecs.io.ReadWriteStream is ReadableStream, Stream, Closeable, WritableStream
end

Interfaces

Interface
ReadableStream
Stream
Closeable
WritableStream

tecs.io.Seekable interface

Seekable supplies random-access cursor operations shared by readers and writers.

interface tecs.io.Seekable
    enum Origin
        "current"
        "end"
        "start"
    end

    seek: function(
        self, origin: Origin, offset: integer
    ): integer, string
    size: function(self): integer, string
    tell: function(self): integer, string
end

tecs.io.Seekable.Origin enum

Origin selects the reference point for a seek.

enum tecs.io.Seekable.Origin
    "current"
    "end"
    "start"
end

tecs.io.Seekable:seek Instance

Repositions the cursor and returns its new absolute position.

"start" measures offset from byte zero, "current" measures it from the cursor, and "end" measures it from the current byte length. The offset defaults to zero and may be negative for the latter two origins. A result before byte zero or past the current end fails without moving the cursor.

function tecs.io.Seekable.seek(
    self, origin: Origin, offset: integer
): integer, string
Arguments
Name Type Description
self Seekable The open cursor to reposition.
origin Origin The caller selects the reference point.
offset integer The caller supplies a signed integer byte offset or omits it for zero.
Returns
Type Description
integer Returns the new zero-based cursor position.
string Returns the storage reason when the first return is nil.

tecs.io.Seekable:size Instance

Returns the storage's current byte length.

The result includes every write already accepted even when buffered bytes have not reached the underlying destination yet.

function tecs.io.Seekable.size(self): integer, string
Arguments
Name Type Description
self Seekable The open cursor to inspect.
Returns
Type Description
integer Returns the current byte length.
string Returns the storage reason when the first return is nil.

tecs.io.Seekable:tell Instance

Returns the current zero-based cursor position.

function tecs.io.Seekable.tell(self): integer, string
Arguments
Name Type Description
self Seekable The open cursor to inspect.
Returns
Type Description
integer Returns the cursor's byte position.
string Returns the storage reason when the first return is nil.

tecs.io.SeekableReader interface

A SeekableReader supplies bytes through a repositionable cursor.

interface tecs.io.SeekableReader is Reader, Closeable, Seekable
end

Interfaces

Interface
Reader
Closeable
Seekable

tecs.io.SeekableWriter interface

A SeekableWriter patches a destination through a repositionable cursor.

interface tecs.io.SeekableWriter is Writer, Closeable, Seekable
end

Interfaces

Interface
Writer
Closeable
Seekable

tecs.io.Stream interface

A Stream describes binary storage without retaining a cursor.

interface tecs.io.Stream is Closeable
    contentLength: function(self): integer | nil
    contentType: function(self): string | nil
    isReadable: function(self): boolean
    isReplayable: function(self): boolean
    isWritable: function(self): boolean
    withMetadata: function<T is Stream>(
        self,
        contentType: string,
        contentLength: integer,
        isReplayable: boolean
    ): T
end

Interfaces

Interface
Closeable

tecs.io.Stream:contentLength Instance

Returns the byte length when it is known.

function tecs.io.Stream.contentLength(self): integer | nil
Arguments
Name Type Description
self Stream The descriptor to inspect.
Returns
Type Description
integer | nil Returns the current byte length, or nil when it cannot be known before reading.

Examples

local source <const> = tecs.io.newStringStream("four")
local length <const> = source:contentLength()
if length ~= nil then
    print(length)
end

source:close()

tecs.io.Stream:contentType Instance

Returns the media type supplied at construction.

function tecs.io.Stream.contentType(self): string | nil
Arguments
Name Type Description
self Stream The descriptor to inspect.
Returns
Type Description
string | nil Returns the media type, or nil when none was supplied.

Examples

local source <const> = tecs.io.newStringStream("{}", "application/json")
print(source:contentType())

source:close()

tecs.io.Stream:isReadable Instance

Returns whether the descriptor can open a reader.

function tecs.io.Stream.isReadable(self): boolean
Arguments
Name Type Description
self Stream The descriptor to inspect.
Returns
Type Description
boolean Returns true when newReader is supported.

Examples

local source <const> = tecs.io.newStringStream("data")
print(source:isReadable())

source:close()

tecs.io.Stream:isReplayable Instance

Returns whether each reader starts from the beginning.

True means the descriptor can open independent readers repeatedly. False means opening an endpoint or running a whole-source operation may claim the descriptor permanently; newReader reports when it can no longer open one.

function tecs.io.Stream.isReplayable(self): boolean
Arguments
Name Type Description
self Stream The descriptor to inspect.
Returns
Type Description
boolean Returns true when opening a later reader replays all bytes.

Examples

local source <const> = tecs.io.newStringStream("data")
print(source:isReplayable())

source:close()

tecs.io.Stream:isWritable Instance

Returns whether the descriptor can open a writer.

function tecs.io.Stream.isWritable(self): boolean
Arguments
Name Type Description
self Stream The descriptor to inspect.
Returns
Type Description
boolean Returns true when newWriter is supported.

Examples

local save <const> = tecs.io.newFileStream("save.bin")
print(save:isWritable())

save:close()

tecs.io.Stream:withMetadata Instance

Creates a lazy view that overrides this descriptor's metadata.

Nil inherits each value from the receiver. The view retains and delegates to the receiver, preserves its static and runtime directional interface, and closes the receiver when it closes. If every supplied value already matches, this returns the receiver.

function tecs.io.Stream.withMetadata<T is Stream>(
    self,
    contentType: string,
    contentLength: integer,
    isReplayable: boolean
): T
Type Parameters
Name Constraint Description
T Stream
Arguments
Name Type Description
self T The stream whose storage and operations the view retains.
contentType string The caller overrides the media type or omits it.
contentLength integer The caller overrides the non-negative byte length or omits it.
isReplayable boolean The caller overrides replayability or omits it.
Returns
Type Description
T Returns a metadata view with the receiver's stream type.

Examples

local source <const> = tecs.io.newStringStream("{}")
local json <const> = source:withMetadata("application/json")
print(json:contentType())

json:close()

tecs.io.TCPListener record

A TCPListener listens for TCP clients. Closing it stops listening, leaves accepted streams open, and remains safe to repeat.

record tecs.io.TCPListener is Closeable
    port: integer

    accept: function(self): TCPSocket, string
    close: function(self): boolean, string
    isClosed: function(self): boolean
    wait: function(self, timeoutMs: integer): boolean, string
end

Interfaces

Interface
Closeable

tecs.io.TCPListener.port field

Read-only. Networking sets port from the value passed to listen and never changes it. Zero remains zero.

tecs.io.TCPListener.port: integer

tecs.io.TCPListener:accept Instance

Takes one pending client without waiting.

Returns nil with no error when nobody waits. The caller owns the returned stream.

function tecs.io.TCPListener.accept(self): TCPSocket, string
Arguments
Name Type Description
self TCPListener
Returns
Type Description
TCPSocket Returns one caller-owned client, or nil when none waits or acceptance fails.
string Returns the reason only when acceptance fails.

tecs.io.TCPListener:close Instance

function tecs.io.TCPListener.close(self): boolean, string
Arguments
Name Type Description
self TCPListener
Returns
Type Description
boolean
string

tecs.io.TCPListener:isClosed Instance

Returns whether close has released this listener.

function tecs.io.TCPListener.isClosed(self): boolean
Arguments
Name Type Description
self TCPListener
Returns
Type Description
boolean Returns true after close.

tecs.io.TCPListener:wait Instance

Waits up to timeoutMs for a client to become ready to accept.

Returns false without an error on timeout. This does not accept the client; call accept afterwards.

function tecs.io.TCPListener.wait(
    self, timeoutMs: integer
): boolean, string
Arguments
Name Type Description
self TCPListener
timeoutMs integer The caller supplies 0 to 2147483647 milliseconds or omits it for zero. Zero polls without blocking.
Returns
Type Description
boolean Returns true when at least one client waits.
string Returns the reason on failure. Timeout returns false without a reason.

tecs.io.TCPSocket record

A TCPSocket owns one connected TCP byte stream. Closing it may discard queued writes, so a caller drains delivery-sensitive output first. Repeated closure remains safe.

record tecs.io.TCPSocket is Closeable
    close: function(self): boolean, string
    drain: function(self, timeoutMs: integer): boolean, string
    isClosed: function(self): boolean
    peer: function(self): Address, string
    pendingWrites: function(self): integer, string
    read: function(self, maxBytes: integer): string, string
    readInto: function(
        self, destination: IOBuffer, offset: integer, maxBytes: integer
    ): integer, string
    wait: function(self, timeoutMs: integer): boolean, string
    write: function(self, bytes: string): boolean, string
    writeFrom: function(
        self, source: IOBuffer, offset: integer, count: integer
    ): integer, string
    writeView: function(
        self, source: types.ByteView, offset: integer, count: integer
    ): integer, string
end

Interfaces

Interface
Closeable

tecs.io.TCPSocket:close Instance

function tecs.io.TCPSocket.close(self): boolean, string
Arguments
Name Type Description
self TCPSocket
Returns
Type Description
boolean
string

tecs.io.TCPSocket:drain Instance

Waits up to timeoutMs for queued writes to be sent.

Returns false without an error on timeout.

function tecs.io.TCPSocket.drain(
    self, timeoutMs: integer
): boolean, string
Arguments
Name Type Description
self TCPSocket
timeoutMs integer The caller supplies 0 to 2147483647 milliseconds or omits it for 5000. Zero polls without blocking.
Returns
Type Description
boolean Returns true when the local send queue reaches zero before timeout.
string Returns the reason on failure. Timeout returns false without a reason.

tecs.io.TCPSocket:isClosed Instance

Returns whether close has released this connection.

function tecs.io.TCPSocket.isClosed(self): boolean
Arguments
Name Type Description
self TCPSocket
Returns
Type Description
boolean Returns true after close.

tecs.io.TCPSocket:peer Instance

Returns a newly owned address for the remote peer.

The caller closes the returned address.

function tecs.io.TCPSocket.peer(self): Address, string
Arguments
Name Type Description
self TCPSocket
Returns
Type Description
Address Returns a caller-owned address that outlives the connection, or nil on failure.
string Returns the reason when the first return is nil.

tecs.io.TCPSocket:pendingWrites Instance

Returns bytes accepted but not yet sent.

function tecs.io.TCPSocket.pendingWrites(self): integer, string
Arguments
Name Type Description
self TCPSocket
Returns
Type Description
integer Returns the queued byte count, zero after sending, or nil on failure.
string Returns the reason when the first return is nil.

tecs.io.TCPSocket:read Instance

Reads up to maxBytes without waiting.

Returns nil with no error when no bytes are ready. Returns nil with an error after the peer disconnects or the read fails. A successful read may contain fewer bytes than requested.

function tecs.io.TCPSocket.read(
    self, maxBytes: integer
): string, string
Arguments
Name Type Description
self TCPSocket
maxBytes integer The caller supplies a ceiling from 1 to 65536 bytes or omits it for 16384. Invalid values raise.
Returns
Type Description
string Returns a fresh string of available bytes, or nil when no bytes arrived or the read failed.
string Returns the reason only when reading fails or the peer disconnects.

tecs.io.TCPSocket:readInto Instance

Reads available bytes directly into reusable FFI memory.

The call writes at a zero-based offset and extends the buffer through the last byte read. It returns nil without a reason when no bytes are ready and leaves the logical length and bytes unchanged; reserving the requested range may still grow capacity. A zero count returns zero without consuming input.

function tecs.io.TCPSocket.readInto(
    self, destination: IOBuffer, offset: integer, maxBytes: integer
): integer, string
Arguments
Name Type Description
self TCPSocket
destination IOBuffer The caller supplies an open Buffer.
offset integer The caller supplies a zero-based destination offset or omits it for zero.
maxBytes integer The caller supplies a ceiling from 0 to 65536 bytes or omits it for 16384. Invalid values raise.
Returns
Type Description
integer Returns the bytes read, zero for a zero-byte request, or nil when no bytes arrived or the read failed.
string Returns the reason only when reading fails or the peer disconnects.

tecs.io.TCPSocket:wait Instance

Waits up to timeoutMs for input or disconnection.

Returns false without an error on timeout. This does not consume input; call read afterwards.

function tecs.io.TCPSocket.wait(
    self, timeoutMs: integer
): boolean, string
Arguments
Name Type Description
self TCPSocket
timeoutMs integer The caller supplies 0 to 2147483647 milliseconds or omits it for zero. Zero polls without blocking.
Returns
Type Description
boolean Returns true when input arrives or the peer disconnects.
string Returns the reason on failure. Timeout returns false without a reason.

tecs.io.TCPSocket:write Instance

Queues one chunk for reliable ordered delivery.

This accepting the bytes does not mean the peer has received them; use pendingWrites or drain when that distinction matters.

function tecs.io.TCPSocket.write(self, bytes: string): boolean, string
Arguments
Name Type Description
self TCPSocket
bytes string The caller supplies at most 16777216 bytes. Larger values raise; an empty string succeeds without queuing data.
Returns
Type Description
boolean Returns true only when the connection accepts the whole chunk.
string Returns the reason when the first return is false.

tecs.io.TCPSocket:writeFrom Instance

Queues a buffer range for reliable ordered delivery.

The native send queue copies the range before this call returns, so the caller may mutate or close the buffer afterwards. This avoids constructing an intermediate Lua string but does not bypass the queue's ownership copy.

function tecs.io.TCPSocket.writeFrom(
    self, source: IOBuffer, offset: integer, count: integer
): integer, string
Arguments
Name Type Description
self TCPSocket
source IOBuffer The caller supplies an open Buffer.
offset integer The caller supplies a zero-based source offset or omits it for zero.
count integer The caller supplies at most 16777216 bytes or omits it for the remainder. Invalid ranges raise.
Returns
Type Description
integer Returns the number of bytes accepted.
string Returns the reason when the first return is nil.

tecs.io.TCPSocket:writeView Instance

Queues a retained byte view without constructing an intermediate string.

The native send queue copies the range before this call returns.

function tecs.io.TCPSocket.writeView(
    self, source: types.ByteView, offset: integer, count: integer
): integer, string
Arguments
Name Type Description
self TCPSocket
source types.ByteView The caller supplies an open ByteView.
offset integer The caller supplies a zero-based source offset or omits it for zero.
count integer The caller supplies at most 16777216 bytes or omits it for the remainder. Invalid ranges raise.
Returns
Type Description
integer Returns the number of bytes accepted.
string Returns the reason when the first return is nil.

tecs.io.UDPPacket record

A UDPPacket owns one received UDP datagram and its source address. Closing it releases both the address and byte buffer and remains safe to repeat.

record tecs.io.UDPPacket is Closeable
    address: Address
    port: integer
    bytes: IOBuffer

    close: function(self): boolean, string
end

Interfaces

Interface
Closeable

tecs.io.UDPPacket.address field

Read-only. Networking sets address when receiving the packet. The packet owns it until close.

tecs.io.UDPPacket.port field

Read-only. Networking sets port to the remote source port when receiving the packet.

tecs.io.UDPPacket.port: integer

tecs.io.UDPPacket.bytes field

Read-only. Networking sets bytes to one caller-owned Buffer containing the complete datagram. A zero-length datagram uses an empty buffer. close releases it.

tecs.io.UDPPacket:close Instance

function tecs.io.UDPPacket.close(self): boolean, string
Arguments
Name Type Description
self UDPPacket
Returns
Type Description
boolean
string

tecs.io.UDPSocket record

A UDPSocket sends and receives UDP packets. Closing it releases the socket and remains safe to repeat.

record tecs.io.UDPSocket is Closeable
    port: integer

    close: function(self): boolean, string
    isClosed: function(self): boolean
    receive: function(self): UDPPacket, string
    send: function(
        self, address: Address, port: integer, bytes: string
    ): boolean, string
    wait: function(self, timeoutMs: integer): boolean, string
end

Interfaces

Interface
Closeable

tecs.io.UDPSocket.port field

Read-only. Networking sets port from the value passed to bind and never changes it. Zero remains zero.

tecs.io.UDPSocket.port: integer

tecs.io.UDPSocket:close Instance

function tecs.io.UDPSocket.close(self): boolean, string
Arguments
Name Type Description
self UDPSocket
Returns
Type Description
boolean
string

tecs.io.UDPSocket:isClosed Instance

Returns whether close has released this socket.

function tecs.io.UDPSocket.isClosed(self): boolean
Arguments
Name Type Description
self UDPSocket
Returns
Type Description
boolean Returns true after close.

tecs.io.UDPSocket:receive Instance

Takes one packet without waiting.

Returns nil with no error when no packet is ready. The packet owns its source address, which the caller closes.

function tecs.io.UDPSocket.receive(self): UDPPacket, string
Arguments
Name Type Description
self UDPSocket
Returns
Type Description
UDPPacket Returns one caller-owned complete packet, or nil when none waits or reception fails.
string Returns the reason only when reception fails.

tecs.io.UDPSocket:send Instance

Sends one packet without waiting.

function tecs.io.UDPSocket.send(
    self, address: Address, port: integer, bytes: string
): boolean, string
Arguments
Name Type Description
self UDPSocket
address Address The caller supplies an open address from this module.
port integer The caller supplies a remote port from 1 to 65535.
bytes string The caller supplies one datagram of at most 65507 bytes.
Returns
Type Description
boolean Returns true when the network accepts the complete datagram.
string Returns the reason when the first return is false.

tecs.io.UDPSocket:wait Instance

Waits up to timeoutMs for a packet.

Returns false without an error on timeout. This does not consume a packet; call receive afterwards.

function tecs.io.UDPSocket.wait(
    self, timeoutMs: integer
): boolean, string
Arguments
Name Type Description
self UDPSocket
timeoutMs integer The caller supplies 0 to 2147483647 milliseconds or omits it for zero. Zero polls without blocking.
Returns
Type Description
boolean Returns true when at least one packet waits.
string Returns the reason on failure. Timeout returns false without a reason.

tecs.io.WritableStream interface

A WritableStream opens writers and supplies whole-destination transfers.

interface tecs.io.WritableStream is Stream, Closeable
    newWriter: function(self): Writer, string
    writeAll: function(self, bytes: string): integer, string
    writeBuffer: function(
        self, buffer: Buffer, offset: integer, count: integer
    ): integer, string
    writeView: function(
        self, view: ByteView, offset: integer, count: integer
    ): integer, string
end

Interfaces

Interface
Stream
Closeable

tecs.io.WritableStream:newWriter Instance

Opens a writer with a new cursor.

Opening replaces the destination's previous bytes.

function tecs.io.WritableStream.newWriter(self): Writer, string
Arguments
Name Type Description
self WritableStream The writable descriptor.
Returns
Type Description
Writer Returns a caller-owned writer, or nil when unavailable.
string Returns the reason when the first return is nil.

Examples

local bytes <const> = tecs.io.newBuffer()
local destination <const> = bytes:newStream()
local writer <const> = assert(destination:newWriter())

assert(writer:write("data"))
assert(writer:close())
destination:close()
bytes:close()

tecs.io.WritableStream:writeAll Instance

Replaces the destination with a Lua string.

The operation opens, finishes, and closes one writer. On a non-replayable stream, this claims its one endpoint.

function tecs.io.WritableStream.writeAll(
    self, bytes: string
): integer, string
Arguments
Name Type Description
self WritableStream The writable descriptor.
bytes string The caller supplies the complete binary contents.
Returns
Type Description
integer Returns the bytes written.
string Returns the destination's reason when the first return is nil.

Examples

local destination <const> = tecs.io.newFileStream("save.bin")
local count <const> = destination:writeAll("save data")
print(count)

destination:close()

tecs.io.WritableStream:writeBuffer Instance

Replaces the destination with a buffer range.

The operation opens, finishes, and closes one writer. On a non-replayable stream, this claims its one endpoint.

function tecs.io.WritableStream.writeBuffer(
    self, buffer: Buffer, offset: integer, count: integer
): integer, string
Arguments
Name Type Description
self WritableStream The writable descriptor.
buffer Buffer The caller keeps the source buffer open and unchanged through the call.
offset integer The caller supplies a zero-based offset or omits it for zero.
count integer The caller supplies a byte count or omits it for the remainder.
Returns
Type Description
integer Returns the bytes written.
string Returns the destination's reason when the first return is nil.

Examples

local bytes <const> = tecs.io.newBuffer("save data")
local destination <const> = tecs.io.newFileStream("save.bin")
local count <const> = destination:writeBuffer(bytes)
print(count)

destination:close()
bytes:close()

tecs.io.WritableStream:writeView Instance

Replaces the destination with a retained immutable byte range.

The operation opens, finishes, and closes one writer. On a non-replayable stream, this claims its one endpoint.

The caller keeps view open through the call.

function tecs.io.WritableStream.writeView(
    self, view: ByteView, offset: integer, count: integer
): integer, string
Arguments
Name Type Description
self WritableStream The writable descriptor.
view ByteView The caller supplies an open ByteView.
offset integer The caller supplies a zero-based offset or omits it for zero.
count integer The caller supplies a byte count or omits it for the remainder.
Returns
Type Description
integer Returns the bytes written.
string Returns the destination's reason when the first return is nil.

tecs.io.Writer interface

A Writer accepts bytes in order and finishes its destination on close.

interface tecs.io.Writer is Closeable
    flush: function(self): boolean, string
    write: function(self, bytes: string): boolean, string
    writeFrom: function(
        self, source: Buffer, offset: integer, count: integer
    ): integer, string
    writeView: function(
        self, source: ByteView, offset: integer, count: integer
    ): integer, string
end

Interfaces

Interface
Closeable

tecs.io.Writer:flush Instance

Flushes buffered bytes without closing the destination.

function tecs.io.Writer.flush(self): boolean, string
Arguments
Name Type Description
self Writer The writer to flush.
Returns
Type Description
boolean Returns whether buffered bytes reached the destination.
string Returns the destination's reason when the first return is false.

Examples

local destination <const> = tecs.io.newFileStream("save.bin")
local writer <const> = assert(destination:newWriter())

assert(writer:write("checkpoint"))
assert(writer:flush())
assert(writer:close())
destination:close()

tecs.io.Writer:write Instance

Caller-writable. Supplies the operation that writes the next bytes.

function tecs.io.Writer.write(self, bytes: string): boolean, string
Arguments
Name Type Description
self Writer The writer receiving the bytes.
bytes string The binary string to append, including any embedded NUL bytes.
Returns
Type Description
boolean Returns whether every byte reached the destination.
string Returns the destination's reason when the first return is false.

Examples

local bytes <const> = tecs.io.newBuffer()
local writer <const> = bytes:newWriter()
local wrote <const>, reason = writer:write("data")

assert(wrote, reason)
assert(writer:close())
print(bytes:getString())

bytes:close()

tecs.io.Writer:writeFrom Instance

Writes a complete buffer range and advances the cursor.

function tecs.io.Writer.writeFrom(
    self, source: Buffer, offset: integer, count: integer
): integer, string
Arguments
Name Type Description
self Writer The open writer whose cursor advances.
source Buffer The caller supplies an open source buffer and retains ownership.
offset integer The caller supplies a zero-based source offset or omits it for zero.
count integer The caller supplies a byte count or omits it for the remainder.
Returns
Type Description
integer Returns the complete byte count.
string Returns the destination's reason when the first return is nil.

Examples

local source <const> = tecs.io.newBuffer("header:data")
local destination <const> = tecs.io.newBuffer()
local writer <const> = destination:newWriter()
local count <const>, reason = writer:writeFrom(source, 7, 4)

assert(count, reason)
assert(writer:close())
print(destination:getString())

source:close()
destination:close()

tecs.io.Writer:writeView Instance

Writes a complete immutable-view range and advances the cursor.

function tecs.io.Writer.writeView(
    self, source: ByteView, offset: integer, count: integer
): integer, string
Arguments
Name Type Description
self Writer The open writer whose cursor advances.
source ByteView The caller supplies an open source view and retains ownership.
offset integer The caller supplies a zero-based source offset or omits it for zero.
count integer The caller supplies a byte count or omits it for the remainder.
Returns
Type Description
integer Returns the complete byte count.
string Returns the destination's reason when the first return is nil.

Examples

local source <const> = tecs.io.newBuffer("header:data")
local view <const> = source:view(7, 4)
local destination <const> = tecs.io.newBuffer()
local writer <const> = destination:newWriter()
local count <const>, reason = writer:writeView(view)

assert(count, reason)
assert(writer:close())
print(destination:getString())

view:close()
source:close()
destination:close()

Functions

tecs.io.bind Static

Binds a UDP socket. A nil address listens on all local interfaces.

function tecs.io.bind(
    port: integer, address: Address
): UDPSocket, string

Arguments

Name Type Description
port integer The caller supplies a local port from 0 to 65535. Zero lets the platform choose one but leaves UDPSocket.port at zero.
address Address The caller supplies a local address or omits it for all interfaces.

Returns

Type Description
UDPSocket Returns a caller-owned socket, or nil on failure.
string Returns the reason when the first return is nil.

tecs.io.connect Static

Begins connecting to a resolved address.

function tecs.io.connect(
    address: Address, port: integer
): FutureType<TCPSocket>

Arguments

Name Type Description
address Address The caller supplies an address from this module. A closed address returns an already-failed future.
port integer The caller supplies a remote port from 1 to 65535.

Returns

Type Description
FutureType<TCPSocket> Returns a future over a caller-owned connection. tecs.io.poll or Future:wait settles it.

tecs.io.init Static

Starts networking for this module. Safe to call repeatedly.

resolve, connect, listen and bind start it automatically.

function tecs.io.init(): boolean, string

Arguments

None.

Returns

Type Description
boolean Returns true when networking runs.
string Returns the startup reason when the first return is false.

tecs.io.listen Static

Binds a TCP listener. A nil address listens on all local interfaces.

function tecs.io.listen(
    port: integer, address: Address
): TCPListener, string

Arguments

Name Type Description
port integer The caller supplies a local port from 0 to 65535. Zero lets the platform choose one but leaves TCPListener.port at zero.
address Address The caller supplies a local address or omits it for all interfaces.

Returns

Type Description
TCPListener Returns a caller-owned listener, or nil on failure.
string Returns the reason when the first return is nil.

Examples

local listener <const>, listenReason = tecs.io.listen(8080)

assert(listener, listenReason)
local client: tecs.io.TCPSocket = nil
local request = ""

-- Call this once per frame. It serves one HTTP/1.1 request at a time; a real
-- server keeps one request buffer per connected socket.
local function pollWebServer()
    if client == nil then
        client = listener:accept()
        return
    end

    local chunk <const>, readReason = client:read()
    if readReason ~= nil then
        client:close()
        client = nil
        request = ""
        return
    end
    if chunk == nil then
        return
    end
    request = request .. chunk
    if request:find("\r\n\r\n", 1, true) == nil then
        return
    end

    local body <const> = "Hello from Tecs\n"
    local response <const> = (
        "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n"
        .. "Content-Type: text/plain\r\nConnection: close\r\n\r\n%s"
    ):format(#body, body)
    local sent <const>, sendReason = client:write(response)
    assert(sent, sendReason)
    assert(client:drain(1000))
    client:close()
    client = nil
    request = ""
end

pollWebServer()

listener:close()

tecs.io.pending Static

Returns the number of pending resolution or connection futures.

function tecs.io.pending(): integer

Arguments

None.

Returns

Type Description
integer Returns zero after every operation settles or cancels.

tecs.io.poll Static

Advances pending I/O in a headless loop without waiting.

Application calls this automatically once per host iteration, including while suspended or crashed. A game system, plugin, or update function must not call it. Only a headless program without an application owns a manual call, normally once per loop while pending() is greater than zero.

function tecs.io.poll(): integer

Arguments

None.

Returns

Type Description
integer Returns how many resolution or connection futures settled during this call, including failures.

Examples

while tecs.io.pending() > 0 do
    tecs.io.poll()
end

tecs.io.resolve Static

Begins resolving a hostname.

function tecs.io.resolve(host: string): FutureType<Address>

Arguments

Name Type Description
host string The caller supplies a DNS name or numeric address of at most 253 bytes. Empty strings and embedded NUL bytes raise.

Returns

Type Description
FutureType<Address> Returns a future over a caller-owned address. tecs.io.poll or Future:wait settles it.

tecs.io.shutdown Static

Stops this module's networking instance.

It refuses while an address, TCP socket, listener, UDP socket, packet or asynchronous operation remains live.

function tecs.io.shutdown(): boolean, string

Arguments

None.

Returns

Type Description
boolean Returns true after shutdown or when networking never started.
string Returns the live-resource reason when shutdown refuses.

tecs.io.transfer Static

Transfers every remaining byte between directional endpoints.

Lua files satisfy the basic endpoint protocol directly. Tecs readers and writers may additionally provide readInto and writeFrom fast paths, which this call selects without changing the source code using them. The call borrows both endpoints and closes neither one.

function tecs.io.transfer(
    source: types.Reader | FILE, destination: types.Writer | FILE
): integer, string

Arguments

Name Type Description
source types.Reader | FILE The caller supplies an open reader or Lua file positioned at its first byte to transfer.
destination types.Writer | FILE The caller supplies an open writer or Lua file positioned where transferred bytes should begin.

Returns

Type Description
integer Returns the number of bytes written.
string Returns the source or destination reason when the first return is nil.

Examples

local source <const> = assert(tecs.io.files.open("save.bin"))
local destination <const> = assert(tecs.io.files.open("save.copy", "w"))
local count <const>, reason = tecs.io.transfer(source, destination)

assert(count, reason)

source:close()
destination:close()