Qubit IO
Small stream I/O trait and extension utilities for Rust.
Overview
Qubit IO is focused on stream and byte I/O built on top of std::io. It does
not try to become a filesystem abstraction layer. The crate provides reusable
building blocks for code that reads, writes, seeks, buffers, encodes, decodes,
limits, tees, counts, or compares byte streams.
Use this crate when you need:
- object-safe trait aliases for common
std::iocapability combinations; - extension methods for exact reads, bounded reads, bounded delimiter reads, and position-preserving seek operations;
- small stream helper functions such as bounded copy and content comparison;
- binary, LEB128, ZigZag, and length-prefixed UTF-8 encoding helpers;
- wrapper types for counting, limiting, teeing, checksumming, and seek-position restoration;
- reader/writer codec objects, including buffered variants for high-throughput scalar decoding and encoding.
For detailed usage, examples, and API selection guidance, see the User Guide. API reference documentation is available on docs.rs.
For local filesystem capabilities, see qubit-local-files.
Installation
[]
= "0.3"
Quick Example
use Cursor;
use ;
let mut input = new;
let mut output = Vecnew;
copy?;
assert_eq!;
let mut cursor = new;
cursor.write_all_at_preserving_position?;
let data = new.read_to_end_limited?;
assert_eq!;
# Ok::
Main Capabilities
Object-Safe I/O Trait Combinations
qubit-io provides named composition traits that can be used as trait objects:
| Trait | Combines | Typical use |
|---|---|---|
ReadSeek |
Read + Seek |
readable random-access input |
BufReadSeek |
BufRead + Seek |
buffered random-access input |
ReadWrite |
Read + Write |
duplex stream or mutable buffer |
WriteSeek |
Write + Seek |
writable random-access output |
ReadWriteSeek |
Read + Write + Seek |
fully mutable random-access I/O object |
These traits are useful when an API should accept &mut dyn ReadSeek instead
of being generic over R: Read + Seek.
Buffer Codecs
The codec module contains buffer-level helpers that do not depend on
std::io::Read or std::io::Write:
| Type | Purpose |
|---|---|
Coder |
progress-oriented conversion trait for caller-managed buffers |
CoderProgress, CoderStatus |
conversion progress and stop reason reporting |
BinaryCodec |
unchecked fixed-width scalar encoding and decoding on caller-validated byte buffers |
Leb128Codec, ZigZagCodec |
unchecked compact integer encoding on caller-validated byte buffers |
Leb128DecodeError |
structured LEB128 decode error reporting |
BinaryCodec, Leb128Codec, and ZigZagCodec expose static unsafe
read_unchecked and write_unchecked functions for hot paths where the caller
has already validated buffer capacity. Each concrete codec specialization
provides REQUIRED_MIN_BUFFER_LEN, the minimum caller-provided buffer capacity
that can hold one value for that specialization.
Extension Traits
The extension traits keep common low-level I/O patterns close to the standard library while avoiding repeated boilerplate:
| Extension trait | Examples |
|---|---|
ReadExt |
read_exact_or_eof, discard_exact_or_eof, copy_to, read_to_end_limited, read_to_string_limited |
BufReadExt |
read_until_limited, read_line_limited, discard_until_limited |
SeekExt |
stream_size |
ReadSeekExt |
peek_exact_or_eof, read_exact_or_eof_at |
WriteSeekExt |
write_all_at_preserving_position |
BinaryReadExt / BinaryWriteExt |
fixed-width integer and floating-point scalar encoding |
Leb128ReadExt / Leb128WriteExt |
unsigned and signed LEB128 integer encoding |
ZigZagReadExt / ZigZagWriteExt |
ZigZag-mapped signed integer encoding |
StringReadExt / StringWriteExt |
length-prefixed UTF-8 strings |
usize and isize LEB128/ZigZag methods use the current Rust target's pointer
width. They are convenient for in-process Rust data, but fixed-width integer
methods such as u64 or i64 are the safer choice for persistent files and
cross-platform protocols. The ULEB string helpers encode the byte length as
usize; use the u16 or u32 string helpers when the wire format must be
target-independent.
Streams Namespace
Streams contains stream-level associated functions:
| Method | Purpose |
|---|---|
copy |
delegates to std::io::copy |
copy_at_most |
copies no more than a specified number of bytes |
copy_to_end_limited |
copies only if EOF is reached within a size limit |
content_eq |
compares two readable streams for byte equality |
compare_content |
lexicographically compares two readable streams |
Wrappers
Wrapper types make stream behavior part of the type instead of a one-off call:
| Wrapper | Purpose |
|---|---|
CountingReader, CountingWriter |
count successfully read or written bytes |
LimitReader, LimitWriter |
enforce read or write byte budgets |
TeeReader, TeeWriter |
duplicate data to a branch writer |
ChecksumReader, ChecksumWriter |
update caller-provided checksum state while reading or writing |
PositionGuard |
restore a seek position on drop unless dismissed |
Codec Wrappers
Callers who prefer reader/writer objects over extension-method calls can use
root-level codec wrappers. These wrappers keep codec configuration in the
wrapper object while still behaving like normal streams: readers implement
Read, writers implement Write, and both pass through Seek when the inner
stream supports seeking.
| Wrapper | Purpose |
|---|---|
BinaryReader, BinaryWriter |
fixed-width scalar encoding and decoding with type-level byte order |
Leb128Reader, Leb128Writer |
LEB128 integers and ULEB length-prefixed UTF-8 strings |
ZigZagReader, ZigZagWriter |
ZigZag over unsigned LEB128 payloads |
BufferedBinaryReader, BufferedBinaryWriter |
buffered fixed-width scalar encoding and decoding |
BufferedLeb128Reader, BufferedLeb128Writer |
buffered LEB128 integers and ULEB length-prefixed UTF-8 strings |
BufferedZigZagReader, BufferedZigZagWriter |
buffered ZigZag over unsigned LEB128 payloads |
Buffered readers may prefetch bytes, so the wrapped reader's physical position
can be ahead of the logical position exposed by the wrapper. Calling
into_inner on a buffered reader discards unread prefetched bytes.
Buffered writers do not flush pending bytes from Drop. Call flush() or
into_inner() to guarantee delivery to the wrapped writer. Buffered writers
flush pending bytes before Seek.
Prelude
qubit_io::prelude re-exports the method-providing extension traits,
object-safe composition traits, byte order, and buffer codec types. It
intentionally does not re-export stream wrapper types.
use *;
Crate Boundary
qubit-io is intentionally limited to stream and byte I/O. It does not expose
local path helpers, temporary files, directory copy helpers, directory cleanup,
or atomic file writes. For local filesystem capabilities, see
qubit-local-files.
Runtime Dependencies
This crate depends on the Rust standard library and thiserror.
Testing & Code Coverage
This project maintains test coverage for the stream traits, extension methods, codec helpers, and wrapper types.
Running Tests
# Run all tests
# Run with coverage report
# Generate text format report
# Run CI checks (format, clippy, test, coverage, audit)
License
Copyright (c) 2026. Haixing Hu.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
See LICENSE for the full license text.
Contributing
Contributions are welcome. Please feel free to submit a Pull Request.
Development Guidelines
- Follow the Rust API guidelines.
- Keep stream and byte-I/O concerns in
qubit-io. - Use qubit-local-files for local filesystem utilities.
- Maintain comprehensive test coverage.
- Document public APIs with examples when they clarify behavior.
- Ensure
./ci-check.shpasses before submitting a PR.
Author
Haixing Hu
Related Projects
- qubit-local-files: local filesystem utilities for Rust.
- More Rust libraries from Qubit are published under the qubit-ltd organization on GitHub.
Repository: https://github.com/qubit-ltd/rs-io