1use core::future::poll_fn;
5use core::pin::Pin;
6use core::task::{Context, Poll, ready};
7use std::io;
8
9use futures_io::{AsyncBufRead, AsyncRead, AsyncWrite};
10
11const DEFAULT_BUF_SIZE: usize = 8 * 1024;
13
14#[derive(Debug)]
16struct CopyBuffer {
17 read_done: bool,
18 need_flush: bool,
19 pos: usize,
20 cap: usize,
21 amount: u64,
22 buf: Box<[u8]>,
23}
24
25impl CopyBuffer {
26 fn new(size: usize) -> Self {
27 Self {
28 read_done: false,
29 need_flush: false,
30 pos: 0,
31 cap: 0,
32 amount: 0,
33 buf: vec![0; size.max(1)].into_boxed_slice(),
34 }
35 }
36
37 fn poll_copy<R, W>(
41 &mut self,
42 cx: &mut Context<'_>,
43 mut reader: Pin<&mut R>,
44 mut writer: Pin<&mut W>,
45 ) -> Poll<io::Result<u64>>
46 where
47 R: AsyncRead + ?Sized,
48 W: AsyncWrite + ?Sized,
49 {
50 loop {
51 if self.pos == self.cap && !self.read_done {
52 match reader.as_mut().poll_read(cx, &mut self.buf) {
53 Poll::Ready(Ok(0)) => self.read_done = true,
54 Poll::Ready(Ok(n)) => {
55 self.pos = 0;
56 self.cap = n;
57 }
58 Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
59 Poll::Pending => {
60 if self.need_flush {
61 ready!(writer.as_mut().poll_flush(cx))?;
62 self.need_flush = false;
63 }
64 return Poll::Pending;
65 }
66 }
67 }
68 while self.pos < self.cap {
69 let n = ready!(
70 writer
71 .as_mut()
72 .poll_write(cx, &self.buf[self.pos..self.cap])
73 )?;
74 if n == 0 {
75 return Poll::Ready(Err(io::Error::new(
76 io::ErrorKind::WriteZero,
77 "the writer took no more bytes",
78 )));
79 }
80 self.pos += n;
81 self.amount += n as u64;
82 self.need_flush = true;
83 }
84 if self.pos == self.cap && self.read_done {
85 ready!(writer.as_mut().poll_flush(cx))?;
86 return Poll::Ready(Ok(self.amount));
87 }
88 }
89 }
90}
91
92pub async fn copy<R, W>(reader: &mut R, writer: &mut W) -> io::Result<u64>
105where
106 R: AsyncRead + Unpin + ?Sized,
107 W: AsyncWrite + Unpin + ?Sized,
108{
109 let mut buf = CopyBuffer::new(DEFAULT_BUF_SIZE);
110 poll_fn(|cx| buf.poll_copy(cx, Pin::new(&mut *reader), Pin::new(&mut *writer))).await
111}
112
113pub async fn copy_buf<R, W>(reader: &mut R, writer: &mut W) -> io::Result<u64>
116where
117 R: AsyncBufRead + Unpin + ?Sized,
118 W: AsyncWrite + Unpin + ?Sized,
119{
120 let mut amount = 0u64;
121 poll_fn(|cx| {
122 loop {
123 let mut reader = Pin::new(&mut *reader);
124 let writer = Pin::new(&mut *writer);
125 let available = ready!(reader.as_mut().poll_fill_buf(cx))?;
126 if available.is_empty() {
127 ready!(writer.poll_flush(cx))?;
128 return Poll::Ready(Ok(amount));
129 }
130 let n = ready!(writer.poll_write(cx, available))?;
131 if n == 0 {
132 return Poll::Ready(Err(io::Error::new(
133 io::ErrorKind::WriteZero,
134 "the writer took no more bytes",
135 )));
136 }
137 reader.consume(n);
138 amount += n as u64;
139 }
140 })
141 .await
142}
143
144#[derive(Debug)]
146enum Transfer {
147 Running(CopyBuffer),
148 ShuttingDown(u64),
149 Done(u64),
150}
151
152impl Transfer {
153 fn poll<R, W>(
156 &mut self,
157 cx: &mut Context<'_>,
158 reader: Pin<&mut R>,
159 mut writer: Pin<&mut W>,
160 ) -> Poll<io::Result<u64>>
161 where
162 R: AsyncRead + ?Sized,
163 W: AsyncWrite + ?Sized,
164 {
165 if let Self::Running(buf) = self {
166 let amount = ready!(buf.poll_copy(cx, reader, writer.as_mut()))?;
167 *self = Self::ShuttingDown(amount);
168 }
169 self.poll_after_copy(cx, writer)
170 }
171
172 fn poll_after_copy<W: AsyncWrite + ?Sized>(
173 &mut self,
174 cx: &mut Context<'_>,
175 writer: Pin<&mut W>,
176 ) -> Poll<io::Result<u64>> {
177 match *self {
178 Self::ShuttingDown(amount) => {
179 ready!(writer.poll_close(cx))?;
180 *self = Self::Done(amount);
181 Poll::Ready(Ok(amount))
182 }
183 Self::Done(amount) => Poll::Ready(Ok(amount)),
184 Self::Running(_) => Poll::Pending,
185 }
186 }
187}
188
189pub async fn copy_bidirectional<A, B>(a: &mut A, b: &mut B) -> io::Result<(u64, u64)>
194where
195 A: AsyncRead + AsyncWrite + Unpin + ?Sized,
196 B: AsyncRead + AsyncWrite + Unpin + ?Sized,
197{
198 copy_bidirectional_with_sizes(a, b, DEFAULT_BUF_SIZE, DEFAULT_BUF_SIZE).await
199}
200
201pub async fn copy_bidirectional_with_sizes<A, B>(
204 a: &mut A,
205 b: &mut B,
206 a_to_b: usize,
207 b_to_a: usize,
208) -> io::Result<(u64, u64)>
209where
210 A: AsyncRead + AsyncWrite + Unpin + ?Sized,
211 B: AsyncRead + AsyncWrite + Unpin + ?Sized,
212{
213 let mut forward = Transfer::Running(CopyBuffer::new(a_to_b));
214 let mut backward = Transfer::Running(CopyBuffer::new(b_to_a));
215 poll_fn(|cx| {
216 let ab = forward.poll(cx, Pin::new(&mut *a), Pin::new(&mut *b))?;
217 let ba = backward.poll(cx, Pin::new(&mut *b), Pin::new(&mut *a))?;
218 match (ab, ba) {
219 (Poll::Ready(ab), Poll::Ready(ba)) => Poll::Ready(Ok((ab, ba))),
220 _ => Poll::Pending,
221 }
222 })
223 .await
224}