Skip to main content

osdp/
transport.rs

1//! Transport abstraction. The driver works against any half-duplex byte
2//! stream that exposes [`Transport::write_all`] and [`Transport::read`].
3
4use crate::error::Error;
5
6/// Synchronous half-duplex byte transport.
7pub trait Transport {
8    /// Send `bytes` in their entirety. The implementation must not return
9    /// until either every byte is on the wire or an error has occurred.
10    fn write_all(&mut self, bytes: &[u8]) -> Result<(), Error>;
11
12    /// Read up to `buf.len()` bytes.
13    ///
14    /// Implementations should return `Ok(0)` when no bytes are available
15    /// before the deadline configured at the transport level. Drivers track
16    /// REPLY_DELAY independently via the [`crate::clock::Clock`].
17    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error>;
18
19    /// Flush any internally-buffered bytes.
20    fn flush(&mut self) -> Result<(), Error> {
21        Ok(())
22    }
23}
24
25impl<T: Transport + ?Sized> Transport for &mut T {
26    fn write_all(&mut self, bytes: &[u8]) -> Result<(), Error> {
27        (**self).write_all(bytes)
28    }
29    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
30        (**self).read(buf)
31    }
32    fn flush(&mut self) -> Result<(), Error> {
33        (**self).flush()
34    }
35}
36
37/// In-memory loopback transport used in tests and the chaos bus.
38#[cfg(feature = "alloc")]
39#[derive(Debug, Default)]
40pub struct VecTransport {
41    /// Bytes the caller has written and that are waiting to be drained by
42    /// the peer (or by [`Self::take_outgoing`]).
43    pub outgoing: alloc::collections::VecDeque<u8>,
44    /// Bytes the peer has fed in and that the caller is yet to read.
45    pub incoming: alloc::collections::VecDeque<u8>,
46}
47
48#[cfg(feature = "alloc")]
49impl VecTransport {
50    /// New empty transport.
51    pub fn new() -> Self {
52        Self::default()
53    }
54
55    /// Push `bytes` onto the read-side queue (simulates the peer).
56    pub fn feed(&mut self, bytes: &[u8]) {
57        self.incoming.extend(bytes.iter().copied());
58    }
59
60    /// Drain the write-side queue.
61    pub fn take_outgoing(&mut self) -> alloc::vec::Vec<u8> {
62        let v: alloc::vec::Vec<u8> = self.outgoing.drain(..).collect();
63        v
64    }
65
66    /// Move every byte from this transport's outgoing queue into `other`'s
67    /// incoming queue, modelling a one-way half-duplex bus segment. Useful in
68    /// loopback tests and examples that wire two `VecTransport`s back-to-back.
69    pub fn shuffle_to(&mut self, other: &mut VecTransport) {
70        other.incoming.extend(self.outgoing.drain(..));
71    }
72}
73
74#[cfg(feature = "alloc")]
75impl Transport for VecTransport {
76    fn write_all(&mut self, bytes: &[u8]) -> Result<(), Error> {
77        self.outgoing.extend(bytes.iter().copied());
78        Ok(())
79    }
80
81    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
82        let n = buf.len().min(self.incoming.len());
83        for slot in buf.iter_mut().take(n) {
84            *slot = self.incoming.pop_front().unwrap();
85        }
86        Ok(n)
87    }
88}
89
90/// Adapter wrapping any [`embedded_io::Read`] + [`embedded_io::Write`] into a
91/// [`Transport`].
92///
93/// The embedded-io crate is the de-facto traits crate for synchronous byte
94/// streams in `no_std` Rust (UARTs, sockets, in-memory pipes, …).
95#[cfg(feature = "embedded-io")]
96#[cfg_attr(docsrs, doc(cfg(feature = "embedded-io")))]
97pub struct EmbeddedIoTransport<T> {
98    /// The wrapped reader/writer.
99    pub inner: T,
100}
101
102#[cfg(feature = "embedded-io")]
103impl<T> EmbeddedIoTransport<T> {
104    /// Wrap `inner`.
105    pub fn new(inner: T) -> Self {
106        Self { inner }
107    }
108
109    /// Unwrap, returning the underlying reader/writer.
110    pub fn into_inner(self) -> T {
111        self.inner
112    }
113}
114
115#[cfg(feature = "embedded-io")]
116impl<T> Transport for EmbeddedIoTransport<T>
117where
118    T: embedded_io::Read + embedded_io::Write,
119{
120    fn write_all(&mut self, bytes: &[u8]) -> Result<(), Error> {
121        embedded_io::Write::write_all(&mut self.inner, bytes)
122            .map_err(|_| Error::Io("embedded-io write failed"))
123    }
124
125    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
126        embedded_io::Read::read(&mut self.inner, buf)
127            .map_err(|_| Error::Io("embedded-io read failed"))
128    }
129
130    fn flush(&mut self) -> Result<(), Error> {
131        embedded_io::Write::flush(&mut self.inner)
132            .map_err(|_| Error::Io("embedded-io flush failed"))
133    }
134}