silo:std.io

Source src/silo:std.io

1##! Byte-oriented IO traits — `Read`, `Write`, `BufRead`, `Seek`, and the `SeekFrom` union.
2##!
3##! Generic code can be written against `(Read src)` / `(Write sink a
4##! | o)` today. Concrete impls on capability handles (filesystem
5##! files, TCP sockets, Console stdin/stdout) are deferred pending the
6##! typed-handle infrastructure; `io-copy` is a stub that panics until
7##! those impls exist. The default in-memory `Write` target is `Str`
8##! directly — Silo's `Str` is a mutable owned buffer.
9##!
10##! Buffer parameter and return types use `Bytes` today where the
11##! long-term shape is an `(Seq U8 _)` existential, and error positions
12##! use `Str` where a dedicated `IOError` union will live. Default
13##! method bodies for `.read-exact`, `.read-to-end`, `.read-to-str`,
14##! `.rewind`, `.stream-position`, `.seek-relative`, and the `BufRead`
15##! helpers land alongside the capability-handle impls.
16
17:use
18  :open core AnyUInt Bytes I64 Option Result Str U64 U8 Unit
19  :open effects.panic panic
20:end
21
22# si[impl io.read+1]
23## Read — fills a caller-supplied byte buffer from the underlying source.
24## `.read` returns the handle threaded through and the number of bytes read;
25## a return of `0` means end-of-stream. Effect-polymorphic: in-memory
26## readers carry no effect, file-backed handles carry `+FileSystem`,
27## network handles carry `+Tcp`/`+Udp`.
28:trait(pub) Read
29  ## Fill the caller-provided buffer; return the handle and bytes read.
30  ## Zero return MUST mean end-of-stream.
31  .read ( Self Bytes -> Self AnyUInt ) +eff
32:end
33
34# si[impl io.write+1]
35## Write — unified sink trait parameterised on the input element type `a`
36## and an associated output type `o` returned by `.finish`. Every writer
37## MUST implement the primitive `(Write Self Bytes | Self)`; blanket impls
38## cascade UTF-8 encoding for `Str`, `Codepoint`, and `Pattern`. `.write`
39## is all-or-fail: partial writes MUST raise via `+eff`. `.flush` defaults
40## to a no-op in the spec; the default body is elided here pending
41## handle impls.
42:trait(pub) Write a | o
43  ## Write the entire value or raise via `+eff`. Returns the handle on
44  ## success; there is no partial-write return.
45  .write ( Self a -> Self ) +eff
46  ## Push any buffered bytes downstream. Spec default is a no-op; concrete
47  ## impls override for streaming writers.
48  .flush ( Self -> Self ) +eff
49  ## Consume the writer and produce the associated output type.
50  .finish ( Self -> o ) +eff
51:end
52
53# si[impl io.bufread+1]
54## BufRead — Read plus buffer-aware operations. An implementation MUST
55## maintain an internal buffer that decouples application-level reads
56## from source-level reads.
57:trait(pub) BufRead { (Read Self) }
58  ## Fill and return a view of the internal buffer.
59  .fill-buf ( Self -> Self Bytes ) +eff
60  ## Mark `n` bytes of the internal buffer as consumed.
61  .consume ( Self AnyUInt -> Self )
62  ## Read one line (UTF-8); returns the handle and a fallible Str.
63  .read-line ( Self -> Self (Result Str Str) ) +eff
64  ## Read up to and including the delimiter byte; returns the handle and
65  ## the collected bytes on success.
66  .read-until ( Self U8 -> Self (Result Bytes Str) ) +eff
67:end
68
69# si[impl io.seek]
70## SeekFrom — the offset origin. `Start` uses an unsigned offset (position
71## measured from beginning); `End` and `Current` use signed offsets because
72## relative positions may be negative.
73:union(pub) SeekFrom
74  | Start U64
75  | End I64
76  | Current I64
77:end
78
79# si[impl io.seek]
80## Seek — random-access positioning. Implemented by file handles and
81## in-memory byte buffers; network sockets MUST NOT implement Seek.
82:trait(pub) Seek
83  ## Move the position per `SeekFrom`; return the new absolute offset.
84  .seek ( Self SeekFrom -> Self (Result U64 Str) ) +eff
85:end
86
87# si[impl io.copy+1]
88## `io-copy` — copy bytes from any `Read` source to any `Write Bytes` sink
89## until end-of-stream on the source, returning the total bytes copied.
90##
91## The real implementation needs capability-handle impls of `Read` and
92## `Write` so the effect row can be resolved; until those land, the body
93## here panics. The signature is the spec signature with the existential
94## `(Seq U8 _)` replaced by `Bytes` (see divergence 1) and the effect
95## variable elided because no constraint can mention the `Read`/`Write`
96## impls' effect rows yet.
97:fn(pub) io-copy ( src sink -> src sink AnyUInt )
98  "io-copy not implemented yet — awaits capability-handle Read/Write impls" panic
99:end