#Why is moving value through std::mem::replace allowed in fn poll of Future trait ?

28 messages · Page 1 of 1 (latest)

smoky lava
#

Why I'm allowed to move the value through std::mem::replace, while moving through dereferencing is not allowed in Future dynamic objects, when the objective is to pin the values to memory.

use std::time::Duration;

struct TimerFuture {
    is_done: bool,
    duration: Duration,
}

impl TimerFuture {
    fn new(duration: Duration) -> Self {
        Self {
            is_done: false,
            duration,
        }
    }
}

impl Future for TimerFuture {
    type Output = ();
    fn poll(
        mut self: std::pin::Pin<&mut Self>,
        _: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Self::Output> {
        // Due to shared reference TimerFuture cannot be moved and it's valid
        // in the sense of pinning the value to memory, even a &mut Self would
        // do instead of Pin<&mut Self>.
        // let _c=*self;

        // But I can do below by calling replace function on Pin<&mut Self>
        // that moves current TimerFuture to _c, copying new TimerFuture.
        // Isn't this invalid when the objective isto pin the value.
        let _c = std::mem::replace(&mut *self, TimerFuture::new(Duration::from_millis(500)));
        std::task::Poll::Ready(())
    }
}

rapid abyss
#

Due to shared reference TimerFuture cannot be moved
it's not a shared reference

dense yoke
#

if you want that in generic code, you need an Unpin bound on the future type

#

by implementing Unpin a type opts-out of the pinning contract

rapid abyss
#

// let _c=*self;
that one doesn't work because you can't move a T out of a &mut T unless you also put another T back in (or if T: Copy)

dense yoke
smoky lava
rapid abyss
dense yoke
#

yes

#

let _c = *self; is equivalent to let _c = *Deref::deref(&self); I believe

#

not really important though, sorry for mentioning it

smoky lava
dense yoke
#

some types do care about pinning

#

for example, every async { … } block is !Unpin

rapid abyss
rapid abyss
dense yoke
#

?play

fn assert_unpin<T: Unpin>(_: T) {}

assert_unpin(async {});
livid dockBOT
#
error[E0277]: `{async block@src/main.rs:4:14: 4:19}` cannot be unpinned
 --> src/main.rs:4:14
  |
4 | assert_unpin(async {});
  | ------------ ^^^^^^^^ the trait `Unpin` is not implemented for `{async block@src/main.rs:4:14: 4:19}`
  | |
  | required by a bound introduced by this call
  |
  = note: consider using the `pin!` macro
          consider using `Box::pin` if you need to access the pinned value outside of the current scope
note: required by a bound in `assert_unpin`
 --> src/main.rs:2:20
  |
2 | fn assert_unpin<T: Unpin>(_: T) {}
  |                    ^^^^^ required by this bound in `assert_unpin`

For more information about this error, try `rustc --explain E0277`.```
smoky lava
rapid abyss
dense yoke
dense yoke
dense yoke
smoky lava
#

Thanks @dense yoke @rapid abyss for clearing my doubt