Documentation
¶
Overview ¶
Package iox provides non-blocking I/O helpers that extend Go's standard io semantics with explicit non-failure control-flow errors (see ErrWouldBlock, ErrMore) while remaining compatible with standard library interfaces.
IDE note: iox re-exports (aliases) the core io interfaces so that users can stay in the "iox" namespace while reading documentation and navigating types. The contracts below mirror the standard io expectations, with iox-specific behavior documented where relevant (typically at call sites such as Copy).
Index ¶
- Constants
- Variables
- func Copy(dst Writer, src Reader) (written int64, err error)
- func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error)
- func CopyBufferPolicy(dst Writer, src Reader, buf []byte, policy SemanticPolicy) (written int64, err error)
- func CopyN(dst Writer, src Reader, n int64) (written int64, err error)
- func CopyNBuffer(dst Writer, src Reader, n int64, buf []byte) (written int64, err error)
- func CopyNBufferPolicy(dst Writer, src Reader, n int64, buf []byte, policy SemanticPolicy) (written int64, err error)
- func CopyNPolicy(dst Writer, src Reader, n int64, policy SemanticPolicy) (written int64, err error)
- func CopyPolicy(dst Writer, src Reader, policy SemanticPolicy) (written int64, err error)
- func IsMore(err error) bool
- func IsNonFailure(err error) bool
- func IsProgress(err error) bool
- func IsSemantic(err error) bool
- func IsWouldBlock(err error) bool
- type Backoff
- type Buffer
- type ByteReader
- type ByteScanner
- type ByteWriter
- type Closer
- type Op
- type Outcome
- type PolicyAction
- type PolicyFunc
- type ReadCloser
- type ReadSeeker
- type ReadWriteCloser
- type ReadWriteSeeker
- type ReadWriter
- type Reader
- type ReaderAt
- type ReaderFrom
- type ReaderFromAdapter
- type ReturnPolicy
- type RuneReader
- type RuneScanner
- type Seeker
- type SemanticPolicy
- type StringWriter
- type WriteCloser
- type WriteSeeker
- type Writer
- type WriterAt
- type WriterTo
- type WriterToAdapter
- type YieldOnWriteWouldBlockPolicy
- type YieldPolicy
Constants ¶
const ( // DefaultBackoffBase is the tuned base duration for backoff (500µs). // It matches the expected scale of local-network round-trip times. DefaultBackoffBase = 500 * time.Microsecond // DefaultBackoffMax is the default ceiling for sleep duration (100ms). DefaultBackoffMax = 100 * time.Millisecond )
Variables ¶
var ( // EOF is returned by Read when no more input is available. // Functions should return EOF only to signal a graceful end of input. EOF = io.EOF // ErrClosedPipe is returned on write to a closed pipe. // It may also be returned by other operations that behave like a closed pipe. ErrClosedPipe = io.ErrClosedPipe // ErrNoProgress reports that a Reader returned no data and no error after // multiple Read calls. It is used by some io helpers to detect broken Readers // (i.e., lack of forward progress). ErrNoProgress = io.ErrNoProgress // ErrShortBuffer means a provided buffer was too small to complete the operation. // Callers typically retry with a larger buffer. ErrShortBuffer = io.ErrShortBuffer // ErrShortWrite means a write accepted fewer bytes than requested and returned // no explicit error (or equivalently, could not complete the full write). ErrShortWrite = io.ErrShortWrite // ErrUnexpectedEOF means EOF was encountered earlier than expected. // It is commonly used by fixed-size reads/copies when the stream ends mid-record. ErrUnexpectedEOF = io.ErrUnexpectedEOF )
Common sentinel errors re-exported for convenience.
Note: iox also defines semantic non-failure errors (ErrWouldBlock, ErrMore) used by iox helpers and adapters; those are not part of the standard io set.
var ErrMore = errors.New("io: expect more")
ErrMore means “this operation remains active; more completions will follow” (multi-shot / streaming style). Next step: keep polling and processing results.
var ErrNoSeeker = errors.New("io: source is not seekable; partial write unrecoverable")
ErrNoSeeker is returned by Copy helpers when a partial write occurs with a semantic error (ErrWouldBlock or ErrMore) and the source does not implement io.Seeker. Without Seek capability, the unwritten bytes in the transient buffer cannot be recovered, resulting in data loss.
To avoid this error:
- Use a seekable source (e.g., *os.File, *bytes.Reader).
- Use CopyPolicy with PolicyRetry to ensure all read bytes are written before returning.
var ErrWouldBlock = errors.New("io: would block")
ErrWouldBlock means “no further progress without waiting”. Linux analogy: EAGAIN/EWOULDBLOCK / not-ready / no completion available. Next step: wait (via poll/epoll/io_uring/etc), then retry.
Functions ¶
func Copy ¶
Copy copies from src to dst until either EOF is reached on src or an error occurs.
iox semantics extension:
- ErrWouldBlock: return immediately because the next step would block. written may be > 0 (partial progress); retry after readiness/completion.
- ErrMore: return immediately because progress happened and the operation remains active; written may be > 0; keep polling for more completions.
Partial write recovery (Seeker rollback):
If dst.Write returns a semantic error (ErrWouldBlock or ErrMore) with a partial write (nw < nr), Copy attempts to roll back the source pointer by calling src.Seek(nw-nr, io.SeekCurrent) if src implements io.Seeker. This allows the caller to retry Copy without data loss.
If src does NOT implement io.Seeker and a partial write occurs with a semantic error, Copy returns ErrNoSeeker to prevent silent data corruption. Callers using non-blocking destinations with non-seekable sources (e.g., sockets) should use CopyPolicy with PolicyRetry to ensure all read bytes are written before returning.
func CopyBuffer ¶
CopyBuffer is like Copy but stages through buf if needed. If buf is nil, a stack buffer is used. If buf has zero length, CopyBuffer panics.
Partial write recovery: same Seeker rollback semantics as Copy. Returns ErrNoSeeker if src is not seekable and a partial write occurs with a semantic error. See Copy documentation for details.
func CopyBufferPolicy ¶ added in v0.2.0
func CopyBufferPolicy(dst Writer, src Reader, buf []byte, policy SemanticPolicy) (written int64, err error)
CopyBufferPolicy is like CopyBuffer but consults policy on semantic errors.
- nil policy: identical to CopyBuffer
- non-nil: PolicyRetry triggers policy.Yield(op) and a retry; otherwise the semantic error is returned unchanged.
Partial write recovery: same semantics as CopyPolicy. When policy returns PolicyReturn on a partial write, Seeker rollback is attempted; returns ErrNoSeeker if src is not seekable. When policy returns PolicyRetry, the write is retried internally without rollback.
func CopyN ¶
CopyN copies n bytes (or until an error) from src to dst. On return, written == n if and only if err == nil.
iox semantics extension:
- ErrWouldBlock / ErrMore may be returned when progress stops early; written may be > 0 and is the number of bytes already copied.
func CopyNBuffer ¶
CopyNBuffer is like CopyN but stages through buf if needed. If buf is nil, a stack buffer is used. If buf has zero length, CopyNBuffer panics.
func CopyNBufferPolicy ¶ added in v0.2.0
func CopyNBufferPolicy(dst Writer, src Reader, n int64, buf []byte, policy SemanticPolicy) (written int64, err error)
CopyNBufferPolicy is like CopyNBuffer but consults policy on semantic errors.
- nil policy: identical to CopyNBuffer
func CopyNPolicy ¶ added in v0.2.0
CopyNPolicy is like CopyN but consults policy on semantic errors.
- nil policy: identical to CopyN
- non-nil: uses the policy-aware engine; PolicyRetry yields and retries.
func CopyPolicy ¶ added in v0.2.0
func CopyPolicy(dst Writer, src Reader, policy SemanticPolicy) (written int64, err error)
CopyPolicy is like Copy but consults policy when encountering semantic errors.
Semantics:
- If policy is nil, behavior is identical to Copy (default non-blocking semantics).
- If policy returns PolicyRetry on ErrWouldBlock/ErrMore, the engine will call policy.Yield(op) and retry from that point; otherwise it returns.
Partial write recovery:
When policy returns PolicyReturn (not retry) on a semantic error with partial write progress, CopyPolicy attempts Seeker rollback on src (same as Copy). If src is not seekable, ErrNoSeeker is returned to prevent silent data loss. When policy returns PolicyRetry, the engine retries the write internally, ensuring all read bytes are written before the next read—no rollback needed.
For non-seekable sources (e.g., network sockets) where data integrity is required, configure policy to return PolicyRetry for write-side semantic errors. This guarantees forward progress without data loss.
func IsMore ¶
IsMore reports whether err carries the iox multi-shot (more completions) semantic. It returns true for ErrMore and wrappers (via errors.Is).
func IsNonFailure ¶
IsNonFailure reports whether err should be treated as a non-failure in non-blocking I/O control flow: nil, ErrWouldBlock, or ErrMore.
Typical usage: decide whether to keep a descriptor active without logging an error or tearing down the operation.
func IsProgress ¶
IsProgress reports whether the current call produced usable progress now: returns true for nil and ErrMore. In both cases caller can proceed with delivered data/work; for ErrMore keep polling for subsequent completions.
func IsSemantic ¶
IsSemantic reports whether err represents an iox semantic signal: either ErrWouldBlock or ErrMore (including wrapped forms).
func IsWouldBlock ¶
IsWouldBlock reports whether err carries the iox would-block semantic. It returns true for ErrWouldBlock and wrappers (via errors.Is).
Types ¶
type Backoff ¶ added in v0.3.0
type Backoff struct {
// contains filtered or unexported fields
}
Backoff implements a linear block-based back-off strategy with jitter. It is designed for external I/O readiness waiting (e.g., buffer release).
Zero-value is ready to use: a freshly declared Backoff{} uses DefaultBackoffBase (500µs) and DefaultBackoffMax (100ms).
This is the "Adapt" layer of the Three-Tier Progress model:
- Strike: System call → Direct kernel hit.
- Spin: Hardware yield (spin) → Local atomic synchronization.
- Adapt: Software backoff (iox.Backoff) → External I/O readiness.
The algorithm groups iterations into blocks. In block n, it performs n sleeps of duration (base × n). Jitter (±12.5%) is applied to prevent synchronized thundering herds.
func (*Backoff) Duration ¶ added in v0.3.0
Duration returns the current duration without jitter. For a zero-value Backoff, returns DefaultBackoffBase.
func (*Backoff) Reset ¶ added in v0.3.0
func (b *Backoff) Reset()
Reset restores the backoff state to block 1.
func (*Backoff) SetBase ¶ added in v0.3.0
SetBase configures the initial duration and linear scaling factor.
type Buffer ¶
type Buffer [32 * 1024]byte
Buffer is the default stack buffer used by Copy when none is supplied.
type ByteReader ¶
type ByteReader = io.ByteReader
ByteReader reads and returns a single byte.
ByteReader is an alias of io.ByteReader.
type ByteScanner ¶
type ByteScanner = io.ByteScanner
ByteScanner is a ByteReader that can "unread" the last byte read.
ByteScanner is an alias of io.ByteScanner.
type ByteWriter ¶
type ByteWriter = io.ByteWriter
ByteWriter writes a single byte.
ByteWriter is an alias of io.ByteWriter.
type Closer ¶
Closer is implemented by types that can release resources.
Close should be idempotent where practical; callers should not assume any particular behavior beyond resource release and an error indicating failure.
Closer is an alias of io.Closer.
type Op ¶ added in v0.2.0
type Op uint8
Op identifies where a semantic signal (ErrWouldBlock / ErrMore) came from.
This is intentionally coarse-grained: it lets a Policy distinguish reader-side vs writer-side semantics (e.g., writer-side ErrMore as a frame boundary).
type Outcome ¶
type Outcome uint8
Outcome classifies an operation result based on iox's extended semantics.
OutcomeOK: success, no more to come. OutcomeWouldBlock: no progress is possible right now; retry later. OutcomeMore: progress happened and more completions are expected. OutcomeFailure: any other error (including EOF when it's not absorbed by helpers).
type PolicyAction ¶ added in v0.2.0
type PolicyAction uint8
PolicyAction tells an engine whether it should return to the caller or attempt the operation again.
const ( // PolicyReturn means: return immediately to the caller. // Use this for "delivery boundaries" (e.g., writer-side ErrMore). PolicyReturn PolicyAction = iota // PolicyRetry means: do not return; retry after waiting/yielding. // This is typically used to map ErrWouldBlock to blocking-ish behavior. PolicyRetry )
type PolicyFunc ¶ added in v0.2.0
type PolicyFunc struct {
YieldFunc func(op Op)
WouldBlockFunc func(op Op) PolicyAction
MoreFunc func(op Op) PolicyAction
}
PolicyFunc is a convenience implementation for callers that want to inject behavior without defining a struct type.
Default behaviors when fields are nil:
- YieldFunc: calls runtime.Gosched() to yield the processor
- WouldBlockFunc: returns PolicyReturn (caller handles ErrWouldBlock)
- MoreFunc: returns PolicyReturn (caller handles ErrMore)
func (PolicyFunc) OnMore ¶ added in v0.2.0
func (p PolicyFunc) OnMore(op Op) PolicyAction
func (PolicyFunc) OnWouldBlock ¶ added in v0.2.0
func (p PolicyFunc) OnWouldBlock(op Op) PolicyAction
func (PolicyFunc) Yield ¶ added in v0.2.0
func (p PolicyFunc) Yield(op Op)
type ReadCloser ¶
type ReadCloser = io.ReadCloser
ReadCloser groups Read and Close.
ReadCloser is an alias of io.ReadCloser.
type ReadSeeker ¶
type ReadSeeker = io.ReadSeeker
ReadSeeker groups Read and Seek.
ReadSeeker is an alias of io.ReadSeeker.
type ReadWriteCloser ¶
type ReadWriteCloser = io.ReadWriteCloser
ReadWriteCloser groups Read, Write, and Close.
ReadWriteCloser is an alias of io.ReadWriteCloser.
type ReadWriteSeeker ¶
type ReadWriteSeeker = io.ReadWriteSeeker
ReadWriteSeeker groups Read, Write, and Seek.
ReadWriteSeeker is an alias of io.ReadWriteSeeker.
type ReadWriter ¶
type ReadWriter = io.ReadWriter
ReadWriter groups the basic Read and Write methods.
ReadWriter is an alias of io.ReadWriter.
type Reader ¶
Reader is implemented by types that can read bytes into p.
Read must return the number of bytes read (0 <= n <= len(p)) and any error encountered. Even if Read returns n > 0, it may return a non-nil error to signal a condition observed after producing those bytes.
Callers should treat a return of (0, nil) as "no progress": it does not mean end-of-stream. Well-behaved implementations should avoid returning (0, nil) except when len(p) == 0.
Reader is an alias of io.Reader.
func AsWriterTo ¶
AsWriterTo wraps r so that it also implements WriterTo via iox semantics.
func TeeReader ¶
TeeReader returns a Reader that writes to w what it reads from r. It mirrors io.TeeReader but propagates iox semantics:
- If r.Read returns data with ErrWouldBlock or ErrMore, the data is first written to w, then the special error is returned unchanged.
- If writing to w fails, that error is returned.
- Short writes to w are reported as io.ErrShortWrite.
Count semantics:
- The returned n is the number of bytes read from r.
- If the side write fails or is short, n is still the read count. This avoids byte loss: the bytes were already consumed from r.
func TeeReaderPolicy ¶ added in v0.2.0
func TeeReaderPolicy(r Reader, w Writer, policy SemanticPolicy) Reader
TeeReaderPolicy is like TeeReader but consults policy when encountering semantic errors from r.Read or the side write to w.
- nil policy: identical to TeeReader
- non-nil: PolicyRetry triggers policy.Yield(op) and a retry. For read-side semantics when n>0, the bytes are delivered to the caller after side write, and a retry decision of PolicyRetry results in returning (n, nil).
type ReaderAt ¶
ReaderAt reads from the underlying input at a given offset.
ReaderAt should not affect and should not be affected by the current seek offset. Implementations must return a non-nil error when n < len(p).
ReaderAt is an alias of io.ReaderAt.
type ReaderFrom ¶
type ReaderFrom = io.ReaderFrom
ReaderFrom is an optional optimization for Writers.
If implemented by a Writer, Copy-like helpers may call ReadFrom to transfer data from r more efficiently than a generic read/write loop.
ReaderFrom is an alias of io.ReaderFrom.
type ReaderFromAdapter ¶
type ReaderFromAdapter struct{ W Writer }
ReaderFromAdapter adapts a Writer to implement ReaderFrom using iox.Copy.
type ReturnPolicy ¶ added in v0.2.0
type ReturnPolicy struct{}
ReturnPolicy is the simplest policy: never waits and never retries. It preserves non-blocking semantics (callers handle ErrWouldBlock/ErrMore).
func (ReturnPolicy) OnMore ¶ added in v0.2.0
func (ReturnPolicy) OnMore(Op) PolicyAction
func (ReturnPolicy) OnWouldBlock ¶ added in v0.2.0
func (ReturnPolicy) OnWouldBlock(Op) PolicyAction
func (ReturnPolicy) Yield ¶ added in v0.2.0
func (ReturnPolicy) Yield(Op)
type RuneReader ¶
type RuneReader = io.RuneReader
RuneReader reads and returns a single UTF-8 encoded rune.
RuneReader is an alias of io.RuneReader.
type RuneScanner ¶
type RuneScanner = io.RuneScanner
RuneScanner is a RuneReader that can "unread" the last rune read.
RuneScanner is an alias of io.RuneScanner.
type Seeker ¶
Seeker is implemented by types that can set the offset for the next Read or Write.
Seek sets the offset based on whence and returns the new absolute offset.
Seeker is an alias of io.Seeker.
type SemanticPolicy ¶ added in v0.2.0
type SemanticPolicy interface {
Yield(op Op)
OnWouldBlock(op Op) PolicyAction
OnMore(op Op) PolicyAction
}
SemanticPolicy customizes how an engine reacts to iox semantic errors.
This is a decision function that maps (operation, error) pairs to actions, plus an optional yield hook for when retry is selected.
Contract expectations:
- OnWouldBlock / OnMore are only called for the matching semantic errors.
- If PolicyRetry is returned, the engine will call Yield(op) and then retry.
- If Yield(op) does not actually wait for readiness/completion, the engine may spin.
Note: keep this interface narrow; it should remain usable for both Copy and Tee.
type StringWriter ¶
type StringWriter = io.StringWriter
StringWriter writes the contents of s more efficiently than Write([]byte(s)) for implementations that can avoid an allocation/copy.
StringWriter is an alias of io.StringWriter.
type WriteCloser ¶
type WriteCloser = io.WriteCloser
WriteCloser groups Write and Close.
WriteCloser is an alias of io.WriteCloser.
type WriteSeeker ¶
type WriteSeeker = io.WriteSeeker
WriteSeeker groups Write and Seek.
WriteSeeker is an alias of io.WriteSeeker.
type Writer ¶
Writer is implemented by types that can write bytes from p.
Write must return the number of bytes written (0 <= n <= len(p)) and any error encountered. If Write returns n < len(p), it must return a non-nil error (except in the special case of len(p) == 0).
Writer is an alias of io.Writer.
func AsReaderFrom ¶
AsReaderFrom wraps w so that it also implements ReaderFrom via iox semantics.
func TeeWriter ¶
TeeWriter returns a Writer that writes to primary and also mirrors the bytes accepted by primary to tee.
Call order and error precedence:
- First, it calls primary.Write(p).
- If primary accepts n>0 bytes, it then calls tee.Write(p[:n]).
- If the tee write fails or is short, that error (or io.ErrShortWrite) is returned, even if primary also returned an error.
- Otherwise, the primary error (if any) is returned.
Special errors ErrWouldBlock and ErrMore are propagated unchanged.
Count semantics:
- The returned n is the number of bytes accepted by the primary writer.
- If the tee write fails after primary has accepted bytes, n is still the primary count. This makes retry-by-slicing (p[n:]) safe: it will not duplicate primary writes.
func TeeWriterPolicy ¶ added in v0.2.0
func TeeWriterPolicy(primary Writer, tee Writer, policy SemanticPolicy) Writer
TeeWriterPolicy is like TeeWriter but consults policy on semantic errors.
- nil policy: identical to TeeWriter
- non-nil: PolicyRetry yields and retries writing remaining bytes for either the primary or tee writes. Short writes are reported as io.ErrShortWrite.
type WriterAt ¶
WriterAt writes to the underlying output at a given offset.
WriterAt should not affect and should not be affected by the current seek offset. Implementations must return a non-nil error when n < len(p).
WriterAt is an alias of io.WriterAt.
type WriterTo ¶
WriterTo is an optional optimization for Readers.
If implemented by a Reader, Copy-like helpers may call WriteTo to transfer data to w more efficiently than a generic read/write loop.
WriterTo is an alias of io.WriterTo.
type WriterToAdapter ¶
type WriterToAdapter struct{ R Reader }
WriterToAdapter adapts a Reader to implement WriterTo using iox.Copy.
type YieldOnWriteWouldBlockPolicy ¶ added in v0.2.0
type YieldOnWriteWouldBlockPolicy struct {
YieldFunc func(op Op)
}
YieldOnWriteWouldBlockPolicy retries only when the *writer side* would block. Reader-side ErrWouldBlock is returned to the caller.
Useful when reads are fed by an event loop already, but writes need a local backpressure strategy (e.g., bounded output buffer).
func (YieldOnWriteWouldBlockPolicy) OnMore ¶ added in v0.2.0
func (YieldOnWriteWouldBlockPolicy) OnMore(Op) PolicyAction
func (YieldOnWriteWouldBlockPolicy) OnWouldBlock ¶ added in v0.2.0
func (YieldOnWriteWouldBlockPolicy) OnWouldBlock(op Op) PolicyAction
func (YieldOnWriteWouldBlockPolicy) Yield ¶ added in v0.2.0
func (p YieldOnWriteWouldBlockPolicy) Yield(op Op)
type YieldPolicy ¶ added in v0.2.0
type YieldPolicy struct {
// YieldFunc is invoked when the engine decides to retry after ErrWouldBlock.
// It may spin, park, poll, run an event-loop tick, etc.
YieldFunc func(op Op)
}
YieldPolicy is a ready-to-use policy with the common mapping:
- ErrWouldBlock: yield/wait and retry
- ErrMore: return immediately (treat as a delivery/boundary signal)
This matches protocols where writer-side ErrMore denotes a completed frame and the caller wants to handle the boundary immediately, then call Copy again.
Default Yield behavior: runtime.Gosched().
func (YieldPolicy) OnMore ¶ added in v0.2.0
func (YieldPolicy) OnMore(Op) PolicyAction
func (YieldPolicy) OnWouldBlock ¶ added in v0.2.0
func (YieldPolicy) OnWouldBlock(Op) PolicyAction
func (YieldPolicy) Yield ¶ added in v0.2.0
func (p YieldPolicy) Yield(op Op)
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package examples contains small, runnable snippets that demonstrate how to use iox's non-blocking semantics in typical copy-style flows.
|
Package examples contains small, runnable snippets that demonstrate how to use iox's non-blocking semantics in typical copy-style flows. |