1 //! Traits to perform in-order, serial, byte-wise I/O.
2 
3 mod impls;
4 
5 /// A trait to perform in-order, serial, byte-wise I/O.
6 ///
7 /// When the `std` feature is enabled, this trait is automatically implemented
8 /// for [`TcpStream`](std::net::TcpStream) and
9 /// [`UnixStream`](std::os::unix::net::UnixStream) (on unix systems).
10 pub trait Connection {
11     /// Transport-specific error type.
12     type Error;
13 
14     /// Write a single byte.
write(&mut self, byte: u8) -> Result<(), Self::Error>15     fn write(&mut self, byte: u8) -> Result<(), Self::Error>;
16 
17     /// Write the entire buffer, blocking until complete.
18     ///
19     /// This method's default implementation calls `self.write()` on each byte
20     /// in the buffer. This can be quite inefficient, so if a more efficient
21     /// implementation exists (such as calling `write_all()` on an underlying
22     /// `std::io::Write` object), this method should be overwritten.
write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error>23     fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
24         for b in buf {
25             self.write(*b)?;
26         }
27         Ok(())
28     }
29 
30     /// Flush this Connection, ensuring that all intermediately buffered
31     /// contents reach their destination.
32     ///
33     /// _Note:_ Not all `Connection`s have internal buffering (e.g: writing data
34     /// to a UART TX register with FIFOs disabled). In these cases, it's fine to
35     /// simply return `Ok(())`.
flush(&mut self) -> Result<(), Self::Error>36     fn flush(&mut self) -> Result<(), Self::Error>;
37 
38     /// Called at the start of a debugging session _before_ any GDB packets have
39     /// been sent/received.
40     ///
41     /// This method's default implementation is a no-op.
42     ///
43     /// # Example
44     ///
45     /// The `on_session_start` implementation for `TcpStream` ensures that
46     /// [`set_nodelay(true)`](std::net::TcpStream::set_nodelay)
47     /// is called. The GDB remote serial protocol requires sending/receiving
48     /// many small packets, so forgetting to enable `TCP_NODELAY` can result in
49     /// a massively degraded debugging experience.
on_session_start(&mut self) -> Result<(), Self::Error>50     fn on_session_start(&mut self) -> Result<(), Self::Error> {
51         Ok(())
52     }
53 }
54 
55 /// Extends [`Connection`] with `read` and `peek` methods.
56 ///
57 /// This trait is used as part of `gdbstub`'s quickstart
58 /// [`GdbStub::run_blocking`](crate::stub::GdbStub::run_blocking) API.
59 ///
60 /// When the `std` feature is enabled, this trait is automatically implemented
61 /// for [`TcpStream`](std::net::TcpStream) and
62 /// [`UnixStream`](std::os::unix::net::UnixStream) (on unix systems).
63 ///
64 /// [`gdbstub_run::Callbacks::read_byte`]:
65 /// crate::gdbstub_run::Callbacks::read_byte
66 pub trait ConnectionExt: Connection {
67     /// Read a single byte.
read(&mut self) -> Result<u8, Self::Error>68     fn read(&mut self) -> Result<u8, Self::Error>;
69 
70     /// Peek a single byte. This MUST be a **non-blocking** operation, returning
71     /// `None` if no byte is available.
72     ///
73     /// Returns a byte (if one is available) without removing that byte from the
74     /// queue. Subsequent calls to `peek` MUST return the same byte.
peek(&mut self) -> Result<Option<u8>, Self::Error>75     fn peek(&mut self) -> Result<Option<u8>, Self::Error>;
76 }
77