Struct io_streams::BufDuplexer

source ·
pub struct BufDuplexer<Inner: HalfDuplex> { /* private fields */ }
Expand description

Wraps a reader and writer and buffers their output.

It can be excessively inefficient to work directly with something that implements Write. For example, every call to write on TcpStream results in a system call. A BufDuplexer<Inner> keeps an in-memory buffer of data and writes it to an underlying writer in large, infrequent batches.

It can be excessively inefficient to work directly with a Read instance. For example, every call to read on TcpStream results in a system call. A BufDuplexer<Inner> performs large, infrequent reads on the underlying Read and maintains an in-memory buffer of the results.

BufDuplexer<Inner> can improve the speed of programs that make small and repeated write calls to the same file or network socket. It does not help when writing very large amounts at once, or writing just one or a few times. It also provides no advantage when writing to a destination that is in memory, like a Vec<u8>.

BufDuplexer<Inner> can improve the speed of programs that make small and repeated read calls to the same file or network socket. It does not help when reading very large amounts at once, or reading just one or a few times. It also provides no advantage when reading from a source that is already in memory, like a Vec<u8>.

It is critical to call flush before BufDuplexer<Inner> is dropped. Though dropping will attempt to flush the contents of the writer buffer, any errors that happen in the process of dropping will be ignored. Calling flush ensures that the writer buffer is empty and thus dropping will not even attempt file operations.

When the BufDuplexer<Inner> is dropped, the contents of its reader buffer will be discarded. Creating multiple instances of a BufDuplexer<Inner> on the same stream can cause data loss. Reading from the underlying reader after unwrapping the BufDuplexer<Inner> with BufDuplexer::into_inner can also cause data loss.

§Examples

Let’s write the numbers one through ten to a TcpStream:

use std::io::prelude::*;
use std::net::TcpStream;

let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();

for i in 0..10 {
    stream.write(&[i + 1]).unwrap();
}

Because we’re not buffering, we write each one in turn, incurring the overhead of a system call per byte written. We can fix this with a BufDuplexer<Inner>:

use io_streams::BufDuplexer;
use std::io::prelude::*;
use std::net::TcpStream;

let mut stream = BufDuplexer::new(TcpStream::connect("127.0.0.1:34254").unwrap());

for i in 0..10 {
    stream.write(&[i + 1]).unwrap();
}
stream.flush().unwrap();

By wrapping the stream with a BufDuplexer<Inner>, these ten writes are all grouped together by the buffer and will all be written out in one system call when the stream is flushed.

use io_streams::BufDuplexer;
use std::io::prelude::*;
use std::net::TcpStream;

fn main() -> std::io::Result<()> {
    let mut stream = BufDuplexer::new(TcpStream::connect("127.0.0.1:34254").unwrap());

    let mut line = String::new();
    let len = stream.read_line(&mut line)?;
    println!("First line is {} bytes long", len);
    Ok(())
}

Implementations§

source§

impl<Inner: HalfDuplex> BufDuplexer<Inner>

source

pub fn new(inner: Inner) -> Self

Creates a new BufDuplexer<Inner> with default buffer capacities. The default is currently 8 KB, but may change in the future.

§Examples
use io_streams::BufDuplexer;
use std::net::TcpStream;

let mut buffer = BufDuplexer::new(TcpStream::connect("127.0.0.1:34254").unwrap());
source

pub fn with_capacities( reader_capacity: usize, writer_capacity: usize, inner: Inner ) -> Self

Creates a new BufDuplexer<Inner> with the specified buffer capacities.

§Examples

Creating a buffer with ten bytes of reader capacity and a writer buffer of a hundered bytes:

use io_streams::BufDuplexer;
use std::net::TcpStream;

let stream = TcpStream::connect("127.0.0.1:34254").unwrap();
let mut buffer = BufDuplexer::with_capacities(10, 100, stream);
source

pub fn get_ref(&self) -> &Inner

Gets a reference to the underlying reader/writer.

§Examples
use io_streams::BufDuplexer;
use std::net::TcpStream;

let mut buffer = BufDuplexer::new(TcpStream::connect("127.0.0.1:34254").unwrap());

// we can use reference just like buffer
let reference = buffer.get_ref();
source

pub fn get_mut(&mut self) -> &mut Inner

Gets a mutable reference to the underlying reader/writer.

It is inadvisable to directly write to the underlying reader/writer.

§Examples
use io_streams::BufDuplexer;
use std::net::TcpStream;

let mut buffer = BufDuplexer::new(TcpStream::connect("127.0.0.1:34254").unwrap());

// we can use reference just like buffer
let reference = buffer.get_mut();
source

pub fn writer_buffer(&self) -> &[u8]

Returns a reference to the internally buffered writer data.

§Examples
use io_streams::BufDuplexer;
use std::net::TcpStream;

let buf_writer = BufDuplexer::new(TcpStream::connect("127.0.0.1:34254").unwrap());

// See how many bytes are currently buffered
let bytes_buffered = buf_writer.writer_buffer().len();
source

pub fn reader_buffer(&self) -> &[u8]

Returns a reference to the internally buffered reader data.

Unlike fill_buf, this will not attempt to fill the buffer if it is empty.

§Examples
use char_device::CharDevice;
use io_streams::BufDuplexer;
use std::fs::File;
use std::io::BufRead;

fn main() -> std::io::Result<()> {
    let f = CharDevice::new(File::open("/dev/ttyS0")?)?;
    let mut reader = BufDuplexer::new(f);
    assert!(reader.reader_buffer().is_empty());

    if reader.fill_buf()?.len() > 0 {
        assert!(!reader.reader_buffer().is_empty());
    }
    Ok(())
}
source

pub fn writer_capacity(&self) -> usize

Returns the number of bytes the internal writer buffer can hold without flushing.

§Examples
use io_streams::BufDuplexer;
use std::net::TcpStream;

let buf_duplexer = BufDuplexer::new(TcpStream::connect("127.0.0.1:34254").unwrap());

// Check the capacity of the inner buffer
let capacity = buf_duplexer.writer_capacity();
// Calculate how many bytes can be written without flushing
let without_flush = capacity - buf_duplexer.writer_buffer().len();
source

pub fn reader_capacity(&self) -> usize

Returns the number of bytes the internal reader buffer can hold at once.

§Examples
use char_device::CharDevice;
use io_streams::BufDuplexer;
use std::fs::File;
use std::io::BufRead;

fn main() -> std::io::Result<()> {
    let f = CharDevice::new(File::open("/dev/tty")?)?;
    let mut reader = BufDuplexer::new(f);

    let capacity = reader.reader_capacity();
    let buffer = reader.fill_buf()?;
    assert!(buffer.len() <= capacity);
    Ok(())
}
source

pub fn into_inner(self) -> Result<Inner, IntoInnerError<Self>>

Unwraps this BufDuplexer<Inner>, returning the underlying reader/writer.

The buffer is written out before returning the reader/writer.

§Errors

An Err will be returned if an error occurs while flushing the buffer.

§Examples
use io_streams::BufDuplexer;
use std::net::TcpStream;

let mut buffer = BufDuplexer::new(TcpStream::connect("127.0.0.1:34254").unwrap());

// unwrap the TcpStream and flush the buffer
let stream = buffer.into_inner().unwrap();

Trait Implementations§

source§

impl<Inner: HalfDuplex + AsFd> AsFd for BufDuplexer<Inner>

source§

fn as_fd(&self) -> BorrowedFd<'_>

Borrows the file descriptor. Read more
source§

impl<Inner: HalfDuplex + AsRawFd> AsRawFd for BufDuplexer<Inner>

source§

fn as_raw_fd(&self) -> RawFd

Extracts the raw file descriptor. Read more
source§

impl<Inner: HalfDuplex> BufRead for BufDuplexer<Inner>

source§

fn fill_buf(&mut self) -> Result<&[u8]>

Returns the contents of the internal buffer, filling it with more data from the inner reader if it is empty. Read more
source§

fn consume(&mut self, amt: usize)

Tells this buffer that amt bytes have been consumed from the buffer, so they should no longer be returned in calls to read. Read more
source§

fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize>

Read all bytes into buf until the delimiter byte or EOF is reached. Read more
source§

fn read_line(&mut self, buf: &mut String) -> Result<usize>

Read all bytes until a newline (the 0xA byte) is reached, and append them to the provided String buffer. Read more
source§

fn has_data_left(&mut self) -> Result<bool, Error>

🔬This is a nightly-only experimental API. (buf_read_has_data_left)
Check if the underlying Read has any data left to be read. Read more
source§

fn skip_until(&mut self, byte: u8) -> Result<usize, Error>

🔬This is a nightly-only experimental API. (bufread_skip_until)
Skip all bytes until the delimiter byte or EOF is reached. Read more
1.0.0 · source§

fn split(self, byte: u8) -> Split<Self>
where Self: Sized,

Returns an iterator over the contents of this reader split on the byte byte. Read more
1.0.0 · source§

fn lines(self) -> Lines<Self>
where Self: Sized,

Returns an iterator over the lines of this reader. Read more
source§

impl<Inner> Debug for BufDuplexer<Inner>
where Inner: Debug + HalfDuplex,

source§

fn fmt(&self, fmt: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<Inner: HalfDuplex> Read for BufDuplexer<Inner>

source§

fn read(&mut self, buf: &mut [u8]) -> Result<usize>

Pull some bytes from this source into the specified buffer, returning how many bytes were read. Read more
source§

fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>

Like read, except that it reads into a slice of buffers. Read more
source§

fn is_read_vectored(&self) -> bool

🔬This is a nightly-only experimental API. (can_vector)
Determines if this Reader has an efficient read_vectored implementation. Read more
1.0.0 · source§

fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, Error>

Read all bytes until EOF in this source, placing them into buf. Read more
1.0.0 · source§

fn read_to_string(&mut self, buf: &mut String) -> Result<usize, Error>

Read all bytes until EOF in this source, appending them to buf. Read more
1.6.0 · source§

fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error>

Read the exact number of bytes required to fill buf. Read more
source§

fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<(), Error>

🔬This is a nightly-only experimental API. (read_buf)
Pull some bytes from this source into the specified buffer. Read more
source§

fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> Result<(), Error>

🔬This is a nightly-only experimental API. (read_buf)
Read the exact number of bytes required to fill cursor. Read more
1.0.0 · source§

fn by_ref(&mut self) -> &mut Self
where Self: Sized,

Creates a “by reference” adaptor for this instance of Read. Read more
1.0.0 · source§

fn bytes(self) -> Bytes<Self>
where Self: Sized,

Transforms this Read instance to an Iterator over its bytes. Read more
1.0.0 · source§

fn chain<R>(self, next: R) -> Chain<Self, R>
where R: Read, Self: Sized,

Creates an adapter which will chain this stream with another. Read more
1.0.0 · source§

fn take(self, limit: u64) -> Take<Self>
where Self: Sized,

Creates an adapter which will read at most limit bytes from it. Read more
source§

impl<Inner: HalfDuplex> Write for BufDuplexer<Inner>

source§

fn write(&mut self, buf: &[u8]) -> Result<usize>

Write a buffer into this writer, returning how many bytes were written. Read more
source§

fn write_all(&mut self, buf: &[u8]) -> Result<()>

Attempts to write an entire buffer into this writer. Read more
source§

fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize>

Like write, except that it writes from a slice of buffers. Read more
source§

fn is_write_vectored(&self) -> bool

🔬This is a nightly-only experimental API. (can_vector)
Determines if this Writer has an efficient write_vectored implementation. Read more
source§

fn flush(&mut self) -> Result<()>

Flush this output stream, ensuring that all intermediately buffered contents reach their destination. Read more
source§

fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> Result<(), Error>

🔬This is a nightly-only experimental API. (write_all_vectored)
Attempts to write multiple buffers into this writer. Read more
1.0.0 · source§

fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<(), Error>

Writes a formatted string into this writer, returning any error encountered. Read more
1.0.0 · source§

fn by_ref(&mut self) -> &mut Self
where Self: Sized,

Creates a “by reference” adapter for this instance of Write. Read more

Auto Trait Implementations§

§

impl<Inner> Freeze for BufDuplexer<Inner>
where Inner: Freeze,

§

impl<Inner> RefUnwindSafe for BufDuplexer<Inner>
where Inner: RefUnwindSafe,

§

impl<Inner> Send for BufDuplexer<Inner>
where Inner: Send,

§

impl<Inner> Sync for BufDuplexer<Inner>
where Inner: Sync,

§

impl<Inner> Unpin for BufDuplexer<Inner>
where Inner: Unpin,

§

impl<Inner> UnwindSafe for BufDuplexer<Inner>
where Inner: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> AsFilelike for T
where T: AsFd,

source§

fn as_filelike(&self) -> BorrowedFd<'_>

Borrows the reference. Read more
source§

fn as_filelike_view<Target>(&self) -> FilelikeView<'_, Target>
where Target: FilelikeViewType,

Return a borrowing view of a resource which dereferences to a &Target. Read more
source§

impl<T> AsGrip for T
where T: AsFd,

source§

fn as_grip(&self) -> BorrowedFd<'_>

Extracts the grip.
source§

impl<T> AsRawFilelike for T
where T: AsRawFd,

source§

fn as_raw_filelike(&self) -> i32

Returns the raw value.
source§

impl<T> AsRawGrip for T
where T: AsRawFd,

source§

fn as_raw_grip(&self) -> i32

Extracts the raw grip.
source§

impl<T> AsRawSocketlike for T
where T: AsRawFd,

source§

fn as_raw_socketlike(&self) -> i32

Returns the raw value.
source§

impl<T> AsSocketlike for T
where T: AsFd,

source§

fn as_socketlike(&self) -> BorrowedFd<'_>

Borrows the reference.
source§

fn as_socketlike_view<Target>(&self) -> SocketlikeView<'_, Target>
where Target: SocketlikeViewType,

Return a borrowing view of a resource which dereferences to a &Target. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> FileIoExt for T
where T: AsFilelike + IoExt,

source§

fn advise(&self, offset: u64, len: u64, advice: Advice) -> Result<(), Error>

Announce the expected access pattern of the data at the given offset.
source§

fn allocate(&self, offset: u64, len: u64) -> Result<(), Error>

Allocate space in the file, increasing the file size as needed, and ensuring that there are no holes under the given range.
source§

fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize, Error>

Reads a number of bytes starting from a given offset. Read more
source§

fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> Result<(), Error>

Reads the exact number of byte required to fill buf from the given offset. Read more
source§

fn read_vectored_at( &self, bufs: &mut [IoSliceMut<'_>], offset: u64 ) -> Result<usize, Error>

Is to read_vectored what read_at is to read.
source§

fn is_read_vectored_at(&self) -> bool

Determines if this FileIoExt implementation has an efficient read_vectored_at implementation.
source§

fn read_to_end_at(&self, buf: &mut Vec<u8>, offset: u64) -> Result<usize, Error>

Read all bytes, starting at offset, until EOF in this source, placing them into buf.
source§

fn read_to_string_at( &self, buf: &mut String, offset: u64 ) -> Result<usize, Error>

Read all bytes, starting at offset, until EOF in this source, appending them to buf.
source§

fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize, Error>

Writes a number of bytes starting from a given offset. Read more
source§

fn write_all_at(&self, buf: &[u8], offset: u64) -> Result<(), Error>

Attempts to write an entire buffer starting from a given offset. Read more
source§

fn write_vectored_at( &self, bufs: &[IoSlice<'_>], offset: u64 ) -> Result<usize, Error>

Is to write_vectored what write_at is to write.
source§

fn is_write_vectored_at(&self) -> bool

Determines if this FileIoExt implementation has an efficient write_vectored_at implementation.
source§

fn append(&self, buf: &[u8]) -> Result<usize, Error>

Writes a number of bytes at the end of a file. Read more
source§

fn append_vectored(&self, bufs: &[IoSlice<'_>]) -> Result<usize, Error>

Is to append what write_vectored is to write.
source§

fn is_append_vectored(&self) -> bool

Determines if this FileIoExt implementation has an efficient append_vectored implementation.
source§

fn seek(&self, pos: SeekFrom) -> Result<u64, Error>

Seek to an offset, in bytes, in a stream. Read more
source§

fn stream_position(&self) -> Result<u64, Error>

Returns the current seek position from the start of the stream. Read more
source§

fn read_exact_vectored_at( &self, bufs: &mut [IoSliceMut<'_>], offset: u64 ) -> Result<(), Error>

Is to read_exact_vectored what read_exact_at is to read_exact.
source§

fn write_all_vectored_at( &self, bufs: &mut [IoSlice<'_>], offset: u64 ) -> Result<(), Error>

Is to write_all_vectored what write_all_at is to write_all.
source§

fn append_all(&self, buf: &[u8]) -> Result<(), Error>

Attempts to write an entire buffer at the end of a file. Read more
source§

fn append_all_vectored(&self, bufs: &mut [IoSlice<'_>]) -> Result<(), Error>

Is to append_all what write_all_vectored is to write_all.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> GetSetFdFlags for T

source§

fn get_fd_flags(&self) -> Result<FdFlags, Error>
where T: AsFilelike,

Query the “status” flags for the self file descriptor.
source§

fn new_set_fd_flags(&self, fd_flags: FdFlags) -> Result<SetFdFlags<T>, Error>
where T: AsFilelike,

Create a new SetFdFlags value for use with set_fd_flags. Read more
source§

fn set_fd_flags(&mut self, set_fd_flags: SetFdFlags<T>) -> Result<(), Error>
where T: AsFilelike,

Set the “status” flags for the self file descriptor. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IoExt for T

source§

fn read(&self, buf: &mut [u8]) -> Result<usize, Error>

Pull some bytes from this source into the specified buffer, returning how many bytes were read. Read more
source§

fn read_exact(&self, buf: &mut [u8]) -> Result<(), Error>

Read the exact number of bytes required to fill buf. Read more
source§

fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize, Error>

Like read, except that it reads into a slice of buffers. Read more
source§

fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize, Error>

Read all bytes until EOF in this source, placing them into buf. Read more
source§

fn read_to_string(&self, buf: &mut String) -> Result<usize, Error>

Read all bytes until EOF in this source, appending them to buf. Read more
source§

fn peek(&self, buf: &mut [u8]) -> Result<usize, Error>

Read bytes from the current position without advancing the current position. Read more
source§

fn write(&self, buf: &[u8]) -> Result<usize, Error>

Write a buffer into this writer, returning how many bytes were written. Read more
source§

fn write_all(&self, buf: &[u8]) -> Result<(), Error>

Attempts to write an entire buffer into this writer. Read more
source§

fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> Result<usize, Error>

Like write, except that it writes from a slice of buffers. Read more
source§

fn flush(&self) -> Result<(), Error>

Flush this output stream, ensuring that all intermediately buffered contents reach their destination. Read more
source§

fn write_fmt(&self, fmt: Arguments<'_>) -> Result<(), Error>

Writes a formatted string into this writer, returning any error encountered. Read more
source§

fn read_exact_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> Result<(), Error>

Is to read_vectored what read_exact is to read.
source§

fn write_all_vectored(&self, bufs: &mut [IoSlice<'_>]) -> Result<(), Error>

Is to write_vectored what write_all is to write.
source§

impl<T> IsReadWrite for T
where T: AsFilelike,

source§

fn is_read_write(&self) -> Result<(bool, bool), Error>

Test whether the handle is readable and/or writable.
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.