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
67#[cfg(feature = "alloc")]
68impl Transport for VecTransport {
69    fn write_all(&mut self, bytes: &[u8]) -> Result<(), Error> {
70        self.outgoing.extend(bytes.iter().copied());
71        Ok(())
72    }
73
74    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
75        let n = buf.len().min(self.incoming.len());
76        for slot in buf.iter_mut().take(n) {
77            *slot = self.incoming.pop_front().unwrap();
78        }
79        Ok(n)
80    }
81}
82
83/// Adapter wrapping any [`embedded_io::Read`] + [`embedded_io::Write`] into a
84/// [`Transport`].
85///
86/// The embedded-io crate is the de-facto traits crate for synchronous byte
87/// streams in `no_std` Rust (UARTs, sockets, in-memory pipes, …).
88#[cfg(feature = "embedded-io")]
89#[cfg_attr(docsrs, doc(cfg(feature = "embedded-io")))]
90pub struct EmbeddedIoTransport<T> {
91    /// The wrapped reader/writer.
92    pub inner: T,
93}
94
95#[cfg(feature = "embedded-io")]
96impl<T> EmbeddedIoTransport<T> {
97    /// Wrap `inner`.
98    pub fn new(inner: T) -> Self {
99        Self { inner }
100    }
101
102    /// Unwrap, returning the underlying reader/writer.
103    pub fn into_inner(self) -> T {
104        self.inner
105    }
106}
107
108#[cfg(feature = "embedded-io")]
109impl<T> Transport for EmbeddedIoTransport<T>
110where
111    T: embedded_io::Read + embedded_io::Write,
112{
113    fn write_all(&mut self, bytes: &[u8]) -> Result<(), Error> {
114        embedded_io::Write::write_all(&mut self.inner, bytes)
115            .map_err(|_| Error::Io("embedded-io write failed"))
116    }
117
118    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
119        embedded_io::Read::read(&mut self.inner, buf)
120            .map_err(|_| Error::Io("embedded-io read failed"))
121    }
122
123    fn flush(&mut self) -> Result<(), Error> {
124        embedded_io::Write::flush(&mut self.inner)
125            .map_err(|_| Error::Io("embedded-io flush failed"))
126    }
127}