tokio/io/util/
copy_bidirectional.rs1use super::copy::CopyBuffer;
2
3use crate::io::{AsyncRead, AsyncWrite};
4
5use std::future::poll_fn;
6use std::io;
7use std::pin::Pin;
8use std::task::{ready, Context, Poll};
9
10enum TransferState {
11 Running(CopyBuffer),
12 ShuttingDown(u64),
13 Done(u64),
14}
15
16fn transfer_one_direction<A, B>(
17 cx: &mut Context<'_>,
18 state: &mut TransferState,
19 r: &mut A,
20 w: &mut B,
21) -> Poll<io::Result<u64>>
22where
23 A: AsyncRead + AsyncWrite + Unpin + ?Sized,
24 B: AsyncRead + AsyncWrite + Unpin + ?Sized,
25{
26 let mut r = Pin::new(r);
27 let mut w = Pin::new(w);
28
29 loop {
30 match state {
31 TransferState::Running(buf) => {
32 let count = ready!(buf.poll_copy(cx, r.as_mut(), w.as_mut()))?;
33 *state = TransferState::ShuttingDown(count);
34 }
35 TransferState::ShuttingDown(count) => {
36 ready!(w.as_mut().poll_shutdown(cx))?;
37
38 *state = TransferState::Done(*count);
39 }
40 TransferState::Done(count) => return Poll::Ready(Ok(*count)),
41 }
42 }
43}
44#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
76pub async fn copy_bidirectional<A, B>(a: &mut A, b: &mut B) -> io::Result<(u64, u64)>
77where
78 A: AsyncRead + AsyncWrite + Unpin + ?Sized,
79 B: AsyncRead + AsyncWrite + Unpin + ?Sized,
80{
81 copy_bidirectional_impl(
82 a,
83 b,
84 CopyBuffer::new(super::DEFAULT_BUF_SIZE),
85 CopyBuffer::new(super::DEFAULT_BUF_SIZE),
86 )
87 .await
88}
89
90#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
99pub async fn copy_bidirectional_with_sizes<A, B>(
100 a: &mut A,
101 b: &mut B,
102 a_to_b_buf_size: usize,
103 b_to_a_buf_size: usize,
104) -> io::Result<(u64, u64)>
105where
106 A: AsyncRead + AsyncWrite + Unpin + ?Sized,
107 B: AsyncRead + AsyncWrite + Unpin + ?Sized,
108{
109 assert!(
110 a_to_b_buf_size > 0,
111 "`a_to_b_buf_size` must be greater than 0"
112 );
113 assert!(
114 b_to_a_buf_size > 0,
115 "`b_to_a_buf_size` must be greater than 0"
116 );
117
118 copy_bidirectional_impl(
119 a,
120 b,
121 CopyBuffer::new(a_to_b_buf_size),
122 CopyBuffer::new(b_to_a_buf_size),
123 )
124 .await
125}
126
127async fn copy_bidirectional_impl<A, B>(
128 a: &mut A,
129 b: &mut B,
130 a_to_b_buffer: CopyBuffer,
131 b_to_a_buffer: CopyBuffer,
132) -> io::Result<(u64, u64)>
133where
134 A: AsyncRead + AsyncWrite + Unpin + ?Sized,
135 B: AsyncRead + AsyncWrite + Unpin + ?Sized,
136{
137 let mut a_to_b = TransferState::Running(a_to_b_buffer);
138 let mut b_to_a = TransferState::Running(b_to_a_buffer);
139 poll_fn(|cx| {
140 let a_to_b = transfer_one_direction(cx, &mut a_to_b, a, b)?;
141 let b_to_a = transfer_one_direction(cx, &mut b_to_a, b, a)?;
142
143 let a_to_b = ready!(a_to_b);
146 let b_to_a = ready!(b_to_a);
147
148 Poll::Ready(Ok((a_to_b, b_to_a)))
149 })
150 .await
151}