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

util: implement ReusableBoxFuture with one function #4675

Merged
merged 5 commits into from May 13, 2022

Conversation

SabrinaJewson
Copy link
Contributor

Motivation

ReusableBoxFuture is currently complex-ish, with unsafe code and types in multiple places.

Solution

Move all the unsafety into a single function reuse_pin_box (and a helper type). I think this makes the definition of ReusableBoxFuture a bit simpler, and I'm pretty sure that it's sound. The function has the signature:

fn reuse_pin_box<T: ?Sized, U, O, F>(boxed: Pin<Box<T>>, new_value: U, callback: F) -> Result<O, U>
where
    F: FnOnce(Box<U>) -> O,

It encapsulates the basic premise of ReusableBoxFuture — a Box that can be reused — and ReusableBoxFuture is then implemented on top of it. It accepts a callback instead of returning Result<Box<U>, O> so that code can be run even if dropping the old T fails.

@github-actions github-actions bot added the R-loom Run loom tests on this PR label May 10, 2022
This is so we can get an unconditional `Send` bound on rustc <1.60.
@SabrinaJewson
Copy link
Contributor Author

By the way, I didn't catch that Clippy warning initially because Tokio doesn't even build for my with my local Clippy. If I try it just produces this error:

Click to show Clippy output
warning: this expression borrows a value the compiler would automatically borrow
  --> tokio/src/future/poll_fn.rs:38:9
   |
38 |         (&mut self.f)(cx)
   |         ^^^^^^^^^^^^^ help: change this to: `self.f`
   |
   = note: `#[warn(clippy::needless_borrow)]` on by default
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

warning: methods called `is_*` usually take `self` by reference or no `self`
  --> tokio/src/io/util/vec_with_initialized.rs:67:28
   |
67 |     pub(crate) fn is_empty(&mut self) -> bool {
   |                            ^^^^^^^^^
   |
   = note: `#[warn(clippy::wrong_self_convention)]` on by default
   = help: consider choosing a less ambiguous name
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention

warning: unnecessary use of `to_vec`
   --> tokio/src/net/addr.rs:148:20
    |
148 |         let iter = self.to_vec().into_iter();
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `self.iter().copied()`
    |
    = note: `#[warn(clippy::unnecessary_to_owned)]` on by default
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned

warning: `tokio` (lib) generated 3 warnings
    Checking tokio v1.18.2 (/home/sabrina/code/tokio/tokio)
    Checking tokio-stream v0.1.8 (/home/sabrina/code/tokio/tokio-stream)
error: written amount is not handled
  --> tokio/tests/tcp_split.rs:39:5
   |
39 |     write_half.write(MSG).await?;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[deny(clippy::unused_io_amount)]` on by default
   = help: use `AsyncWriteExt::write_all` instead, or handle partial writes
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount

Not sure what's going on here but it would be nice if that could be fixed

@Darksonn
Copy link
Contributor

Tokio uses an older clippy version because some of the new lints are incompatible with our minimum supported Rust version. You can find the version we use in the CI configuration.

Copy link
Member

@hawkw hawkw left a comment

Choose a reason for hiding this comment

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

Overall, this approach looks good to me --- having the ReusableBoxFuture own a Pin<Box<...>> definitely feels much nicer than the NonNull, as we need less unsafe code outside of the code that actually reuses the allocation.

I commented on a few relatively minor things.

tokio-util/src/sync/reusable_box.rs Show resolved Hide resolved
{
// future::Pending<T> is a ZST so this never allocates.
let boxed = mem::replace(&mut this.boxed, Box::pin(Pending(PhantomData)));
reuse_pin_box(boxed, future, |boxed| this.boxed = Pin::from(boxed))
Copy link
Member

Choose a reason for hiding this comment

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

this appears to be the only place where reuse_pin_box is ever called...do you think it would make sense to just put that code in this function? that way we avoid having an additional function that gets monomorphized over a big pile of generic types, which might help with binary size a bit...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Conceptually I quite like the idea of reuse_pin_box as an independent futures-unaware utility function — it makes a lot of sense to me as a layer of abstraction. Would putting #[inline(always)] on the function have the same effect?

Copy link
Contributor

Choose a reason for hiding this comment

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

My guess is that it'll be inlined either way.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I think it'll get inlined either way.

I'm not strongly opposed to keeping the separate function; I just wanted to note that it isn't currently used elsewhere. 🤷‍♀️

tokio-util/src/sync/reusable_box.rs Show resolved Hide resolved
tokio-util/src/sync/reusable_box.rs Outdated Show resolved Hide resolved
hawkw pushed a commit that referenced this pull request May 10, 2022
## Motivation

In #4675 I learnt the hard way that Tokio uses Clippy on its MSRV. 

## Solution

Document this in the contributor's guide.
@Darksonn Darksonn added A-tokio-util Area: The tokio-util crate M-sync Module: tokio/sync labels May 12, 2022
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.

Thanks.

@Darksonn Darksonn merged commit f7346f0 into tokio-rs:master May 13, 2022
@SabrinaJewson SabrinaJewson deleted the reusable-box-future-fn branch May 14, 2022 05:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio-util Area: The tokio-util crate M-sync Module: tokio/sync R-loom Run loom tests on this PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants