
# tecs.io


Input, output, and nonblocking network transport.

A [`Stream`](/modules/io/#tecs.io.Stream) describes binary storage without keeping
a cursor. A [`Reader`](/modules/io/#tecs.io.Reader) and
[`Writer`](/modules/io/#tecs.io.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:

```teal
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`](/modules/Future/) values. An
[`Application`](/modules/Application/) polls [`runtime`](/modules/runtime/) once per
iteration, so a game waits on status without driving I/O itself:

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

### Constructors

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

### Types

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

### Functions

| Function | Kind | Description |
| --- | --- | --- |
| [`bind`](/modules/io/#tecs.io.bind) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Binds a UDP socket. |
| [`connect`](/modules/io/#tecs.io.connect) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Begins connecting to a resolved address. |
| [`init`](/modules/io/#tecs.io.init) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Starts networking for this module. |
| [`listen`](/modules/io/#tecs.io.listen) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Binds a TCP listener. |
| [`pending`](/modules/io/#tecs.io.pending) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Returns the number of pending resolution or connection futures. |
| [`poll`](/modules/io/#tecs.io.poll) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Advances pending I/O in a headless loop without waiting. |
| [`resolve`](/modules/io/#tecs.io.resolve) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Begins resolving a hostname. |
| [`shutdown`](/modules/io/#tecs.io.shutdown) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Stops this module's networking instance. |
| [`transfer`](/modules/io/#tecs.io.transfer) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Transfers every remaining byte between directional endpoints. |

## Constructors

<a id="tecs.io.newBase64DecodeReader"></a>
### tecs.io.newBase64DecodeReader <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Creates a reader that incrementally decodes RFC 4648 Base64 text.

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


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

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `source` | [`types.Reader`](/modules/io/#tecs.io.Reader)<code> &#124; FILE</code> | The caller supplies the reader of Base64 text. |

#### Returns

| Type | Description |
| --- | --- |
| [`types.Reader`](/modules/io/#tecs.io.Reader) | Returns a caller-owned reader of decoded bytes. |

#### Examples

```teal
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)
```

<a id="tecs.io.newBase64EncodeWriter"></a>
### tecs.io.newBase64EncodeWriter <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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.


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

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `destination` | [`types.Writer`](/modules/io/#tecs.io.Writer)<code> &#124; FILE</code> | The caller supplies the writer receiving Base64 text. |

#### Returns

| Type | Description |
| --- | --- |
| [`types.Writer`](/modules/io/#tecs.io.Writer) | Returns a caller-owned writer that accepts unencoded bytes. |

#### Examples

```teal
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)
```

<a id="tecs.io.newBuffer"></a>
### tecs.io.newBuffer <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Creates an owned growable byte buffer.



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

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `initial` | <code>integer &#124; string</code> | The caller supplies a non-negative zero-filled logical length, a string to copy, or nil for an empty buffer. |

#### Returns

| Type | Description |
| --- | --- |
| [`IOBuffer`](/modules/io/#tecs.io.Buffer) | Returns a caller-owned buffer. |

#### Examples

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

bytes:close()
```

<a id="tecs.io.newByteReader"></a>
### tecs.io.newByteReader <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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.


```teal
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`](/modules/io/#tecs.io.Reader) | Returns a caller-owned reader whose cursor starts at zero. |

#### Examples

```teal
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()
```

<a id="tecs.io.newByteStream"></a>
### tecs.io.newByteStream <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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

Closing the stream or its readers never frees the allocation.


```teal
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`](/modules/io/#tecs.io.ReadableStream) | Returns a readable stream. |

#### Examples

```teal
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()
```

<a id="tecs.io.newDeflateWriter"></a>
### tecs.io.newDeflateWriter <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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.


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

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `destination` | [`types.Writer`](/modules/io/#tecs.io.Writer)<code> &#124; FILE</code> | The caller supplies the writer receiving compressed bytes. |
| `options` | [`types.DeflateWriterOptions`](/modules/io/#tecs.io.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`](/modules/io/#tecs.io.Writer) | Returns a caller-owned writer that accepts uncompressed bytes. |

#### Examples

```teal
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)
```

<a id="tecs.io.newEmptyStream"></a>
### tecs.io.newEmptyStream <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Creates a replayable readable empty stream.



```teal
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`](/modules/io/#tecs.io.ReadableStream) | Returns a source whose length is zero. |

#### Examples

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

source:close()
```

<a id="tecs.io.newFileStream"></a>
### tecs.io.newFileStream <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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.


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

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `path` | <code>string &#124; </code>[`Path`](/modules/io/Path/) | The caller supplies the source or destination as a string or [`Path`](/modules/io/Path/). |
| `contentType` | `string` | The caller supplies optional media type metadata. |

#### Returns

| Type | Description |
| --- | --- |
| [`types.ReadWriteStream`](/modules/io/#tecs.io.ReadWriteStream) | Returns a readable and writable stream. |

#### Examples

```teal
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()
```

<a id="tecs.io.newHandleStream"></a>
### tecs.io.newHandleStream <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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.


```teal
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`](/modules/io/#tecs.io.ReadWriteStream) | Returns a non-replayable readable and writable stream. |

#### Examples

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

source:close()
handle:close()
```

<a id="tecs.io.newHexDecodeReader"></a>
### tecs.io.newHexDecodeReader <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Creates a reader that incrementally decodes hexadecimal text.

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


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

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `source` | [`types.Reader`](/modules/io/#tecs.io.Reader)<code> &#124; FILE</code> | The caller supplies the reader of hexadecimal text. |

#### Returns

| Type | Description |
| --- | --- |
| [`types.Reader`](/modules/io/#tecs.io.Reader) | Returns a caller-owned reader of decoded bytes. |

#### Examples

```teal
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)
```

<a id="tecs.io.newHexEncodeWriter"></a>
### tecs.io.newHexEncodeWriter <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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

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


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

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `destination` | [`types.Writer`](/modules/io/#tecs.io.Writer)<code> &#124; FILE</code> | The caller supplies the writer receiving hexadecimal text. |

#### Returns

| Type | Description |
| --- | --- |
| [`types.Writer`](/modules/io/#tecs.io.Writer) | Returns a caller-owned writer that accepts unencoded bytes. |

#### Examples

```teal
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)
```

<a id="tecs.io.newInflateReader"></a>
### tecs.io.newInflateReader <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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.


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

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `source` | [`types.Reader`](/modules/io/#tecs.io.Reader)<code> &#124; FILE</code> | The caller supplies the reader of compressed bytes. |
| `options` | [`types.InflateReaderOptions`](/modules/io/#tecs.io.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`](/modules/io/#tecs.io.Reader) | Returns a caller-owned reader of decompressed bytes. |

#### Examples

```teal
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)
```

<a id="tecs.io.newStringReader"></a>
### tecs.io.newStringReader <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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.


```teal
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`](/modules/io/#tecs.io.Reader) | Returns a caller-owned reader whose cursor starts at zero. |

#### Examples

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

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

reader:close()
```

<a id="tecs.io.newStringStream"></a>
### tecs.io.newStringStream <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Creates a replayable read-only string stream.

The stream retains the immutable string without copying it.


```teal
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`](/modules/io/#tecs.io.ReadableStream) | Returns a readable stream. |

#### Examples

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

source:close()
```

<a id="tecs.io.newTranscodeReader"></a>
### tecs.io.newTranscodeReader <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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.


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

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `source` | [`types.Reader`](/modules/io/#tecs.io.Reader)<code> &#124; FILE</code> | 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`](/modules/io/#tecs.io.Reader) | Returns a caller-owned reader of converted text. |

#### Examples

```teal
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)
```

<a id="tecs.io.newTranscodeWriter"></a>
### tecs.io.newTranscodeWriter <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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.


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

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `destination` | [`types.Writer`](/modules/io/#tecs.io.Writer)<code> &#124; FILE</code> | 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`](/modules/io/#tecs.io.Writer) | Returns a caller-owned writer that accepts bytes in `fromEncoding`. |

#### Examples

```teal
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

<a id="tecs.io.Address"></a>
### tecs.io.Address <span class="tealdoc-kind-badge tealdoc-kind-record">record</span>

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


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

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

#### Interfaces

| Interface |
| --- |
| [`Closeable`](/modules/#tecs.Closeable) |

<a id="tecs.io.Address.host"></a>
#### tecs.io.Address.host <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

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


```teal
tecs.io.Address.host: string
```

<a id="tecs.io.Address.text"></a>
#### tecs.io.Address.text <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

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


```teal
tecs.io.Address.text: string
```

<a id="tecs.io.Address.close"></a>
#### tecs.io.Address:close <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

```teal
function tecs.io.Address.close(self): boolean, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `Address` |  |

##### Returns

| Type | Description |
| --- | --- |
| `boolean` |  |
| `string` |  |

<a id="tecs.io.Address.isClosed"></a>
#### tecs.io.Address:isClosed <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns whether `close` has released this address.



```teal
function tecs.io.Address.isClosed(self): boolean
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `Address` |  |

##### Returns

| Type | Description |
| --- | --- |
| `boolean` | Returns true after `close`. |

<a id="tecs.io.Buffer"></a>
### tecs.io.Buffer <span class="tealdoc-kind-badge tealdoc-kind-interface">interface</span>

A `Buffer` is owned growable FFI-backed byte storage.


```teal
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`](/modules/#tecs.Closeable) |

<a id="tecs.io.Buffer.WriteRange"></a>
#### tecs.io.Buffer.WriteRange <span class="tealdoc-kind-badge tealdoc-kind-interface">interface</span>

An exclusive, zero-copy writable range reserved from a [`Buffer`](/modules/io/#tecs.io.Buffer).
Closing abandons the range without changing the buffer's logical length.


```teal
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`](/modules/#tecs.Closeable) |

<a id="tecs.io.Buffer.WriteRange.capacity"></a>
##### tecs.io.Buffer.WriteRange:capacity <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the maximum byte count the native writer may fill.



```teal
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. |

<a id="tecs.io.Buffer.WriteRange.commit"></a>
##### tecs.io.Buffer.WriteRange:commit <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Commits bytes written through the borrowed pointer.

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


```teal
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.

<a id="tecs.io.Buffer.WriteRange.getFFIPointer"></a>
##### tecs.io.Buffer.WriteRange:getFFIPointer <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Borrows the reserved range's writable address.



```teal
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`. |

<a id="tecs.io.Buffer.capacity"></a>
#### tecs.io.Buffer:capacity <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the allocated byte capacity.



```teal
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

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

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

bytes:close()
```

<a id="tecs.io.Buffer.clear"></a>
#### tecs.io.Buffer:clear <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Removes every logical byte without releasing the allocation.



```teal
function tecs.io.Buffer.clear(self)
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `Buffer` | The buffer to clear. |

##### Returns

None.

#### Examples

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

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

bytes:close()
```

<a id="tecs.io.Buffer.ensureCapacity"></a>
#### tecs.io.Buffer:ensureCapacity <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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

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

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

bytes:close()
```

<a id="tecs.io.Buffer.getFFIPointer"></a>
#### tecs.io.Buffer:getFFIPointer <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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

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

bytes:close()
```

<a id="tecs.io.Buffer.getString"></a>
#### tecs.io.Buffer:getString <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Copies a range into a Lua string.



```teal
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

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

bytes:close()
```

<a id="tecs.io.Buffer.isReleased"></a>
#### tecs.io.Buffer:isReleased <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns whether `close` has given up the allocation.



```teal
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

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

assert(not bytes:isReleased())

bytes:close()

assert(bytes:isReleased())
```

<a id="tecs.io.Buffer.length"></a>
#### tecs.io.Buffer:length <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the number of logical bytes.



```teal
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

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

bytes:close()
```

<a id="tecs.io.Buffer.newReader"></a>
#### tecs.io.Buffer:newReader <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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

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

bytes:close()

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

reader:close()
```

<a id="tecs.io.Buffer.newStream"></a>
#### tecs.io.Buffer:newStream <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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

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

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

stream:close()
bytes:close()
```

<a id="tecs.io.Buffer.newWriter"></a>
#### tecs.io.Buffer:newWriter <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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

```teal
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()
```

<a id="tecs.io.Buffer.reserveRange"></a>
#### tecs.io.Buffer:reserveRange <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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

The buffer detaches from retained views before exposing mutable
storage.


```teal
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`](/modules/io/#tecs.io.Buffer.WriteRange) | Returns a caller-owned exclusive range. |

<a id="tecs.io.Buffer.resize"></a>
#### tecs.io.Buffer:resize <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Changes the logical length.

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


```teal
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

```teal
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()
```

<a id="tecs.io.Buffer.setString"></a>
#### tecs.io.Buffer:setString <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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

```teal
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()
```

<a id="tecs.io.Buffer.view"></a>
#### tecs.io.Buffer:view <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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



```teal
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`](/modules/io/#tecs.io.ByteView) | Returns a caller-owned retained view. |

<a id="tecs.io.ByteView"></a>
### tecs.io.ByteView <span class="tealdoc-kind-badge tealdoc-kind-interface">interface</span>

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


```teal
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`](/modules/#tecs.Closeable) |

<a id="tecs.io.ByteView.getFFIPointer"></a>
#### tecs.io.ByteView:getFFIPointer <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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`. |

<a id="tecs.io.ByteView.getString"></a>
#### tecs.io.ByteView:getString <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Copies the retained range into a Lua string.



```teal
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. |

<a id="tecs.io.ByteView.isReleased"></a>
#### tecs.io.ByteView:isReleased <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns whether the view has released its retained allocation.



```teal
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`. |

<a id="tecs.io.ByteView.length"></a>
#### tecs.io.ByteView:length <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the retained range's byte length.



```teal
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. |

<a id="tecs.io.ByteView.newReader"></a>
#### tecs.io.ByteView:newReader <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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

```teal
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()
```

<a id="tecs.io.ByteView.newStream"></a>
#### tecs.io.ByteView:newStream <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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

```teal
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()
```

<a id="tecs.io.ByteView.view"></a>
#### tecs.io.ByteView:view <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Retains a zero-copy subrange.



```teal
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`](/modules/io/#tecs.io.ByteView) | Returns a caller-owned view retaining the same allocation. |

<a id="tecs.io.DeflateWriterOptions"></a>
### tecs.io.DeflateWriterOptions <span class="tealdoc-kind-badge tealdoc-kind-record">record</span>

Options control an incremental deflate writer.


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

<a id="tecs.io.DeflateWriterOptions.raw"></a>
#### tecs.io.DeflateWriterOptions.raw <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

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


```teal
tecs.io.DeflateWriterOptions.raw: boolean
```

<a id="tecs.io.DeflateWriterOptions.level"></a>
#### tecs.io.DeflateWriterOptions.level <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

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


```teal
tecs.io.DeflateWriterOptions.level: integer
```

<a id="tecs.io.InflateReaderOptions"></a>
### tecs.io.InflateReaderOptions <span class="tealdoc-kind-badge tealdoc-kind-record">record</span>

Options control an incremental inflate reader.


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

<a id="tecs.io.InflateReaderOptions.raw"></a>
#### tecs.io.InflateReaderOptions.raw <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

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


```teal
tecs.io.InflateReaderOptions.raw: boolean
```

<a id="tecs.io.InflateReaderOptions.maxBytes"></a>
#### tecs.io.InflateReaderOptions.maxBytes <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

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


```teal
tecs.io.InflateReaderOptions.maxBytes: integer
```

<a id="tecs.io.ReadableStream"></a>
### tecs.io.ReadableStream <span class="tealdoc-kind-badge tealdoc-kind-interface">interface</span>

A `ReadableStream` opens readers and supplies whole-source transfers.


```teal
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`](/modules/io/#tecs.io.Stream) |
| [`Closeable`](/modules/#tecs.Closeable) |

<a id="tecs.io.ReadableStream.discard"></a>
#### tecs.io.ReadableStream:discard <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Reads and discards every source byte.

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



```teal
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

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

source:close()
```

<a id="tecs.io.ReadableStream.newReader"></a>
#### tecs.io.ReadableStream:newReader <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Opens a reader with a new cursor.



```teal
function tecs.io.ReadableStream.newReader(self): Reader, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `ReadableStream` | The readable descriptor. |

##### Returns

| Type | Description |
| --- | --- |
| [`Reader`](/modules/io/#tecs.io.Reader) | Returns a caller-owned reader, or nil when unavailable. |
| `string` | Returns the reason when the first return is nil. |

#### Examples

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

reader:close()
source:close()
```

<a id="tecs.io.ReadableStream.readAll"></a>
#### tecs.io.ReadableStream:readAll <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.



```teal
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

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

source:close()
```

<a id="tecs.io.ReadableStream.transferTo"></a>
#### tecs.io.ReadableStream:transferTo <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.



```teal
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

```teal
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()
```

<a id="tecs.io.ReadableStream.transferToBuffer"></a>
#### tecs.io.ReadableStream:transferToBuffer <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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`](/modules/io/#tecs.io.Buffer) | Returns a caller-owned buffer. |
| `string` | Returns the source's reason when the first return is nil. |

#### Examples

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

bytes:close()
source:close()
```

<a id="tecs.io.ReadableStream.transferToFile"></a>
#### tecs.io.ReadableStream:transferToFile <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.



```teal
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

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

source:close()
```

<a id="tecs.io.Reader"></a>
### tecs.io.Reader <span class="tealdoc-kind-badge tealdoc-kind-interface">interface</span>

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


```teal
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`](/modules/#tecs.Closeable) |

<a id="tecs.io.Reader.read"></a>
#### tecs.io.Reader:read <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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



```teal
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

```teal
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()
```

<a id="tecs.io.Reader.readInto"></a>
#### tecs.io.Reader:readInto <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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`](/modules/io/#tecs.io.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

```teal
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()
```

<a id="tecs.io.ReadWriteStream"></a>
### tecs.io.ReadWriteStream <span class="tealdoc-kind-badge tealdoc-kind-interface">interface</span>

A `ReadWriteStream` supports both directional interfaces.


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

#### Interfaces

| Interface |
| --- |
| [`ReadableStream`](/modules/io/#tecs.io.ReadableStream) |
| [`Stream`](/modules/io/#tecs.io.Stream) |
| [`Closeable`](/modules/#tecs.Closeable) |
| [`WritableStream`](/modules/io/#tecs.io.WritableStream) |

<a id="tecs.io.Seekable"></a>
### tecs.io.Seekable <span class="tealdoc-kind-badge tealdoc-kind-interface">interface</span>

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


```teal
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
```

<a id="tecs.io.Seekable.Origin"></a>
#### tecs.io.Seekable.Origin <span class="tealdoc-kind-badge tealdoc-kind-enum">enum</span>

`Origin` selects the reference point for a seek.


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

<a id="tecs.io.Seekable.seek"></a>
#### tecs.io.Seekable:seek <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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`](/modules/io/#tecs.io.Seekable.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. |

<a id="tecs.io.Seekable.size"></a>
#### tecs.io.Seekable:size <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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. |

<a id="tecs.io.Seekable.tell"></a>
#### tecs.io.Seekable:tell <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the current zero-based cursor position.



```teal
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. |

<a id="tecs.io.SeekableReader"></a>
### tecs.io.SeekableReader <span class="tealdoc-kind-badge tealdoc-kind-interface">interface</span>

A `SeekableReader` supplies bytes
through a repositionable cursor.


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

#### Interfaces

| Interface |
| --- |
| [`Reader`](/modules/io/#tecs.io.Reader) |
| [`Closeable`](/modules/#tecs.Closeable) |
| [`Seekable`](/modules/io/#tecs.io.Seekable) |

<a id="tecs.io.SeekableWriter"></a>
### tecs.io.SeekableWriter <span class="tealdoc-kind-badge tealdoc-kind-interface">interface</span>

A `SeekableWriter` patches a
destination through a repositionable cursor.


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

#### Interfaces

| Interface |
| --- |
| [`Writer`](/modules/io/#tecs.io.Writer) |
| [`Closeable`](/modules/#tecs.Closeable) |
| [`Seekable`](/modules/io/#tecs.io.Seekable) |

<a id="tecs.io.Stream"></a>
### tecs.io.Stream <span class="tealdoc-kind-badge tealdoc-kind-interface">interface</span>

A `Stream` describes binary storage without retaining a cursor.


```teal
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`](/modules/#tecs.Closeable) |

<a id="tecs.io.Stream.contentLength"></a>
#### tecs.io.Stream:contentLength <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the byte length when it is known.



```teal
function tecs.io.Stream.contentLength(self): integer | nil
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `Stream` | The descriptor to inspect. |

##### Returns

| Type | Description |
| --- | --- |
| <code>integer &#124; nil</code> | Returns the current byte length, or nil when it cannot be known before reading. |

#### Examples

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

source:close()
```

<a id="tecs.io.Stream.contentType"></a>
#### tecs.io.Stream:contentType <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns the media type supplied at construction.



```teal
function tecs.io.Stream.contentType(self): string | nil
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `Stream` | The descriptor to inspect. |

##### Returns

| Type | Description |
| --- | --- |
| <code>string &#124; nil</code> | Returns the media type, or nil when none was supplied. |

#### Examples

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

source:close()
```

<a id="tecs.io.Stream.isReadable"></a>
#### tecs.io.Stream:isReadable <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns whether the descriptor can open a reader.



```teal
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

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

source:close()
```

<a id="tecs.io.Stream.isReplayable"></a>
#### tecs.io.Stream:isReplayable <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.



```teal
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

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

source:close()
```

<a id="tecs.io.Stream.isWritable"></a>
#### tecs.io.Stream:isWritable <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns whether the descriptor can open a writer.



```teal
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

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

save:close()
```

<a id="tecs.io.Stream.withMetadata"></a>
#### tecs.io.Stream:withMetadata <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
function tecs.io.Stream.withMetadata<T is Stream>(
    self,
    contentType: string,
    contentLength: integer,
    isReplayable: boolean
): T
```

##### Type Parameters

| Name | Constraint | Description |
| --- | --- | --- |
| `T` | [`Stream`](/modules/io/#tecs.io.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

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

json:close()
```

<a id="tecs.io.TCPListener"></a>
### tecs.io.TCPListener <span class="tealdoc-kind-badge tealdoc-kind-record">record</span>

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


```teal
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`](/modules/#tecs.Closeable) |

<a id="tecs.io.TCPListener.port"></a>
#### tecs.io.TCPListener.port <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

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


```teal
tecs.io.TCPListener.port: integer
```

<a id="tecs.io.TCPListener.accept"></a>
#### tecs.io.TCPListener:accept <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Takes one pending client without waiting.

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


```teal
function tecs.io.TCPListener.accept(self): TCPSocket, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `TCPListener` |  |

##### Returns

| Type | Description |
| --- | --- |
| [`TCPSocket`](/modules/io/#tecs.io.TCPSocket) | Returns one caller-owned client, or nil when none waits or acceptance fails. |
| `string` | Returns the reason only when acceptance fails. |

<a id="tecs.io.TCPListener.close"></a>
#### tecs.io.TCPListener:close <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

```teal
function tecs.io.TCPListener.close(self): boolean, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `TCPListener` |  |

##### Returns

| Type | Description |
| --- | --- |
| `boolean` |  |
| `string` |  |

<a id="tecs.io.TCPListener.isClosed"></a>
#### tecs.io.TCPListener:isClosed <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns whether `close` has released this listener.



```teal
function tecs.io.TCPListener.isClosed(self): boolean
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `TCPListener` |  |

##### Returns

| Type | Description |
| --- | --- |
| `boolean` | Returns true after `close`. |

<a id="tecs.io.TCPListener.wait"></a>
#### tecs.io.TCPListener:wait <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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. |

<a id="tecs.io.TCPSocket"></a>
### tecs.io.TCPSocket <span class="tealdoc-kind-badge tealdoc-kind-record">record</span>

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.


```teal
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`](/modules/#tecs.Closeable) |

<a id="tecs.io.TCPSocket.close"></a>
#### tecs.io.TCPSocket:close <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

```teal
function tecs.io.TCPSocket.close(self): boolean, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `TCPSocket` |  |

##### Returns

| Type | Description |
| --- | --- |
| `boolean` |  |
| `string` |  |

<a id="tecs.io.TCPSocket.drain"></a>
#### tecs.io.TCPSocket:drain <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Waits up to `timeoutMs` for queued writes to be sent.

Returns false without an error on timeout.


```teal
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. |

<a id="tecs.io.TCPSocket.isClosed"></a>
#### tecs.io.TCPSocket:isClosed <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns whether `close` has released this connection.



```teal
function tecs.io.TCPSocket.isClosed(self): boolean
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `TCPSocket` |  |

##### Returns

| Type | Description |
| --- | --- |
| `boolean` | Returns true after `close`. |

<a id="tecs.io.TCPSocket.peer"></a>
#### tecs.io.TCPSocket:peer <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns a newly owned address for the remote peer.

The caller closes the returned address.


```teal
function tecs.io.TCPSocket.peer(self): Address, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `TCPSocket` |  |

##### Returns

| Type | Description |
| --- | --- |
| [`Address`](/modules/io/#tecs.io.Address) | Returns a caller-owned address that outlives the connection, or nil on failure. |
| `string` | Returns the reason when the first return is nil. |

<a id="tecs.io.TCPSocket.pendingWrites"></a>
#### tecs.io.TCPSocket:pendingWrites <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns bytes accepted but not yet sent.



```teal
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. |

<a id="tecs.io.TCPSocket.read"></a>
#### tecs.io.TCPSocket:read <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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. |

<a id="tecs.io.TCPSocket.readInto"></a>
#### tecs.io.TCPSocket:readInto <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
function tecs.io.TCPSocket.readInto(
    self, destination: IOBuffer, offset: integer, maxBytes: integer
): integer, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `TCPSocket` |  |
| `destination` | [`IOBuffer`](/modules/io/#tecs.io.Buffer) | The caller supplies an open [`Buffer`](/modules/io/#tecs.io.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. |

<a id="tecs.io.TCPSocket.wait"></a>
#### tecs.io.TCPSocket:wait <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Waits up to `timeoutMs` for input or disconnection.

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


```teal
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. |

<a id="tecs.io.TCPSocket.write"></a>
#### tecs.io.TCPSocket:write <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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. |

<a id="tecs.io.TCPSocket.writeFrom"></a>
#### tecs.io.TCPSocket:writeFrom <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
function tecs.io.TCPSocket.writeFrom(
    self, source: IOBuffer, offset: integer, count: integer
): integer, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `TCPSocket` |  |
| `source` | [`IOBuffer`](/modules/io/#tecs.io.Buffer) | The caller supplies an open [`Buffer`](/modules/io/#tecs.io.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. |

<a id="tecs.io.TCPSocket.writeView"></a>
#### tecs.io.TCPSocket:writeView <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Queues a retained byte view without constructing an intermediate string.

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


```teal
function tecs.io.TCPSocket.writeView(
    self, source: types.ByteView, offset: integer, count: integer
): integer, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `TCPSocket` |  |
| `source` | [`types.ByteView`](/modules/io/#tecs.io.ByteView) | The caller supplies an open [`ByteView`](/modules/io/#tecs.io.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. |

<a id="tecs.io.UDPPacket"></a>
### tecs.io.UDPPacket <span class="tealdoc-kind-badge tealdoc-kind-record">record</span>

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.


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

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

#### Interfaces

| Interface |
| --- |
| [`Closeable`](/modules/#tecs.Closeable) |

<a id="tecs.io.UDPPacket.address"></a>
#### tecs.io.UDPPacket.address <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

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


```teal
tecs.io.UDPPacket.address: Address
```

<a id="tecs.io.UDPPacket.port"></a>
#### tecs.io.UDPPacket.port <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

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


```teal
tecs.io.UDPPacket.port: integer
```

<a id="tecs.io.UDPPacket.bytes"></a>
#### tecs.io.UDPPacket.bytes <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

Read-only. Networking sets `bytes` to one caller-owned
[`Buffer`](/modules/io/#tecs.io.Buffer) containing the complete
datagram. A zero-length datagram uses an empty buffer. `close`
releases it.


```teal
tecs.io.UDPPacket.bytes: IOBuffer
```

<a id="tecs.io.UDPPacket.close"></a>
#### tecs.io.UDPPacket:close <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

```teal
function tecs.io.UDPPacket.close(self): boolean, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `UDPPacket` |  |

##### Returns

| Type | Description |
| --- | --- |
| `boolean` |  |
| `string` |  |

<a id="tecs.io.UDPSocket"></a>
### tecs.io.UDPSocket <span class="tealdoc-kind-badge tealdoc-kind-record">record</span>

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


```teal
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`](/modules/#tecs.Closeable) |

<a id="tecs.io.UDPSocket.port"></a>
#### tecs.io.UDPSocket.port <span class="tealdoc-kind-badge tealdoc-kind-field">field</span>

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


```teal
tecs.io.UDPSocket.port: integer
```

<a id="tecs.io.UDPSocket.close"></a>
#### tecs.io.UDPSocket:close <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

```teal
function tecs.io.UDPSocket.close(self): boolean, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `UDPSocket` |  |

##### Returns

| Type | Description |
| --- | --- |
| `boolean` |  |
| `string` |  |

<a id="tecs.io.UDPSocket.isClosed"></a>
#### tecs.io.UDPSocket:isClosed <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Returns whether `close` has released this socket.



```teal
function tecs.io.UDPSocket.isClosed(self): boolean
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `UDPSocket` |  |

##### Returns

| Type | Description |
| --- | --- |
| `boolean` | Returns true after `close`. |

<a id="tecs.io.UDPSocket.receive"></a>
#### tecs.io.UDPSocket:receive <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
function tecs.io.UDPSocket.receive(self): UDPPacket, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `UDPSocket` |  |

##### Returns

| Type | Description |
| --- | --- |
| [`UDPPacket`](/modules/io/#tecs.io.UDPPacket) | Returns one caller-owned complete packet, or nil when none waits or reception fails. |
| `string` | Returns the reason only when reception fails. |

<a id="tecs.io.UDPSocket.send"></a>
#### tecs.io.UDPSocket:send <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Sends one packet without waiting.


```teal
function tecs.io.UDPSocket.send(
    self, address: Address, port: integer, bytes: string
): boolean, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `UDPSocket` |  |
| `address` | [`Address`](/modules/io/#tecs.io.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. |

<a id="tecs.io.UDPSocket.wait"></a>
#### tecs.io.UDPSocket:wait <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Waits up to `timeoutMs` for a packet.

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


```teal
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. |

<a id="tecs.io.WritableStream"></a>
### tecs.io.WritableStream <span class="tealdoc-kind-badge tealdoc-kind-interface">interface</span>

A `WritableStream` opens writers and supplies whole-destination
transfers.


```teal
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`](/modules/io/#tecs.io.Stream) |
| [`Closeable`](/modules/#tecs.Closeable) |

<a id="tecs.io.WritableStream.newWriter"></a>
#### tecs.io.WritableStream:newWriter <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Opens a writer with a new cursor.

Opening replaces the destination's previous bytes.


```teal
function tecs.io.WritableStream.newWriter(self): Writer, string
```

##### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `self` | `WritableStream` | The writable descriptor. |

##### Returns

| Type | Description |
| --- | --- |
| [`Writer`](/modules/io/#tecs.io.Writer) | Returns a caller-owned writer, or nil when unavailable. |
| `string` | Returns the reason when the first return is nil. |

#### Examples

```teal
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()
```

<a id="tecs.io.WritableStream.writeAll"></a>
#### tecs.io.WritableStream:writeAll <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.



```teal
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

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

destination:close()
```

<a id="tecs.io.WritableStream.writeBuffer"></a>
#### tecs.io.WritableStream:writeBuffer <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.



```teal
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`](/modules/io/#tecs.io.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

```teal
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()
```

<a id="tecs.io.WritableStream.writeView"></a>
#### tecs.io.WritableStream:writeView <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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.


```teal
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`](/modules/io/#tecs.io.ByteView) | The caller supplies an open [`ByteView`](/modules/io/#tecs.io.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. |

<a id="tecs.io.Writer"></a>
### tecs.io.Writer <span class="tealdoc-kind-badge tealdoc-kind-interface">interface</span>

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


```teal
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`](/modules/#tecs.Closeable) |

<a id="tecs.io.Writer.flush"></a>
#### tecs.io.Writer:flush <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Flushes buffered bytes without closing the destination.



```teal
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

```teal
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()
```

<a id="tecs.io.Writer.write"></a>
#### tecs.io.Writer:write <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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



```teal
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

```teal
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()
```

<a id="tecs.io.Writer.writeFrom"></a>
#### tecs.io.Writer:writeFrom <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

Writes a complete buffer range and advances the cursor.



```teal
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`](/modules/io/#tecs.io.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

```teal
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()
```

<a id="tecs.io.Writer.writeView"></a>
#### tecs.io.Writer:writeView <span class="tealdoc-kind-badge tealdoc-kind-instance">Instance</span>

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



```teal
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`](/modules/io/#tecs.io.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

```teal
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

<a id="tecs.io.bind"></a>
### tecs.io.bind <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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


```teal
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`](/modules/io/#tecs.io.Address) | The caller supplies a local address or omits it for all interfaces. |

#### Returns

| Type | Description |
| --- | --- |
| [`UDPSocket`](/modules/io/#tecs.io.UDPSocket) | Returns a caller-owned socket, or nil on failure. |
| `string` | Returns the reason when the first return is nil. |

<a id="tecs.io.connect"></a>
### tecs.io.connect <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Begins connecting to a resolved address.


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

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `address` | [`Address`](/modules/io/#tecs.io.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`](/modules/Future/)`<`[`TCPSocket`](/modules/io/#tecs.io.TCPSocket)`>` | Returns a future over a caller-owned connection. `tecs.io.poll` or `Future:wait` settles it. |

<a id="tecs.io.init"></a>
### tecs.io.init <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Starts networking for this module. Safe to call repeatedly.

`resolve`, `connect`, `listen` and `bind` start it automatically.



```teal
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. |

<a id="tecs.io.listen"></a>
### tecs.io.listen <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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


```teal
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`](/modules/io/#tecs.io.Address) | The caller supplies a local address or omits it for all interfaces. |

#### Returns

| Type | Description |
| --- | --- |
| [`TCPListener`](/modules/io/#tecs.io.TCPListener) | Returns a caller-owned listener, or nil on failure. |
| `string` | Returns the reason when the first return is nil. |

#### Examples

```teal
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()
```

<a id="tecs.io.pending"></a>
### tecs.io.pending <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Returns the number of pending resolution or connection futures.



```teal
function tecs.io.pending(): integer
```

#### Arguments

None.

#### Returns

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

<a id="tecs.io.poll"></a>
### tecs.io.poll <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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

[`Application`](/modules/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.


```teal
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

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

<a id="tecs.io.resolve"></a>
### tecs.io.resolve <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Begins resolving a hostname.


```teal
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`](/modules/Future/)`<`[`Address`](/modules/io/#tecs.io.Address)`>` | Returns a future over a caller-owned address. `tecs.io.poll` or `Future:wait` settles it. |

<a id="tecs.io.shutdown"></a>
### tecs.io.shutdown <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Stops this module's networking instance.

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



```teal
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. |

<a id="tecs.io.transfer"></a>
### tecs.io.transfer <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

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.


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

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `source` | [`types.Reader`](/modules/io/#tecs.io.Reader)<code> &#124; FILE</code> | The caller supplies an open reader or Lua file positioned at its first byte to transfer. |
| `destination` | [`types.Writer`](/modules/io/#tecs.io.Writer)<code> &#124; FILE</code> | 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

```teal
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()
```