-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
io: add a copy_bidirectional utility #3230
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation looks correct. All my comments are about code style.
) -> Poll<io::Result<u64>> | ||
where A: AsyncRead + AsyncWrite + Unpin + ?Sized, B: AsyncRead + AsyncWrite + Unpin + ?Sized | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised rustfmt is accepting this. Maybe the cfg_*
macro is stopping it?
Please rustfmt the contents of this file.
loop { | ||
match state { | ||
TransferState::Running(buf) => { | ||
*state = TransferState::ShuttingDown(ready!(dbg!(buf.poll_copy(cx, r.as_mut(), w.as_mut())))?); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seems to be a stray dbg!
here. I'd also prefer to have the ready!
on a separate line to make it more clear that this doesn't unconditionally update the state.
|
||
*state = TransferState::Done(*count); | ||
} | ||
TransferState::Done(count) => break Poll::Ready(Ok(*count)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When using a loop in this way, I think this is clearer.
TransferState::Done(count) => break Poll::Ready(Ok(*count)), | |
TransferState::Done(count) => return Poll::Ready(Ok(*count)), |
} | ||
} | ||
|
||
impl<'a, A, B> std::future::Future for CopyBidirectional<'a, A, B> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I'd prefer to import Future
.
use tokio::{ | ||
io::{self}, | ||
task::JoinHandle, | ||
}; | ||
|
||
use std::time::Duration; | ||
use tokio::io::{AsyncReadExt, AsyncWriteExt}; | ||
use tokio::net::TcpStream; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use tokio::{ | |
io::{self}, | |
task::JoinHandle, | |
}; | |
use std::time::Duration; | |
use tokio::io::{AsyncReadExt, AsyncWriteExt}; | |
use tokio::net::TcpStream; | |
use std::time::Duration; | |
use tokio::io::{self, AsyncReadExt, AsyncWriteExt}; | |
use tokio::net::TcpStream; | |
use tokio::task::JoinHandle; |
let handle = tokio::spawn(async move { | ||
let (r1, r2) = tokio::io::copy_bidirectional(&mut b1, &mut a1).await?; | ||
Ok((r2, r1)) | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the other you just return directly, here you use the question mark. I don't mind either way, but it's nice to be consistent.
|
||
#[tokio::test] | ||
async fn test_basic_transfer() { | ||
symmetric(|_handle, mut a, mut b| async move { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I usually prefer to join the handles, as we otherwise don't catch panics in the task.
Closing in favor of #3572. |
Motivation
While there is a unidirectional copy utility currently, bidirectional copying between two streams (eg, proxying connections) is a bit tricky to do seamlessly and correctly due to the need to propagate EOFs and handle various error conditions.
Solution
This change adds a helper that can be used to, for example, glue together two
TcpStream
s and forward data across them.