pub trait Read:
HasMemory
+ Memory
+ Debug
+ Send {
type Error: Error + Send + Sync + 'static;
// Required methods
fn read_at_most_into(
&mut self,
len: usize,
into: BytesBuf,
) -> impl Future<Output = Result<(usize, BytesBuf), Self::Error>> + Send;
fn read_more_into(
&mut self,
into: BytesBuf,
) -> impl Future<Output = Result<(usize, BytesBuf), Self::Error>> + Send;
fn read_any(
&mut self,
) -> impl Future<Output = Result<BytesBuf, Self::Error>> + Send;
}Expand description
Allows for reading of bytes.
Only supports asynchronous access, exposing the read byte sequences as bytesbuf::BytesBuf.
§Ownership
The methods on this trait accept &mut self and take an exclusive reference to the source for
the duration of the operation. This implies that only one read operation can be concurrently
executed on the object.
§Memory management for efficient I/O
For optimal efficiency when performing I/O, reads should be performed into memory optimized for the underlying I/O endpoint. This is achieved by reserving memory from the implementation’s memory provider before performing the read operation.
There are three ways to ensure you are using memory suitable for optimally efficient I/O:
- If you call methods that do not accept a
BytesBuf(such asread_any()), the implementation will reserve memory from its memory provider internally. This is the simplest way to perform reads but only a limited API surface is available in this mode. - You may call
Memory::reserve()on the implementation to reserve memory from its memory provider explicitly. This allows you to control the memory allocation more finely and potentially reuse existing buffers, improving efficiency. - You may sometimes want to call
reserve()at certain times when Rust borrowing rules do not allow you to call it directly on the implementation because it has already been borrowed. In this case, you can obtain an independent reference to the memory provider first viaHasMemory::memory(), which allows you to bypass the need to borrow the implementing object itself.
Some implementations do not perform real I/O and only move data around in memory. Such implementations typically do not have any special memory requirements and will operate with the same efficiency regardless of which buffers the data is in. Any relaxed behaviors like this will typically be described in the implementation’s API documentation.
§Thread safety
This trait requires Send from both the implementation and any returned futures.
Required Associated Types§
Required Methods§
Sourcefn read_at_most_into(
&mut self,
len: usize,
into: BytesBuf,
) -> impl Future<Output = Result<(usize, BytesBuf), Self::Error>> + Send
fn read_at_most_into( &mut self, len: usize, into: BytesBuf, ) -> impl Future<Output = Result<(usize, BytesBuf), Self::Error>> + Send
Reads at most len bytes into the provided buffer.
It is not necessary for into to be empty - the buffer may already have some
bytes of data in it (e.g. from a previous read).
The buffer will be extended with additional memory capacity
if it does not have enough remaining capacity to fit len additional bytes.
Returns a tuple of the number of bytes read and the updated buffer.
The returned BytesBuf will have 0 or more bytes of data appended to it on success,
with 0 appended bytes indicating that no more bytes can be read from this source. Any
data that was already in the buffer will remain untouched.
§Example
use bytesbuf::mem::Memory;
use bytesbuf_io::Read;
let mut source = get_source();
let buf = source.reserve(100);
let (bytes_read, mut buf) = source.read_at_most_into(10, buf).await.unwrap();
assert!(bytes_read <= 10);
let bytes = buf.consume_all();Sourcefn read_more_into(
&mut self,
into: BytesBuf,
) -> impl Future<Output = Result<(usize, BytesBuf), Self::Error>> + Send
fn read_more_into( &mut self, into: BytesBuf, ) -> impl Future<Output = Result<(usize, BytesBuf), Self::Error>> + Send
Reads an unspecified number of bytes into the provided buffer.
The implementation will decide how many bytes to read based on its internal understanding of what is optimal for sustained throughput at high efficiency. This may be a fixed size, or it may be a variable size based on the current state of the source.
It is not necessary for into to be empty - the buffer may already have some
bytes of data in it (e.g. from a previous read).
The buffer will be extended with additional memory capacity
if it does not have enough remaining capacity to fit len additional bytes.
Returns a tuple of the number of bytes read and the updated buffer.
The returned BytesBuf will have 0 or more bytes of data appended to it on success,
with 0 appended bytes indicating that no more bytes can be read from this source. Any
data that was already in the buffer will remain untouched.
§Example
use bytesbuf_io::Read;
let mut source = get_source();
let mut buf = source.read_any().await.unwrap();
if buf.len() == 0 {
println!("Source ended immediately - nothing we can do.");
return;
}
loop {
// We want at least 1 MB of data, read in whatever sized pieces the I/O endpoint
// considers optimal.
if buf.len() >= 1024 * 1024 {
println!("Got 1 MB of data");
break;
}
let (bytes_read, new_buf) = source.read_more_into(buf).await.unwrap();
buf = new_buf;
if bytes_read == 0 {
println!("Source ended - no more data before we reached 1 MB");
break;
}
}Sourcefn read_any(
&mut self,
) -> impl Future<Output = Result<BytesBuf, Self::Error>> + Send
fn read_any( &mut self, ) -> impl Future<Output = Result<BytesBuf, Self::Error>> + Send
Reads an unspecified number of bytes as a new buffer.
The implementation will decide how many bytes to read based on its internal understanding of what is optimal for sustained throughput at high efficiency. This may be a fixed size, or it may be a variable size based on the current state of the source.
The returned BytesBuf will have 0 or more bytes of data appended to it on success,
with 0 appended bytes indicating that no more bytes can be read from this source.
§Security
This method is insecure if the side producing the bytes is not trusted. An attacker may trickle data byte-by-byte, consuming a large amount of I/O resources.
Robust code working with untrusted sources should take precautions such as only processing
read data when either a time or length threshold is reached and reusing buffers that
have remaining capacity, appending additional data to existing buffers using
read_more_into() instead of reserving new buffers
for each read operation.
§Example
use bytesbuf_io::Read;
let mut source = get_source();
let buf = source.read_any().await.unwrap();
println!("first read produced {} bytes of data", buf.len());Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.