serial_core/
serial_io.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Types to help in the implementation and use [`SerialIo`].
5
6use crate::SerialIo;
7use futures::io::AsyncRead;
8use futures::io::AsyncWrite;
9use inspect::InspectMut;
10use parking_lot::Mutex;
11use std::fmt::Debug;
12use std::io;
13use std::io::IoSliceMut;
14use std::pin::Pin;
15use std::sync::Arc;
16use std::task::Context;
17use std::task::Poll;
18
19/// An implementation of [`SerialIo`] for a connected serial port wrapping an
20/// implementation of [`AsyncRead`] and [`AsyncWrite`].
21pub struct Connected<T>(T);
22
23impl<T> InspectMut for Connected<T> {
24    fn inspect_mut(&mut self, req: inspect::Request<'_>) {
25        req.respond();
26    }
27}
28
29impl<T: AsyncRead + AsyncWrite + Send> Connected<T> {
30    /// Returns a new instance wrapping `t`.
31    pub fn new(t: T) -> Self {
32        Self(t)
33    }
34
35    /// Returns the wrapped value.
36    pub fn into_inner(self) -> T {
37        self.0
38    }
39}
40
41impl<T: AsyncRead + AsyncWrite + Send + Unpin> SerialIo for Connected<T> {
42    fn is_connected(&self) -> bool {
43        true
44    }
45
46    fn poll_connect(&mut self, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
47        Poll::Ready(Ok(()))
48    }
49
50    fn poll_disconnect(&mut self, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
51        Poll::Pending
52    }
53}
54
55impl<T: AsyncRead + Unpin> AsyncRead for Connected<T> {
56    fn poll_read(
57        self: Pin<&mut Self>,
58        cx: &mut Context<'_>,
59        buf: &mut [u8],
60    ) -> Poll<io::Result<usize>> {
61        let r = Pin::new(&mut self.get_mut().0).poll_read(cx, buf);
62        if matches!(r, Poll::Ready(Ok(0))) {
63            Poll::Pending
64        } else {
65            r
66        }
67    }
68
69    fn poll_read_vectored(
70        self: Pin<&mut Self>,
71        cx: &mut Context<'_>,
72        bufs: &mut [IoSliceMut<'_>],
73    ) -> Poll<io::Result<usize>> {
74        let r = Pin::new(&mut self.get_mut().0).poll_read_vectored(cx, bufs);
75        if matches!(r, Poll::Ready(Ok(0))) {
76            Poll::Pending
77        } else {
78            r
79        }
80    }
81}
82
83impl<T: AsyncWrite + Unpin> AsyncWrite for Connected<T> {
84    fn poll_write(
85        self: Pin<&mut Self>,
86        cx: &mut Context<'_>,
87        buf: &[u8],
88    ) -> Poll<io::Result<usize>> {
89        Pin::new(&mut self.get_mut().0).poll_write(cx, buf)
90    }
91
92    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
93        Pin::new(&mut self.get_mut().0).poll_flush(cx)
94    }
95
96    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
97        Pin::new(&mut self.get_mut().0).poll_close(cx)
98    }
99
100    fn poll_write_vectored(
101        self: Pin<&mut Self>,
102        cx: &mut Context<'_>,
103        bufs: &[io::IoSlice<'_>],
104    ) -> Poll<io::Result<usize>> {
105        Pin::new(&mut self.get_mut().0).poll_write_vectored(cx, bufs)
106    }
107}
108
109/// Returns a new implementation of [`SerialIo`] wrapping `t`, plus a handle to
110/// detach `t` and get it back.
111pub fn detachable<T: SerialIo + Unpin>(t: T) -> (DetachableIo<T>, IoDetacher<T>) {
112    let inner = Arc::new(Mutex::new(Some(t)));
113    (
114        DetachableIo {
115            inner: inner.clone(),
116        },
117        IoDetacher { inner },
118    )
119}
120
121/// An object implementing [`AsyncRead`] or [`AsyncWrite`] whose underlying
122/// object can be detached.
123///
124/// Once the object is detached (via [`IoDetacher::detach`]), reads will return
125/// `Ok(0)` (indicating EOF), and writes will fail with
126/// [`std::io::ErrorKind::BrokenPipe`].
127#[derive(Debug)]
128pub struct DetachableIo<T> {
129    inner: Arc<Mutex<Option<T>>>,
130}
131
132impl<T: InspectMut> InspectMut for DetachableIo<T> {
133    fn inspect_mut(&mut self, req: inspect::Request<'_>) {
134        self.inner.lock().inspect_mut(req)
135    }
136}
137
138impl<T> DetachableIo<T> {
139    /// Makes an object that's already in the detached state.
140    pub fn detached() -> Self {
141        Self {
142            inner: Arc::new(Mutex::new(None)),
143        }
144    }
145}
146
147/// A handle used to detach the object from a [`DetachableIo`].
148pub struct IoDetacher<T> {
149    inner: Arc<Mutex<Option<T>>>,
150}
151
152impl<T: SerialIo + Unpin> IoDetacher<T> {
153    /// Takes the underlying IO object from the associated [`DetachableIo`].
154    pub fn detach(self) -> T {
155        self.inner.lock().take().unwrap()
156    }
157}
158
159impl<T: SerialIo + Unpin> SerialIo for DetachableIo<T> {
160    fn is_connected(&self) -> bool {
161        self.inner.lock().as_ref().is_some_and(|s| s.is_connected())
162    }
163
164    fn poll_connect(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
165        let mut inner = self.inner.lock();
166        if let Some(serial) = &mut *inner {
167            serial.poll_connect(cx)
168        } else {
169            Poll::Pending
170        }
171    }
172
173    fn poll_disconnect(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
174        let mut inner = self.inner.lock();
175        if let Some(serial) = &mut *inner {
176            serial.poll_disconnect(cx)
177        } else {
178            Poll::Ready(Ok(()))
179        }
180    }
181}
182
183impl<T: AsyncRead + Unpin> AsyncRead for DetachableIo<T> {
184    fn poll_read(
185        self: Pin<&mut Self>,
186        cx: &mut Context<'_>,
187        buf: &mut [u8],
188    ) -> Poll<io::Result<usize>> {
189        let mut inner = self.inner.lock();
190        if let Some(inner) = &mut *inner {
191            Pin::new(inner).poll_read(cx, buf)
192        } else {
193            Poll::Ready(Ok(0))
194        }
195    }
196
197    fn poll_read_vectored(
198        self: Pin<&mut Self>,
199        cx: &mut Context<'_>,
200        bufs: &mut [IoSliceMut<'_>],
201    ) -> Poll<io::Result<usize>> {
202        let mut inner = self.inner.lock();
203        if let Some(inner) = &mut *inner {
204            Pin::new(inner).poll_read_vectored(cx, bufs)
205        } else {
206            Poll::Ready(Ok(0))
207        }
208    }
209}
210
211impl<T: AsyncWrite + Unpin> AsyncWrite for DetachableIo<T> {
212    fn poll_write(
213        self: Pin<&mut Self>,
214        cx: &mut Context<'_>,
215        buf: &[u8],
216    ) -> Poll<io::Result<usize>> {
217        let mut inner = self.inner.lock();
218        if let Some(inner) = &mut *inner {
219            Pin::new(inner).poll_write(cx, buf)
220        } else {
221            Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()))
222        }
223    }
224
225    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
226        let mut inner = self.inner.lock();
227        if let Some(inner) = &mut *inner {
228            Pin::new(inner).poll_flush(cx)
229        } else {
230            Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()))
231        }
232    }
233
234    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
235        let mut inner = self.inner.lock();
236        if let Some(inner) = &mut *inner {
237            Pin::new(inner).poll_close(cx)
238        } else {
239            Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()))
240        }
241    }
242
243    fn poll_write_vectored(
244        self: Pin<&mut Self>,
245        cx: &mut Context<'_>,
246        bufs: &[io::IoSlice<'_>],
247    ) -> Poll<io::Result<usize>> {
248        let mut inner = self.inner.lock();
249        if let Some(inner) = &mut *inner {
250            Pin::new(inner).poll_write_vectored(cx, bufs)
251        } else {
252            Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()))
253        }
254    }
255}