Skip to content
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

net: add a into_std method for tokio's TcpStream #3189

Merged
merged 9 commits into from Dec 6, 2020

Conversation

liufuyang
Copy link
Contributor

Motivation

Closes #3031

Solution

  1. Add an into_inner method on PollEvented. Make sure to deregister the stream from Tokio.
  2. Convert the mio tcp stream into an std one. Go through mio's IntoRawFd to do so.

@liufuyang liufuyang force-pushed the issue-3031 branch 3 times, most recently from 2c5c087 to 86382a4 Compare November 28, 2020 11:44
@Darksonn Darksonn added A-tokio Area: The main tokio crate C-enhancement Category: A PR with an enhancement or bugfix. M-net Module: tokio/net labels Nov 28, 2020
@liufuyang liufuyang force-pushed the issue-3031 branch 2 times, most recently from 6b2147e to cf99d4e Compare November 28, 2020 12:48
@liufuyang liufuyang changed the title Add a into_std method for tokio's TcpStream io: add a into_std method for tokio's TcpStream Nov 28, 2020
Fixes: tokio-rs#3031

Signed-off-by: Fuyang Liu <liufuyang@users.noreply.github.com>
Copy link
Contributor

@Darksonn Darksonn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems ok to me.

@Thomasdezeeuw is there a better way to convert the mio TcpStream than going through RawFd or RawSocket? I don't see one myself.

@Thomasdezeeuw
Copy link
Contributor

@Darksonn not right now, but there is tokio-rs/mio#1401.

let mut inner = self
.io
.take()
.ok_or_else(|| io::Error::from(io::ErrorKind::NotFound))?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that other parts of the code just unwrap this. Is it the case that it is an Option only for the purpose of being possible to take it out in or before the destructor? @carllerche

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, a panic here is fine as it would be an internal bug.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe @Darksonn is correct — this shouldn't ever be None unless the PollEvented is being dropped or into_std has been called, so this can just be an unwrap()...

Signed-off-by: Fuyang Liu <liufuyang@users.noreply.github.com>
Signed-off-by: Fuyang Liu <liufuyang@users.noreply.github.com>
@liufuyang
Copy link
Contributor Author

Hey @Darksonn, thanks for the comments above. I also added a doc test so to make a std TcpStream and let a client read it. Do you think the test code is solid enough? Or should I add a normal unit test for into_std as well? (If so, which file should I start adding this test?) Thank you :)

Copy link
Contributor

@Darksonn Darksonn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some stylistic comments on the doc-test.

/// # let mut stream: TcpStream = TcpStream::connect("127.0.0.1:8080").await.unwrap();
/// # let _ = stream.write(b"Hello world!").await;
/// # });
/// let mut data = [0 as u8; 50];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// let mut data = [0 as u8; 50];
/// let mut data = [0u8; 50];

/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn Error>> {
/// # tokio::spawn(async {
/// # tokio::time::sleep(Duration::from_millis(50)).await;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can avoid this sleep if you spawn it after calling bind. Also, can you await the returned JoinHandle at the end of the test to make sure the test fails if the task panics?

/// let (tokio_tcp_stream, _) = listener.accept().await?;
///
/// let mut std_tcp_stream = tokio_tcp_stream.into_std()?;
/// # tokio::time::sleep(Duration::from_millis(100)).await;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sleep should be unnecessary.

/// # tokio::spawn(async {
/// # tokio::time::sleep(Duration::from_millis(50)).await;
/// # let mut stream: TcpStream = TcpStream::connect("127.0.0.1:8080").await.unwrap();
/// # let _ = stream.write(b"Hello world!").await;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// # let _ = stream.write(b"Hello world!").await;
/// # stream.write(b"Hello world!").await.unwrap();

Copy link
Contributor Author

@liufuyang liufuyang Dec 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems I need this otherwise I see this during test?

running 1 test
test src/net/tcp/stream.rs - net::tcp::stream::TcpStream::into_std (line 191) ... FAILED

failures:

---- src/net/tcp/stream.rs - net::tcp::stream::TcpStream::into_std (line 191) stdout ----
error: unused `std::result::Result` that must be used
  --> src/net/tcp/stream.rs:204:7
   |
15 |       stream.write(b"Hello world!").await;
   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: the lint level is defined here
  --> src/net/tcp/stream.rs:190:9
   |
1  | #![deny(warnings, rust_2018_idioms)]
   |         ^^^^^^^^
   = note: `#[deny(unused_must_use)]` implied by `#[deny(warnings)]`
   = note: this `Result` may be an `Err` variant, which should be handled

error: aborting due to previous error

Couldn't compile the test.

failures:
    src/net/tcp/stream.rs - net::tcp::stream::TcpStream::into_std (line 191)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need the unwrap() too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha, thanks 😄

/// let mut std_tcp_stream = tokio_tcp_stream.into_std()?;
/// # tokio::time::sleep(Duration::from_millis(100)).await;
/// let size = std_tcp_stream.read(&mut data)?;
/// # assert_eq!("Hello world!", std::str::from_utf8(&data[0..size])?);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// # assert_eq!("Hello world!", std::str::from_utf8(&data[0..size])?);
/// # assert_eq!(b"Hello world!", &data[0..size]);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha, nice :)

/// # tokio::time::sleep(Duration::from_millis(100)).await;
/// let size = std_tcp_stream.read(&mut data)?;
/// # assert_eq!("Hello world!", std::str::from_utf8(&data[0..size])?);
/// # Ok(())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this, it wont compile if the user pastes it into the playground.

Suggested change
/// # Ok(())
/// Ok(())

@Darksonn
Copy link
Contributor

Darksonn commented Dec 5, 2020

I think it would be worth adding a test that the TcpStream still works if you convert it back and forth as in tokio → std → tokio. You can put the test in tokio/tests/tcp_into_std.rs.

Besides that, I think the doc-test captures what I'm looking for.

Signed-off-by: Fuyang Liu <liufuyang@users.noreply.github.com>
Signed-off-by: Fuyang Liu <liufuyang@users.noreply.github.com>
Signed-off-by: Fuyang Liu <liufuyang@users.noreply.github.com>
Copy link
Contributor

@Darksonn Darksonn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks good, besides a missing space.

/// std_tcp_stream.set_nonblocking(false)?;
/// std_tcp_stream.read_exact(&mut data)?;
/// # assert_eq!(b"Hello world!", &data);
/// Ok(())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Ok(())
/// Ok(())

Signed-off-by: Fuyang Liu <liufuyang@users.noreply.github.com>
@Darksonn Darksonn merged commit 0707f4c into tokio-rs:master Dec 6, 2020
@Darksonn Darksonn changed the title io: add a into_std method for tokio's TcpStream net: add a into_std method for tokio's TcpStream Dec 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio Area: The main tokio crate C-enhancement Category: A PR with an enhancement or bugfix. M-net Module: tokio/net
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add a to_std method for tokio's TcpStream
5 participants