Landin library reference source

core/io

Shared: available on every enabled target.

Reader, writer, file and process capabilities, their world composition, and an in-memory provider.

Use the smallest concept a consumer needs. An erased world can lend writer_of to a writer-only consumer. Providers retain authority over handles and arguments. Byte-path helpers terminate paths in caller scratch before invoking file operations; memory keeps all storage with the caller.

Items

Executable example

This complete program is maintained in the repository runtime tests. View source.

import core/io

exercise: () -> (ok: bool) ! io.empty_path | io.path_contains_nul | io.path_too_long =
    ok = false
    source: [2]u8 = [65, 66]
    mut scratch: [3]u8 = zeroed
    terminated := try io.terminate_path(source[0..<2], scratch[0..<3])
    return when terminated.val <> 65 or scratch[2] <> 0
    _ = io.terminate_path(source[0..<2], scratch[0..<1]) else (problem)
        ok = problem == io.path_too_long and scratch[0] == 65
        return
    end
end exercise

public main: () -> (code: i32) =
    code = 1
    ok := exercise() else false
    if ok then
        code = 42
    end if
end main

files concept

public files: type = concept (provider: type)
    --- Open a NUL-terminated path for reading; return a handle owned by this
    --- provider.
    open_read: (self: ptr mut provider, path: ptr u8)
               -> (opened: file) ! not_found | no_access | io_failed
    --- Open a NUL-terminated path for writing; creation and truncation follow
    --- the provider contract.
    open_write: (self: ptr mut provider, path: ptr u8)
                -> (opened: file) ! not_found | no_access | io_failed
    --- Compare file identity for two NUL-terminated paths.
    same_file: (self: ptr mut provider, left: ptr u8, right: ptr u8)
               -> (same: bool) ! io_failed
    --- Consume a file handle, including when closure reports a failure.
    close: (self: ptr mut provider, sink opened: file)
           -> none ! io_failed
end files

core/io/io.ldn:75

File lifecycle and identity capability. Path pointers must be readable through a terminating NUL. A successful open returns a provider-specific handle; close consumes the handle even when reporting failure.

process concept

public process: type = concept (provider: type)
    --- Return the standard-output handle.
    out: (self: ptr provider) -> (stream: file)
    --- Return the standard-error handle.
    err: (self: ptr provider) -> (stream: file)
    --- Return the count of available arguments.
    argument_count: (self: ptr provider) -> (count: usize)
    --- Lend an argument by index; the provider retains its backing. Report
    --- no_argument when out of range.
    argument: (self: ptr provider, index: usize)
              -> (value: argument from self) ! no_argument
end process

core/io/io.ldn:95

Standard streams and argument access. Returned argument storage belongs to the provider; stream identifiers have provider-specific lifetime and closing rules.

reader concept

public reader: type = concept (provider: type)
    --- Read at most the destination length and return progress; zero is end
    --- of input.
    read: (self: ptr mut provider, opened: file, into: []mut u8)
          -> (count: usize) ! io_failed
end reader

core/io/io.ldn:65

Input capability. read fills at most the supplied slice and returns its byte count; zero denotes end of input. The caller retains the destination storage.

world concept

public world: type = concept (provider: type) is reader, writer, files, process
end world

core/io/io.ldn:110

Composition of reader, writer, files and process over one provider type. Consumers should request the narrowest capability they use.

writer concept

public writer: type = concept (provider: type)
    --- Write the entire byte slice or fail. Failure may follow partial
    --- output; do not blindly retry the whole slice.
    write: (self: ptr mut provider, opened: file, bytes: []u8)
           -> none ! io_failed
    --- Attempt one transfer. Nonempty success returns positive progress,
    --- empty success returns zero, and failure transfers no bytes.
    write_some: (self: ptr mut provider, opened: file, bytes: []u8)
                -> (count: usize) ! io_failed
end writer

core/io/io.ldn:51

Output capability with complete and partial writes. write completes all bytes or fails; failure may follow partial output. write_some reports positive progress for nonempty input, zero for empty input, and no progress on failure.

The capability is four narrow concepts over one provider type, so a provider supplies only what it has: a UART is a writer, a read-only image is a reader; system and memory providers also supply files and process entries. A consumer names the narrowest concept it uses; diagnostics stream through any io.writer. world composes all four for roots that have everything. An erased any io.world dispatches every entry, but it is not an any io.writer: build that from the same provider pointer where a writer is wanted [D268].

argument type

public argument: type = struct
    data: ptr u8
    length: usize
end argument

core/io/io.ldn:33

A borrowed pointer and byte length for one process argument. The provider owns its lifetime; use copy_argument for a checked copy into caller storage.

file type

public file: type = file_value

core/io/io.ldn:28

Provider-defined file identifier. Use a handle only with the provider that created it and obey that provider's close rules.

lent_writer type

public lent_writer: type = lent

core/io/io.ldn:121

Adapter retaining an erased world's reference and forwarding the two writer entries.

memory type

public memory: type = struct
    files: []mut memory_file
    arguments: []argument
    output: []mut u8
    errors: []mut u8
    output_used: usize
    errors_used: usize
    output_open: bool
    errors_open: bool
    read_limit: usize
    write_limit: usize
    fail_read_at: usize
    fail_write_at: usize
    fail_close_at: usize
    read_calls: usize
    write_calls: usize
    close_calls: usize
    open_calls: usize
end memory

core/io/memory.ldn:21

In-memory world using caller-owned file slots, output buffers and argument records. No host handles or implicit allocator are used.

memory_file type

public memory_file: type = struct
    name: []u8
    contents: []mut u8
    length: usize
    cursor: usize
    readable: bool
    writable: bool
    opened: bool
    writing: bool
end memory_file

core/io/memory.ldn:8

Caller-supplied in-memory file slot holding its path, readable bytes and writable capacity. Keep all referenced ranges alive and initialize the fields before constructing the provider.

Finite caller-backed provider of every io concept. Handles are indexes, not ownership tokens. Clients preserve length <= capacity and supply all retained backing.

argument_too_long atom

public argument_too_long: atom

core/io/io.ldn:16

The caller's scratch buffer cannot hold all argument bytes.

empty_path atom

public empty_path: atom

core/io/io.ldn:18

The path has no bytes before its terminator.

io_failed atom

public io_failed: atom

core/io/io.ldn:12

An I/O operation failed. Provider-specific diagnostic detail, if offered, must be read from that provider.

no_access atom

public no_access: atom

core/io/io.ldn:9

The provider refused access to the requested file.

no_argument atom

public no_argument: atom

core/io/io.ldn:14

The argument index does not identify an available argument.

not_found atom

public not_found: atom

core/io/io.ldn:7

The requested file or path could not be found by the provider.

path_contains_nul atom

public path_contains_nul: atom

core/io/io.ldn:20

The supplied path bytes contain an embedded NUL.

path_too_long atom

public path_too_long: atom

core/io/io.ldn:22

The scratch buffer cannot hold the path and its terminating NUL.

argument_at function

public argument_at: (provider: type is process, state: ptr provider,
                     index: usize)
                    -> (value: argument from state) ! no_argument

core/io/io.ldn:215

Lend the indexed process argument. Reports no_argument for an invalid index; the provider's argument backing must outlive its use.

argument_count function

public argument_count: (provider: type is process, state: provider)
                       -> (count: usize)

core/io/io.ldn:208

Return the number of argument entries exposed by the provider.

close function

public close: (provider: type is files, inout state: provider,
               sink opened: file) -> none ! io_failed

core/io/io.ldn:169

Close a provider handle. Treat it as consumed even if closing reports io_failed; do not retry a consumed handle.

copy_argument function

public copy_argument: (source: argument, scratch: []mut u8)
                      -> (bytes: []u8 from scratch) ! argument_too_long

core/io/io.ldn:230

Copy an argument into caller scratch and lend the written prefix. Reports argument_too_long before any write when capacity is insufficient.

An argument is a foreign-shaped pointer and length, not a slice. Copy it into genuine caller-owned initialized storage before passing its bytes to ordinary slice APIs. Exact capacity is sufficient and failure precedes every write. The caller keeps the source extent readable and disjoint from scratch, with representable address arithmetic, for the duration of the copy.

err function

public err: (provider: type is process, state: provider) -> (stream: file)

core/io/io.ldn:203

Return the provider's standard-error identifier.

memory_over function

public memory_over: (files: []mut memory_file,
                     arguments: []argument,
                     output: []mut u8, errors: []mut u8)
                    -> (state: memory from files, arguments, output, errors)

core/io/memory.ldn:44

Create an in-memory world over the supplied records and buffers. Retains their references; keep them alive and avoid conflicting access for the world's lifetime.

open_read function

public open_read: (provider: type is files, inout state: provider,
                   path: ptr u8)
                  -> (opened: file) ! not_found | no_access | io_failed

core/io/io.ldn:144

Open a terminated path for reading through files evidence. The caller must close a successful handle using the same provider.

open_read_bytes function

public open_read_bytes: (provider: type is files, inout state: provider,
                         path: []u8, scratch: []mut u8)
                        -> (opened: file)
                        ! empty_path | path_contains_nul | path_too_long
                        | not_found | no_access | io_failed

core/io/io.ldn:281

Terminate a byte path in caller scratch, then open it for reading. Path-validation failures occur before the provider is called.

open_read_text function

public open_read_text: (provider: type is files, inout state: provider,
                        path: utf8, scratch: []mut u8)
                       -> (opened: file)
                       ! empty_path | path_contains_nul | path_too_long
                       | not_found | no_access | io_failed

core/io/io.ldn:307

Open a UTF-8 path for reading using caller scratch for the terminator. Delegates to the byte-path adapter; UTF-8 does not excuse embedded NUL.

UTF-8 paths remain ordinary immutable, source-derived views. Conversion to bytes does not allocate or invent a terminator; the same caller-owned scratch and validation policy as the byte adapters applies.

open_write function

public open_write: (provider: type is files, inout state: provider,
                    path: ptr u8)
                   -> (opened: file) ! not_found | no_access | io_failed

core/io/io.ldn:153

Open a terminated path for writing through files evidence. Creation and truncation behavior belongs to the provider; close a successful handle through that provider.

open_write_bytes function

public open_write_bytes: (provider: type is files, inout state: provider,
                          path: []u8, scratch: []mut u8)
                         -> (opened: file)
                         ! empty_path | path_contains_nul | path_too_long
                         | not_found | no_access | io_failed

core/io/io.ldn:292

Terminate a byte path in caller scratch, then open it for writing. Path validation and provider failures remain distinct.

open_write_text function

public open_write_text: (provider: type is files, inout state: provider,
                         path: utf8, scratch: []mut u8)
                        -> (opened: file)
                        ! empty_path | path_contains_nul | path_too_long
                        | not_found | no_access | io_failed

core/io/io.ldn:318

Open a UTF-8 path for writing using caller scratch for the terminator. Delegates to the byte-path adapter.

out function

public out: (provider: type is process, state: provider) -> (stream: file)

core/io/io.ldn:198

Return the provider's standard-output identifier.

read function

public read: (provider: type is reader, inout state: provider,
              opened: file, into: []mut u8)
             -> (count: usize) ! io_failed

core/io/io.ldn:176

Read up to the destination length through reader evidence. Returns the number of bytes placed in the buffer, or zero at end of input.

same_file function

public same_file: (provider: type is files, inout state: provider,
                   left: ptr u8, right: ptr u8)
                  -> (same: bool) ! io_failed

core/io/io.ldn:161

Ask whether two terminated paths name the same file. Delegates provider-specific identity rules and reports io_failed on failure.

terminate_path function

public terminate_path: (source: []u8, scratch: []mut u8)
                       -> (path: ptr u8 from scratch)
                       ! empty_path | path_contains_nul | path_too_long

core/io/io.ldn:251

Copy path bytes into scratch and add a NUL terminator. Rejects empty input, embedded NUL and insufficient space in that order before any write; overlapping input and scratch are supported.

A files entry receives one already terminated pointer. Dynamic callers make that precondition explicit with caller-owned scratch: empty input, an embedded NUL, and insufficient terminator capacity are distinct and checked in that order. No byte is copied before all checks pass. Source and scratch may overlap; the copy preserves the original source bytes.

write function

public write: (provider: type is writer, inout state: provider,
               opened: file, bytes: []u8) -> none ! io_failed

core/io/io.ldn:185

Write the complete byte slice through writer evidence. io_failed may follow partial output; callers must not assume retrying the whole buffer is safe.

write_some function

public write_some: (provider: type is writer, inout state: provider,
                    opened: file, bytes: []u8) -> (count: usize) ! io_failed

core/io/io.ldn:192

Make one write attempt and return its progress. Nonempty success is positive; empty input returns zero; failure transfers no bytes.

writer_of function

public writer_of: (erased: ptr any world) -> (adapter: lent from erased)

core/io/io.ldn:126

Lend a writer adapter from an erased world. Keep the world and its underlying provider alive while the adapter is used; this does not transfer ownership.

written function

public written: (inout state: memory) -> (bytes: []u8 from state)

core/io/memory.ldn:260

Lend the initialized standard-output prefix accumulated by the memory provider.

written_errors function

public written_errors: (inout state: memory) -> (bytes: []u8 from state)

core/io/memory.ldn:265

Lend the initialized standard-error prefix accumulated by the memory provider.