iox

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 22, 2025 License: MIT Imports: 4 Imported by: 0

README

iox

Non-blocking semantics for Go io package: first-class signals for would-block and multi-shot.

Go Reference Go Report Card Coverage Status

Language: English | 简体中文 | Español | 日本語 | Français

What this package is?

iox is for non-blocking I/O stacks where “no progress right now” and “progress now, but the operation remains active” are normal control flow, not failures.

It introduces two semantic errors with explicit contracts:

  • ErrWouldBlockno progress is possible now without waiting for readiness/completions. Return immediately; retry after your next polling.
  • ErrMoreprogress happened and the operation remains active; more events will follow. Process the current result and keep polling.

iox keeps standard io mental models intact:

  • returned counts always mean “bytes transferred / progress made”
  • returned errors drive control flow (nil, semantic non-failure, or real failure)
  • helpers are compatible with io.Reader, io.Writer, and optimize via io.WriterTo / io.ReaderFrom

Semantics contract

For operations that adopt iox semantics:

Return error Meaning What the caller must do next
nil completed successfully for this call / transfer continue your state machine
ErrWouldBlock no progress possible now stop attempting; wait for readiness/completion; retry
ErrMore progress happened; more completions will follow process now; keep the operation active; continue polling
other error failure handle/log/close/backoff as appropriate

Notes:

  • iox.Copy may return (written > 0, ErrWouldBlock) or (written > 0, ErrMore) to report partial progress before stalling or before delivering a multi-shot continuation.
  • (0, nil) reads are treated as “stop copying now” and return (written, nil) to avoid hidden spinning inside helpers.
Note: iox.Copy and (0, nil) reads

The Go io.Reader contract allows Read to return (0, nil) to mean “no progress”, not end-of-stream. Well-behaved Readers should avoid (0, nil) except when len(p) == 0.

iox.Copy intentionally treats a (0, nil) read as “stop copying now” and returns (written, nil). This avoids hidden spinning inside a helper in non-blocking/event-loop code. If you need strict forward-progress detection across repeated (0, nil), implement that policy at your call site.

Note: iox.Copy and partial write recovery

When copying to a non-blocking destination, dst.Write may return a semantic error (ErrWouldBlock or ErrMore) with a partial write (nw < nr). In this case, bytes have been read from src but not fully written to dst.

To prevent data loss, iox.Copy attempts to roll back the source pointer:

  • If src implements io.Seeker, Copy calls Seek(nw-nr, io.SeekCurrent) to rewind the unwritten bytes.
  • If src does not implement io.Seeker, Copy returns ErrNoSeeker to signal that unwritten bytes are unrecoverable.

Recommendations:

  • Use seekable sources (e.g., *os.File, *bytes.Reader) when copying to non-blocking destinations.
  • For non-seekable sources (e.g., network sockets), use CopyPolicy with PolicyRetry for write-side semantic errors. This ensures all read bytes are written before returning, avoiding the need for rollback.

Quick start

Install with go get:

go get code.hybscloud.com/iox
type reader struct{ step int }

func (r *reader) Read(p []byte) (int, error) {
	switch r.step {
	case 0:
		r.step++
		return copy(p, "hello"), iox.ErrMore
	case 1:
		r.step++
		return copy(p, "world"), nil
	case 2:
		r.step++
		return 0, iox.ErrWouldBlock
	case 3:
		r.step++
		return copy(p, "iox"), nil
	default:
		return 0, io.EOF
	}
}

func main() {
	src := &reader{}
	var dst bytes.Buffer

	n, err := iox.Copy(&dst, src)
	fmt.Printf("n=%d err=%v buf=%q\n", n, err, dst.String()) // n=5  err=io: expect more  buf="hello"
	_, _ = iox.CopyN(io.Discard, &dst, 5)                    // consume "hello"

	n, err = iox.Copy(&dst, src)
	fmt.Printf("n=%d err=%v buf=%q\n", n, err, dst.String()) // n=5  err=io: would block   buf="world"
	_, _ = iox.CopyN(io.Discard, &dst, 5)                    // consume "world"

	n, err = iox.Copy(&dst, src)
	fmt.Printf("n=%d err=%v buf=%q\n", n, err, dst.String()) // n=3  err=<nil>            buf="iox"
}

API overview

  • Errors

    • ErrWouldBlock, ErrMore, ErrNoSeeker
  • Copy

    • Copy(dst Writer, src Reader) (int64, error)
    • CopyBuffer(dst Writer, src Reader, buf []byte) (int64, error)
    • CopyN(dst Writer, src Reader, n int64) (int64, error)
    • CopyNBuffer(dst Writer, src Reader, n int64, buf []byte) (int64, error)
  • Tee

    • TeeReader(r Reader, w Writer) Reader
    • TeeWriter(primary, tee Writer) Writer
  • Adapters

    • AsWriterTo(r Reader) Reader (adds io.WriterTo via iox.Copy)
    • AsReaderFrom(w Writer) Writer (adds io.ReaderFrom via iox.Copy)
  • Semantics

    • IsNonFailure(err error) bool
    • IsWouldBlock(err error) bool
    • IsMore(err error) bool
    • IsProgress(err error) bool
  • Backoff

    • Backoff — adaptive back-off for external I/O waiting
    • DefaultBackoffBase (500µs), DefaultBackoffMax (100ms)

Backoff — Adaptive Waiting for External I/O

When ErrWouldBlock signals that no progress is possible, the caller must wait before retrying. iox.Backoff provides an adaptive back-off strategy for this waiting.

Three-Tier Progress Model:

Tier Mechanism Use Case
Strike System call Direct kernel hit
Spin Hardware yield (spin) Local atomic synchronization
Adapt Software backoff (iox.Backoff) External I/O readiness

Zero-value ready to use:

var b iox.Backoff  // uses DefaultBackoffBase (500µs) and DefaultBackoffMax (100ms)

for {
    n, err := conn.Read(buf)
    if err == iox.ErrWouldBlock {
        b.Wait()  // adaptive sleep with jitter
        continue
    }
    if err != nil {
        return err
    }
    process(buf[:n])
    b.Reset()  // reset on successful progress
}

Algorithm: Block-based linear scaling with ±12.5% jitter to prevent thundering herds.

  • Block 1: 1 sleep of base
  • Block 2: 2 sleeps of 2×base
  • Block n: n sleeps of min(n×base, max)

Methods:

  • Wait() — sleep for the current duration, then advance
  • Reset() — restore to block 1
  • SetBase(d) / SetMax(d) — configure timing

Tee semantics (counts and errors)

  • TeeReader returns n as the number of bytes read from r (source progress), even if the side write fails/is short.
  • TeeWriter returns n as the number of bytes accepted by primary (primary progress), even if the tee write fails/is short.
  • When n > 0, a tee adapter may return (n, err) where err comes from the side/tee (including ErrWouldBlock/ErrMore). Process p[:n] first.
  • For best interoperability with policy-driven helpers, return ErrWouldBlock/ErrMore as-is (avoid wrapping).

Semantic Policy

Some helpers accept an optional SemanticPolicy to decide what to do when they encounter ErrWouldBlock or ErrMore (e.g., return immediately vs yield and retry).

The default is nil, which means non-blocking behavior is preserved: the helper returns ErrWouldBlock / ErrMore to the caller and does not wait or retry on its own.

Fast paths and semantic preservation

iox.Copy uses standard "io" fast paths when available:

  • if src implements io.WriterTo, iox.Copy calls WriteTo
  • else if dst implements io.ReaderFrom, iox.Copy calls ReadFrom
  • else it uses a fixed-size stack buffer (32KiB) and a read/write loop

To preserve ErrWouldBlock / ErrMore across fast paths, ensure your WriteTo / ReadFrom implementations return those errors when appropriate.

If you have a plain io.Reader/io.Writer but want the fast-path interfaces to exist and preserve semantics, wrap with:

  • iox.AsWriterTo(r) to add a WriteTo implemented via iox.Copy
  • iox.AsReaderFrom(w) to add a ReadFrom implemented via iox.Copy

License

MIT — see LICENSE.

©2025 Hayabusa Cloud Co., Ltd.

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

View Source
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

View Source
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.

View Source
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.

View Source
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.
View Source
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

func Copy(dst Writer, src Reader) (written int64, err error)

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

func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error)

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

func CopyN(dst Writer, src Reader, n int64) (written int64, err error)

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

func CopyNBuffer(dst Writer, src Reader, n int64, buf []byte) (written int64, err error)

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

func CopyNPolicy(dst Writer, src Reader, n int64, policy SemanticPolicy) (written int64, err error)

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

func IsMore(err error) bool

IsMore reports whether err carries the iox multi-shot (more completions) semantic. It returns true for ErrMore and wrappers (via errors.Is).

func IsNonFailure

func IsNonFailure(err error) bool

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

func IsProgress(err error) bool

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

func IsSemantic(err error) bool

IsSemantic reports whether err represents an iox semantic signal: either ErrWouldBlock or ErrMore (including wrapped forms).

func IsWouldBlock

func IsWouldBlock(err error) bool

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:

  1. Strike: System call → Direct kernel hit.
  2. Spin: Hardware yield (spin) → Local atomic synchronization.
  3. 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) Block added in v0.3.0

func (b *Backoff) Block() int

Block returns the current progression tier.

func (*Backoff) Duration added in v0.3.0

func (b *Backoff) Duration() time.Duration

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

func (b *Backoff) SetBase(d time.Duration)

SetBase configures the initial duration and linear scaling factor.

func (*Backoff) SetMax added in v0.3.0

func (b *Backoff) SetMax(d time.Duration)

SetMax configures the maximum allowed sleep duration.

func (*Backoff) Wait added in v0.3.0

func (b *Backoff) Wait()

Wait performs a non-blocking-friendly sleep. The duration scales linearly: min(base * n, max) ± 12.5% jitter.

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

type Closer = io.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).

const (
	OpCopyRead Op = iota
	OpCopyWrite

	OpCopyWriterTo
	OpCopyReaderFrom

	OpTeeReaderRead
	OpTeeReaderSideWrite

	OpTeeWriterPrimaryWrite
	OpTeeWriterTeeWrite
)

func (Op) String added in v0.2.0

func (op Op) String() string

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).

const (
	OutcomeFailure Outcome = iota
	OutcomeOK
	OutcomeWouldBlock
	OutcomeMore
)

func Classify

func Classify(err error) Outcome

Classify maps err to an Outcome. Use when a compact switch is preferred.

Note: This does not attempt to reinterpret standard library sentinels like io.EOF; classification depends solely on the error value the caller passes.

func (Outcome) String

func (o Outcome) String() string

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

type Reader = io.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

func AsWriterTo(r Reader) Reader

AsWriterTo wraps r so that it also implements WriterTo via iox semantics.

func TeeReader

func TeeReader(r Reader, w Writer) Reader

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

type ReaderAt = io.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.

func (ReaderFromAdapter) ReadFrom

func (a ReaderFromAdapter) ReadFrom(src Reader) (int64, error)

ReadFrom delegates to iox.Copy to preserve extended semantics.

func (ReaderFromAdapter) Write

func (a ReaderFromAdapter) Write(p []byte) (int, error)

Write forwards to the underlying Writer to preserve Writer semantics.

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

type Seeker = io.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

type Writer = io.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

func AsReaderFrom(w Writer) Writer

AsReaderFrom wraps w so that it also implements ReaderFrom via iox semantics.

func TeeWriter

func TeeWriter(primary Writer, tee Writer) Writer

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

type WriterAt = io.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

type WriterTo = io.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.

func (WriterToAdapter) Read

func (a WriterToAdapter) Read(p []byte) (int, error)

Read forwards to the underlying Reader to preserve Reader semantics.

func (WriterToAdapter) WriteTo

func (a WriterToAdapter) WriteTo(dst Writer) (int64, error)

WriteTo delegates to iox.Copy to preserve extended semantics.

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

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL