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
- files concept
- process concept
- reader concept
- world concept
- writer concept
- argument type
- file type
- lent_writer type
- memory type
- memory_file type
- argument_too_long atom
- empty_path atom
- io_failed atom
- no_access atom
- no_argument atom
- not_found atom
- path_contains_nul atom
- path_too_long atom
- argument_at function
- argument_count function
- close function
- copy_argument function
- err function
- memory_over function
- open_read function
- open_read_bytes function
- open_read_text function
- open_write function
- open_write_bytes function
- open_write_text function
- out function
- read function
- same_file function
- terminate_path function
- write function
- write_some function
- writer_of function
- written function
- written_errors function
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 filesFile 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 processStandard 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 readerInput 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 worldComposition 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 writerOutput 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 argumentA 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_valueProvider-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 = lentAdapter 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 memoryIn-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_fileCaller-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: atomThe caller's scratch buffer cannot hold all argument bytes.
empty_path atom
public empty_path: atomThe path has no bytes before its terminator.
io_failed atom
public io_failed: atomAn I/O operation failed. Provider-specific diagnostic detail, if offered, must be read from that provider.
no_access atom
public no_access: atomThe provider refused access to the requested file.
no_argument atom
public no_argument: atomThe argument index does not identify an available argument.
not_found atom
public not_found: atomThe requested file or path could not be found by the provider.
path_contains_nul atom
public path_contains_nul: atomThe supplied path bytes contain an embedded NUL.
path_too_long atom
public path_too_long: atomThe 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_argumentLend 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)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_failedClose 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_longCopy 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)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)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_failedOpen 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_failedTerminate 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_failedOpen 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_failedOpen 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_failedTerminate 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_failedOpen 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)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_failedRead 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_failedAsk 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_longCopy 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_failedWrite 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_failedMake 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)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)Lend the initialized standard-output prefix accumulated by the memory provider.
written_errors function
public written_errors: (inout state: memory) -> (bytes: []u8 from state)Lend the initialized standard-error prefix accumulated by the memory provider.