Skip to content

Commit

Permalink
Add write_all and flush to Connection
Browse files Browse the repository at this point in the history
While I'm not actually using these methods in the code just yet, I have
a feeling that it might be possible to speed up some of the outbound
communication by using these new methods.

This doesn't complicate the API too much, as `write_all` comes with a
default implementation, and `flush` can usually be implemented in only a
line or two (at least when the backing stream implements
std::io::Write).
  • Loading branch information
daniel5151 committed Sep 13, 2020
1 parent 784ba85 commit fffe938
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 8 deletions.
6 changes: 6 additions & 0 deletions example_no_std/src/conn.rs
Expand Up @@ -90,4 +90,10 @@ impl Connection for TcpConnection {
Ok(Some(buf[0]))
}
}

fn flush(&mut self) -> Result<(), &'static str> {
// huh, apparently flushing isn't a "thing" for Tcp streams.
// see https://doc.rust-lang.org/src/std/net/tcp.rs.html#592-609
Ok(())
}
}
8 changes: 8 additions & 0 deletions src/connection/impls/boxed.rs
Expand Up @@ -17,7 +17,15 @@ impl<E> Connection for Box<dyn Connection<Error = E>> {
(**self).write(byte)
}

fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
(**self).write_all(buf)
}

fn peek(&mut self) -> Result<Option<u8>, Self::Error> {
(**self).peek()
}

fn flush(&mut self) -> Result<(), Self::Error> {
(**self).flush()
}
}
8 changes: 8 additions & 0 deletions src/connection/impls/mod.rs
Expand Up @@ -27,7 +27,15 @@ impl<E> Connection for &mut dyn Connection<Error = E> {
(**self).write(byte)
}

fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
(**self).write_all(buf)
}

fn peek(&mut self) -> Result<Option<u8>, Self::Error> {
(**self).peek()
}

fn flush(&mut self) -> Result<(), Self::Error> {
(**self).flush()
}
}
12 changes: 12 additions & 0 deletions src/connection/impls/tcpstream.rs
Expand Up @@ -41,4 +41,16 @@ impl Connection for TcpStream {

Write::write_all(self, &[byte])
}

fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
use std::io::Write;

Write::write_all(self, buf)
}

fn flush(&mut self) -> Result<(), Self::Error> {
use std::io::Write;

Write::flush(self)
}
}
14 changes: 13 additions & 1 deletion src/connection/impls/unixstream.rs
Expand Up @@ -5,7 +5,7 @@ use std::os::unix::net::UnixStream;

use crate::Connection;

// TODO: Remove PeekExt once rust-lang/rust#73761 is merged
// TODO: Remove PeekExt once `gdbstub`'s MSRV >1.48 (rust-lang/rust#73761)
trait PeekExt {
fn peek(&self, buf: &mut [u8]) -> io::Result<usize>;
}
Expand Down Expand Up @@ -85,4 +85,16 @@ impl Connection for UnixStream {

Write::write_all(self, &[byte])
}

fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
use std::io::Write;

Write::write_all(self, buf)
}

fn flush(&mut self) -> Result<(), Self::Error> {
use std::io::Write;

Write::flush(self)
}
}
35 changes: 28 additions & 7 deletions src/connection/mod.rs
@@ -1,6 +1,6 @@
mod impls;

/// A trait to perform bytewise I/O over a serial transport layer.
/// A trait to perform in-order, serial, byte-wise I/O.
///
/// When the `std` feature is enabled, this trait is automatically implemented
/// for [`TcpStream`](https://doc.rust-lang.org/std/net/struct.TcpStream.html)
Expand All @@ -18,18 +18,39 @@ pub trait Connection {
/// This method's default implementation calls `self.read()` for each byte
/// in the buffer. This can be quite inefficient, so if a more efficient
/// implementation exists (such as calling `read_exact()` on an underlying
/// std::io::Read object), this method should be overwritten.
/// `std::io::Read` object), this method should be overwritten.
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
buf.iter_mut().try_for_each(|b| {
for b in buf {
*b = self.read()?;
Ok(())
})
}
Ok(())
}

/// Write a single byte.
fn write(&mut self, byte: u8) -> Result<(), Self::Error>;

/// Peek a single byte. This should be a **non-blocking** operation
/// (returning None if no byte is available).
/// Write the entire buffer, blocking until complete.
///
/// This method's default implementation calls `self.write()` on each byte
/// in the buffer. This can be quite inefficient, so if a more efficient
/// implementation exists (such as calling `write_all()` on an underlying
/// `std::io::Write` object), this method should be overwritten.
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
for b in buf {
self.write(*b)?;
}
Ok(())
}

/// Peek a single byte. This MUST be a **non-blocking** operation, returning
/// None if no byte is available.
fn peek(&mut self) -> Result<Option<u8>, Self::Error>;

/// Flush this Connection, ensuring that all intermediately buffered
/// contents reach their destination.
///
/// _Note:_ Not all `Connection`s have internal buffering (e.g: writing data
/// to a UART TX register with FIFOs disabled). In these cases, it's fine to
/// simply return `Ok(())`.
fn flush(&mut self) -> Result<(), Self::Error>;
}

0 comments on commit fffe938

Please sign in to comment.