0

I had read the usage of futures::select, but I encounter an obstacle. here is my confusion: At the part of expression in select!, we should use a type implementing Unpin and FusedFuture, but here Pin on a Unpin is no effect accoring to usage of Pin.

1.why we should wrap Pin on a Unpin if call fuse() outside a select!, if it have no effect 2.why a Pin could be used in expression of select! and pass the checker if there needs a Unpin.

here is code:

async fn async_identity_fn(arg: usize) -> usize {
    arg
}
let fut_1 = async_identity_fn(1).fuse();
let fut_2 = async_identity_fn(2).fuse();
let mut fut_1 = Box::pin(fut_1); // Pins the Future on the heap
pin_mut!(fut_2); // Pins the Future on the stack
let res = select! {
    a_res = fut_1 => a_res,
    b_res = fut_2 => b_res,
};

here is some link

usage of Pin ;

confusion about usage of Pin

usage of select!

confusion about condition of using select!

sunboy_zgz
  • 11
  • 4
  • Why do you think `Pin` is not allowed on an `Unpin` type? What does "1. why Pin on a Unpin" mean? What do you mean by "2. why a Pin could be used in expression of select!"? I have troubles understanding your meaning. – Chayim Friedman Jun 21 '22 at 09:53
  • @ChayimFriedman 1. that's because of this summary which is at the bottom of [link](https://rust-lang.github.io/async-book/04_pinning/01_chapter.html) . 2. because at the doc of futures contains such a word "Futures directly passed to select! must be Unpin and implement FusedFuture.". if you have toubles to understand, you can look my links listed under my question. I don't know how to express more clearly. It's really appreciated for your patient answear. – sunboy_zgz Jun 21 '22 at 10:42
  • The link you gave does not say `Pin` with `Unpin` type is forbidden, just that it is useless. But I still don't understand your first question: "why `Pin` on `Unpin`" is not a question - why what? As for your second question, are you asking why `Pin` is allowed if `Unpin` is required? That's because `Pin` on `Unpin` is useless, doing nothing but not interfering. – Chayim Friedman Jun 21 '22 at 10:47
  • @ChayimFriedman thanks for your feedback and answear again. according your supposition, I consider what I really want to know and revise my question. – sunboy_zgz Jun 21 '22 at 11:43
  • "why we should wrap `Pin` on a `Unpin` if call `fuse()` outside a `select!`" I don't see you pin the future. – Chayim Friedman Jun 22 '22 at 01:30
  • @ChayimFriedman In the [doc](https://docs.rs/futures/0.3.21/futures/macro.select.html), there is such a word "If a similar async function is called outside of select to produce a Future, the Future must be pinned in order to be able to pass it to select. This can be achieved via Box::pin for pinning a Future on the heap or the pin_mut! macro for pinning a Future on the stack.". So, I don't know whether we must do the same as this, or it's just a best practice. And the above code is copied from this doc. – sunboy_zgz Jun 22 '22 at 03:50
  • @ChayimFriedman maybe we are talk about the different crate, It's different feature(`select!`) between futures and tokio. because when I talk with others, they also think of tokio at the first time. – sunboy_zgz Jun 22 '22 at 04:39

1 Answers1

0

why we should wrap Pin on a Unpin if call fuse() outside a select!, if it have no effect

Because it is not Unpin:

error[E0277]: `from_generator::GenFuture<[static generator@src/lib.rs:3:49: 5:2]>` cannot be unpinned
  --> src/lib.rs:12:15
   |
12 |       let res = select! {
   |  _______________^
13 | |         a_res = fut_1 => a_res,
14 | |         b_res = fut_2 => b_res,
15 | |     };
   | |_____^ within `futures::future::future::fuse::_::__Origin<'_, impl futures::Future<Output = usize>>`, the trait `Unpin` is not implemented for `from_generator::GenFuture<[static generator@src/lib.rs:3:49: 5:2]>`
   |
   = note: consider using `Box::pin`
   = note: required because it appears within the type `impl futures::Future<Output = usize>`
   = note: required because it appears within the type `impl futures::Future<Output = usize>`
   = note: required because it appears within the type `Option<impl futures::Future<Output = usize>>`
   = note: required because it appears within the type `futures::future::future::fuse::_::__Origin<'_, impl futures::Future<Output = usize>>`
   = note: required because of the requirements on the impl of `Unpin` for `futures::future::Fuse<impl futures::Future<Output = usize>>`
note: required by a bound in `futures_util::async_await::assert_unpin`
  --> /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.21/src/async_await/mod.rs:50:24
   |
50 | pub fn assert_unpin<T: Unpin>(_: &T) {}
   |                        ^^^^^ required by this bound in `futures_util::async_await::assert_unpin`
   = note: this error originates in the macro `$crate::select_internal` (in Nightly builds, run with -Z macro-backtrace for more info)

So it is not valid for select!. However, even for !Unpin value, if we pin it the pinned value does implement Unpin (not because of Pin itself but because Box and references are always Unpin).

why a Pin could be used in expression of select! and pass the checker if there needs a Unpin.

Because the macro can pin the result of the call itself. However, when using variables directly it cannot do that soundly.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77