Skip to content
CryoCryo home

traits

import std::io::traits; · source

Types

Read

type trait Read {
    read(mut &this, buffer: u8*, length: u64) -> Result<u64, IoError>;
    read_all(mut &this, buffer: u8*, length: u64) -> Result<u64, IoError>;
    read_byte(mut &this) -> Result<Option<u8>, IoError>;
    read_char(mut &this) -> Result<Option<u32>, IoError>;
    read_until(mut &this, delimiter: u8, out: mut &Array<u8>) -> Result<u64, IoError>;
    read_exact(mut &this, buffer: u8*, length: u64) -> Result<(), IoError>;
    read_to_end(mut &this, out: mut &Array<u8>) -> Result<u64, IoError>;
    read_to_string(mut &this, out: mut &String) -> Result<u64, IoError>;
    read_line(mut &this, out: mut &String) -> Result<u64, IoError>;
}

read is the only required method. It fills up to length bytes and returns how many it actually got. Zero means EOF. A value less than length means the source had nothing more available at this moment — not necessarily EOF, and it is the caller's decision whether to retry.

Everything else is a default built on that one method.

read_all fills the buffer or hits EOF, retrying on Interrupted; read_exact treats a short read at EOF as UnexpectedEof. read_byte returns None at EOF. read_until and read_line include the delimiter in out; read_to_end and read_to_string take every remaining byte.

read_char fails with UnexpectedEof on a partial scalar and InvalidData on a malformed leading byte, a malformed continuation, or a surrogate — surrogates are not valid Unicode scalars.

Two things worth knowing. read_to_end is unbounded: a pathological source like /dev/zero will exhaust memory, so cap it yourself if the input is untrusted. And read_to_string does not validate UTF-8 — you are certifying that the source is well-formed, or accepting invalid continuation bytes inside a String.

read_until and read_line are byte-level, running read(..., 1) so the stop point is exact. On a source where a one-byte read is expensive — a socket, a file — wrap it in a BufReader, whose read_line override is the fast path.

Methods

read(mut &this, buffer: u8*, length: u64) -> Result<u64, IoError>;

Fill up to length bytes starting at buffer. Returns the number of bytes actually read. Zero means EOF; a value less than length means the underlying source had no more bytes available at this moment (not necessarily EOF; callers decide whether to retry).

read_all(mut &this, buffer: u8*, length: u64) -> Result<u64, IoError>;

Read until the buffer is full or the source returns 0 (EOF). Returns the total bytes read; short returns mean EOF reached. Retries on Interrupted.

read_byte(mut &this) -> Result<Option<u8>, IoError>;

Read a single byte. None means EOF: the source is empty and no more reads will yield data. Retries on Interrupted.

read_char(mut &this) -> Result<Option<u32>, IoError>;

Read a single UTF-8 Unicode scalar and return its codepoint. None is EOF before the first byte of the scalar. A partial scalar (first byte read, continuation missing) fails with UnexpectedEof; a malformed leading byte or continuation fails with InvalidData. Surrogates (0xD800..=0xDFFF) likewise fail with InvalidData; they are not valid Unicode scalars.

read_until(mut &this, delimiter: u8, out: mut &Array<u8>) -> Result<u64, IoError>;

Read bytes into out until delimiter is seen or EOF. The delimiter byte is included in out. Returns the number of bytes appended.

read_exact(mut &this, buffer: u8*, length: u64) -> Result<(), IoError>;

Read exactly length bytes. A short read at EOF is a failure, reported as UnexpectedEof. Use this when the caller knows the precise number of bytes that must be present.

read_to_end(mut &this, out: mut &Array<u8>) -> Result<u64, IoError>;

Read every remaining byte into out, growing the array as needed. Returns the number of bytes appended. EOF terminates the loop; other errors abort and surface.

read_to_string(mut &this, out: mut &String) -> Result<u64, IoError>;

Read every remaining byte into out as UTF-8. Convenience wrapper around read_to_end for the common "slurp text from this source" case. The bytes are not validated; the caller certifies the source is UTF-8 (or accepts the consequences of invalid continuation bytes in a String).

read_line(mut &this, out: mut &String) -> Result<u64, IoError>;

Read bytes into out until a \n or EOF. The newline byte is included in out. Returns the number of bytes appended (0 only if the very first read hit EOF).

Implementors

implement trait Read for struct File
std::fs::file
implement<R> trait Read for struct BufReader<R> where R: Read
std::io::buf
implement trait Read for struct Cursor
std::io::cursor
implement trait Read for struct Stdin
std::io::stdio
implement trait Read for struct StdinLock
std::io::stdio
implement trait Read for struct ChildStdout
std::process::child
implement trait Read for struct ChildStderr
std::process::child

Write

type trait Write {
    write_some(mut &this, bytes: Slice<u8>) -> Result<u64, IoError>;
    flush(mut &this) -> Result<(), IoError>;
    write<T>(mut &this, data: T) -> Result<(), IoError>;
}

write_some is the low-level primitive: write up to bytes.length() bytes and report how many actually landed, which may be fewer on a slow sink. Unbuffered writers override flush with a no-op.

write<T>(data) is the one you normally call. It delivers every byte, retrying short writes and Interrupted, and dispatches on the payload at compile time: a raw Slice<u8>, a Str, a NUL-terminated string, or a single u8. If the sink repeatedly refuses to make progress it fails with WriteZero rather than spinning.

Methods

write_some(mut &this, bytes: Slice<u8>) -> Result<u64, IoError>;

Low-level primitive: write up to bytes.length() bytes, returning the number actually written (may be less than requested on a slow sink). Every implementor provides this; the generic write loops over it to deliver every byte.

flush(mut &this) -> Result<(), IoError>;

Push any buffered bytes to the underlying sink. Unbuffered writers override with a no-op.

write<T>(mut &this, data: T) -> Result<(), IoError>;

Write data in full, retrying short writes and Interrupted errors. Generic over the payload, dispatched at compile time via static match: a raw byte Slice<u8>, a Str view, a NUL-terminated C string, or a single u8. Fails with WriteZero if the sink repeatedly refuses progress; better to surface that than spin.

Implementors

implement trait Write for struct File
std::fs::file
implement<W> trait Write for struct BufWriter<W> where W: Write
std::io::buf
implement<W> trait Write for struct LineWriter<W> where W: Write
std::io::buf
implement trait Write for struct Cursor
std::io::cursor
implement trait Write for struct Stdout
std::io::stdio
implement trait Write for struct Stderr
std::io::stdio
implement trait Write for struct StdoutLock
std::io::stdio
implement trait Write for struct StderrLock
std::io::stdio
implement trait Write for struct ChildStdin
std::process::child

Seek

type trait Seek {
    seek(mut &this, from: SeekFrom) -> Result<u64, IoError>;
    stream_position(mut &this) -> Result<u64, IoError>;
    rewind(mut &this) -> Result<(), IoError>;
}

seek repositions the cursor and returns the resulting absolute offset. stream_position() reports the current offset without moving, defaulting to seek(Current(0)); rewind() is seek(Start(0)).

Seeking past the end is permitted, and what happens next is sink-specific: a File leaves a sparse gap the OS zero-fills, while a Cursor zero-fills on the next write. Seeking to a negative absolute offset fails with InvalidInput.

Methods

seek(mut &this, from: SeekFrom) -> Result<u64, IoError>;

Reposition the cursor and return the new absolute offset from the start of the stream. Seeking past the end is permitted; the effect of a later read/write there is sink-specific (a File leaves a sparse gap the OS zero-fills; an in-memory Cursor zero-fills on the next write). Seeking to a negative absolute offset fails with InvalidInput.

stream_position(mut &this) -> Result<u64, IoError>;

Current absolute offset, without moving. Default: seek(Current(0)).

rewind(mut &this) -> Result<(), IoError>;

Reposition to the start of the stream. Default: seek(Start(0)).

SeekFrom

type enum SeekFrom {
    Start(u64);
    Current(i64);
    End(i64);
}
Variants
Variant
Start(u64)
Current(i64)
End(i64)

Implementors

implement trait Seek for struct File
std::fs::file
implement trait Seek for struct Cursor
std::io::cursor

The async traits

The non-blocking counterparts of Read and Write, shaped for a buffered connection rather than a bare byte stream.

AsyncRead

type trait AsyncRead {
    async fill(mut &this) -> Result<u64, IoError>;
    buffered(&this) -> Slice<u8>;
    consume(mut &this, count: u64) -> void;
    scan_for(&this, delimiter: u8, from: u64) -> u64;
    take_front(mut &this, count: u64) -> Result<Array<u8>, IoError>;
    async ensure(mut &this, count: u64) -> Result<(), IoError>;
    async read_exact(mut &this, count: u64) -> Result<Array<u8>, IoError>;
    async read_some(mut &this, limit: u64) -> Result<Array<u8>, IoError>;
    async read_until(mut &this, delimiter: u8, limit: u64) -> Result<Array<u8>, IoError>;
    async read_line(mut &this, limit: u64) -> Result<String, IoError>;
    async skip(mut &this, count: u64) -> Result<(), IoError>;
}

Where Read hands you bytes, AsyncRead hands you a view into its own buffer: fill pulls more from the transport (suspending rather than blocking; zero means the peer closed), buffered() is what has arrived and not yet been consumed, and consume(n) releases the front of it. Every default — read_until, read_line, ensure, read_exact — is a scan over that buffer. The slice from buffered() is valid only until the next fill or consume; do not hold it across an await.

read_until and read_line take a limit so a peer that never sends the delimiter cannot drive the buffer to exhaust memory — exceeding it is InvalidData. read_line strips the terminator, and a \r before it, so CRLF and LF framing read alike.

Methods
async fill(mut &this) -> Result<u64, IoError>;

Pull more bytes from the transport into the connection's buffer and return how many arrived. Zero means the peer closed its end: no later fill will produce anything either.

buffered(&this) -> Slice<u8>;

The bytes that have been read but not yet consumed.

consume(mut &this, count: u64) -> void;

Discard the first count buffered bytes, which the caller has finished with. count must not exceed buffered().length().

scan_for(&this, delimiter: u8, from: u64) -> u64;

Index just past the first delimiter at or after from, or 0 when it is not in the buffer yet.

take_front(mut &this, count: u64) -> Result<Array<u8>, IoError>;

Copy the first count buffered bytes out and consume them. Callers that can parse in place should read buffered() directly and call consume themselves; this is for the cases that need to keep the bytes past the next fill.

async ensure(mut &this, count: u64) -> Result<(), IoError>;

Fill until at least count bytes are buffered. EOF before that is UnexpectedEof: the caller asked for bytes the peer will never send.

async read_exact(mut &this, count: u64) -> Result<Array<u8>, IoError>;

Read exactly count bytes and hand them back. A short stream is UnexpectedEof.

async read_some(mut &this, limit: u64) -> Result<Array<u8>, IoError>;

Read whatever is available, up to limit bytes, suspending only if nothing is buffered yet. An empty result means EOF — it is the terminating condition for a streaming copy, not an error.

async read_until(mut &this, delimiter: u8, limit: u64) -> Result<Array<u8>, IoError>;

Read up to and including the first delimiter. The delimiter is part of the returned bytes.

async read_line(mut &this, limit: u64) -> Result<String, IoError>;

Read one \n-terminated line, without the terminator. A \r immediately before it is stripped too, so this reads CRLF and LF framing alike. limit caps the line length as in read_until.

async skip(mut &this, count: u64) -> Result<(), IoError>;

Discard exactly count bytes. Cheaper than read_exact for payload a caller is required to consume but does not want, such as frame padding.

AsyncWrite

type trait AsyncWrite {
    pending(mut &this) -> Array<u8>*;
    async flush(mut &this) -> Result<(), IoError>;
    queue<T>(mut &this, data: T) -> Result<(), IoError>;
    async send<T>(mut &this, data: T) -> Result<(), IoError>;
}

AsyncWrite exposes its outgoing buffer through pending() so an encoder can build a frame in place. queue appends without sending; flush puts everything on the wire, leaving the unsent bytes queued on failure so a retry still has them; send is queue then flush.

Methods
pending(mut &this) -> Array<u8>*;

The connection's outgoing buffer, for queue to append to and flush to drain. Exposed rather than wrapped so an encoder can build a frame directly in place instead of into a scratch array that is then copied.

async flush(mut &this) -> Result<(), IoError>;

Put every queued byte on the wire, suspending as often as the transport needs, and clear the buffer. A failure leaves the unsent bytes queued, so a caller that can retry still has them.

queue<T>(mut &this, data: T) -> Result<(), IoError>;

Append data to the outgoing buffer without sending anything. Generic over the payload and dispatched at compile time: a raw Slice<u8>, a Str view, a NUL-terminated C string, or a single u8.

async send<T>(mut &this, data: T) -> Result<(), IoError>;

Queue data and send it immediately. The one-shot convenience for a caller with nothing else to add; a caller with several pieces should queue each and flush once.

AsyncTransport

type trait AsyncTransport {
    async read_into(mut &this, buf: Array<u8>) -> Transfer;
    async write_from(mut &this, buf: Array<u8>) -> Transfer;
}
type struct Transfer {
    buf:    Array<u8>;
    result: Result<u64, IoError>;

    take_buf(mut &this) -> Array<u8>;
    outcome(&this) -> Result<u64, IoError>;
}

AsyncTransport is the seam underneath both: two operations that move an owned buffer to the transport and back through a Transfer. This is what lets a plaintext TcpStream and a TlsStream share one BufStream implementation — everything above the seam is written once.

AsyncTransport
Methods

####### async read_into(mut &this, buf: Array<u8>) -> Transfer;

Read into buf, completing with the bytes that arrived. Zero means the peer closed its end.

####### async write_from(mut &this, buf: Array<u8>) -> Transfer;

Write from buf, completing with the bytes accepted, which may be fewer than offered — the caller sends the remainder in another operation.

Transfer
Properties
PropertyType
bufArray<u8>
resultResult<u64, IoError>
Methods

####### take_buf(mut &this) -> Array<u8>;

Take the buffer back. Calling it twice yields an empty array the second time — the transfer holds the buffer exactly once.

####### outcome(&this) -> Result<u64, IoError>;

How many bytes moved, or why none did.

Implementors

implement<S> trait AsyncRead for struct BufStream<S>
std::io::buf
implement<S> trait AsyncWrite for struct BufStream<S>
std::io::buf
implement trait AsyncTransport for struct TcpStream
std::net::socket::tcp
implement trait AsyncTransport for struct TlsStream
std::net::tls::future

Constants

const READ_TO_END_CHUNK: u64 = 4096;
const BYTE_LF:           u8  = 0x0A;
const BYTE_CR:           u8  = 0x0D;