Skip to content
CryoCryo home

traits

import std::io::traits; · source

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.

MethodBehaviour
read_all(buffer, length)Read until the buffer is full or EOF. Retries on Interrupted.
read_exact(buffer, length)Read exactly length bytes; a short read at EOF is UnexpectedEof.
read_byte()None is EOF.
read_char()One UTF-8 scalar.
read_until(delimiter, out)Reads through the delimiter, which is included in out.
read_line(out)Reads through \n, which is included.
read_to_end(out)Every remaining byte.
read_to_string(out)Every remaining byte as UTF-8.

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.

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.

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.

SeekFrom

type enum SeekFrom {
    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.

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.

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.

Implementors

implement trait AsyncRead for struct BufStream<S>   // std::io::buf
implement 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