1use futures_io::{AsyncRead, AsyncWrite};
2use std::{
3 fmt, io,
4 pin::Pin,
5 sync::{Arc, Mutex},
6 task::{Context, Poll},
7};
8
9pub fn split<S: AsyncRead + AsyncWrite + Unpin>(stream: S) -> (ReadHalf<S>, WriteHalf<S>) {
21 let shared = Arc::new(Mutex::new(stream));
22 (
23 ReadHalf {
24 shared: shared.clone(),
25 },
26 WriteHalf { shared },
27 )
28}
29
30pub struct ReadHalf<S> {
32 shared: Arc<Mutex<S>>,
33}
34
35pub struct WriteHalf<S> {
37 shared: Arc<Mutex<S>>,
38}
39
40impl<S> fmt::Debug for ReadHalf<S> {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 f.debug_struct("ReadHalf").finish()
43 }
44}
45
46impl<S> fmt::Debug for WriteHalf<S> {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 f.debug_struct("WriteHalf").finish()
49 }
50}
51
52impl<S: AsyncRead + AsyncWrite + Unpin> ReadHalf<S> {
53 #[must_use]
55 pub fn unsplit(self, write: WriteHalf<S>) -> Option<S> {
56 if Arc::ptr_eq(&self.shared, &write.shared) {
57 drop(write);
58 Arc::try_unwrap(self.shared)
59 .ok()
60 .map(|m| m.into_inner().unwrap_or_else(|e| e.into_inner()))
61 } else {
62 None
63 }
64 }
65}
66
67fn lock<S>(shared: &Arc<Mutex<S>>) -> std::sync::MutexGuard<'_, S> {
68 shared.lock().unwrap_or_else(|e| e.into_inner())
69}
70
71impl<S: AsyncRead + Unpin> AsyncRead for ReadHalf<S> {
72 fn poll_read(
73 self: Pin<&mut Self>,
74 cx: &mut Context<'_>,
75 buf: &mut [u8],
76 ) -> Poll<io::Result<usize>> {
77 Pin::new(&mut *lock(&self.shared)).poll_read(cx, buf)
78 }
79
80 fn poll_read_vectored(
81 self: Pin<&mut Self>,
82 cx: &mut Context<'_>,
83 bufs: &mut [io::IoSliceMut<'_>],
84 ) -> Poll<io::Result<usize>> {
85 Pin::new(&mut *lock(&self.shared)).poll_read_vectored(cx, bufs)
86 }
87}
88
89impl<S: AsyncWrite + Unpin> AsyncWrite for WriteHalf<S> {
90 fn poll_write(
91 self: Pin<&mut Self>,
92 cx: &mut Context<'_>,
93 buf: &[u8],
94 ) -> Poll<io::Result<usize>> {
95 Pin::new(&mut *lock(&self.shared)).poll_write(cx, buf)
96 }
97
98 fn poll_write_vectored(
99 self: Pin<&mut Self>,
100 cx: &mut Context<'_>,
101 bufs: &[io::IoSlice<'_>],
102 ) -> Poll<io::Result<usize>> {
103 Pin::new(&mut *lock(&self.shared)).poll_write_vectored(cx, bufs)
104 }
105
106 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
107 Pin::new(&mut *lock(&self.shared)).poll_flush(cx)
108 }
109
110 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
111 Pin::new(&mut *lock(&self.shared)).poll_close(cx)
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118 use crate::util::simple_block_on;
119 use std::{
120 collections::VecDeque,
121 future::poll_fn,
122 pin::Pin,
123 task::{Context, Poll},
124 };
125
126 struct Duplex {
129 incoming: VecDeque<u8>,
130 outgoing: Vec<u8>,
131 }
132
133 impl AsyncRead for Duplex {
134 fn poll_read(
135 mut self: Pin<&mut Self>,
136 _cx: &mut Context<'_>,
137 buf: &mut [u8],
138 ) -> Poll<io::Result<usize>> {
139 let n = self.incoming.len().min(buf.len());
140 for slot in buf.iter_mut().take(n) {
141 *slot = self.incoming.pop_front().unwrap();
142 }
143 Poll::Ready(Ok(n))
144 }
145 }
146
147 impl AsyncWrite for Duplex {
148 fn poll_write(
149 mut self: Pin<&mut Self>,
150 _cx: &mut Context<'_>,
151 buf: &[u8],
152 ) -> Poll<io::Result<usize>> {
153 self.outgoing.extend_from_slice(buf);
154 Poll::Ready(Ok(buf.len()))
155 }
156 fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
157 Poll::Ready(Ok(()))
158 }
159 fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
160 Poll::Ready(Ok(()))
161 }
162 }
163
164 #[test]
165 fn split_read_and_write_independently() {
166 let duplex = Duplex {
167 incoming: b"hello".iter().copied().collect(),
168 outgoing: Vec::new(),
169 };
170 let (mut r, mut w) = split(duplex);
171 simple_block_on(async {
172 let n = poll_fn(|cx| Pin::new(&mut w).poll_write(cx, b"world"))
173 .await
174 .unwrap();
175 assert_eq!(n, 5);
176 let mut buf = [0u8; 5];
177 let n = poll_fn(|cx| Pin::new(&mut r).poll_read(cx, &mut buf))
178 .await
179 .unwrap();
180 assert_eq!(n, 5);
181 assert_eq!(&buf, b"hello");
182 });
183 let stream = r.unsplit(w).expect("same split");
184 assert_eq!(stream.outgoing, b"world");
185 }
186
187 #[test]
188 fn unsplit_rejects_foreign_half() {
189 let (r1, _w1) = split(Duplex {
190 incoming: VecDeque::new(),
191 outgoing: Vec::new(),
192 });
193 let (_r2, w2) = split(Duplex {
194 incoming: VecDeque::new(),
195 outgoing: Vec::new(),
196 });
197 assert!(r1.unsplit(w2).is_none());
198 }
199}