0

Following code does not compile because the element pulled from the vector does not implement the Pin<> type.

The error is in ele.poll() call

#[pin_project]
pub struct FifoCompletions<T, F>
where
    F: Future<Output = Result<T, Error>>
{
    #[pin]
    pending: VecDeque<F>,
}

impl <T, F> FifoCompletions<T, F>
where
    F: Future<Output = Result<T, Error>>
{
    pub fn push(&mut self, f: F) {
        self.pending.push_back(f);
    }
}

impl <T, F> Future for FifoCompletions<T, F>
where
    F: Future<Output = Result<T, Error>>
{
    type Output = Result<T, Error>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let this = self.project();
        while !this.pending.is_empty() {
            match this.pending.front_mut() {
                None => unreachable!(),
                Some(ele) => {
                    let output = ready!(ele.poll(cx));
                }
            }

        }
        Poll::Pending
    }
}

Error message is

no method named `poll` found for mutable reference `&mut F` in the current scope

method not found in `&mut F`

help: items from traits can only be used if the type parameter is bounded by the traitrustc(E0599)
sm.rs(66, 45): method not found in `&mut F`
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
user855
  • 19,048
  • 38
  • 98
  • 162
  • It's hard to answer your question because it doesn't include a [MRE]. We can't tell what crates (and their versions), types, traits, fields, etc. are present in the code. It would make it easier for us to help you if you try to reproduce your error on the [Rust Playground](https://play.rust-lang.org) if possible, otherwise in a brand new Cargo project, then [edit] your question to include the additional info. There are [Rust-specific MRE tips](//stackoverflow.com/tags/rust/info) you can use to reduce your original code for posting here. Thanks! – Shepmaster Nov 12 '20 at 01:29
  • Notably, there are no imports shown. – Shepmaster Nov 12 '20 at 01:29
  • Please [edit] your question and paste the exact and entire error that you're getting — that will help us to understand what the problem is so we can help best. Sometimes trying to interpret an error message is tricky and it's actually a different part of the error message that's important. Please use the message from running the compiler directly, not the message produced by an IDE, which might be trying to interpret the error for you. – Shepmaster Nov 12 '20 at 02:23
  • 1
    Didn't I paste the error message above? What else do you need? Also do you really expect this to be changing by compiler version for this particular issue? Are these some robotic responses without reading the question? – user855 Nov 12 '20 at 03:22
  • 1
    I think you need to do the projection inside the `Vec` using unsafe code. The `pin_project` macro does not project inside the `Vec` because it does not know how you intend to use the vector: if you were to push into the pinned `Vec`, the objects could move and the pin invariant would be broken. – rodrigo Nov 12 '20 at 10:54
  • *Didn't I paste the error message above?* sort of, but not from running the compiler in the terminal as I said, which means that your error text is half missing. *What else do you need?* I want you to provide code that produces the error you are asking about without making us guess. – Shepmaster Nov 12 '20 at 16:10
  • *do you really expect this to be changing by compiler version* no, but I didn’t ask for the compiler version, I asked for your dependency versions. *Are these some robotic responses without reading the question* yes, they are canned to some amount because people have a hard time following SOs rules about providing working examples. They also have a hard time reading comments that are aimed at guiding them to produce higher quality questions in a futile attempt to get an answer. It’s easier to reuse the same comment; but it’s even easier to vote to close the question. – Shepmaster Nov 12 '20 at 16:14

1 Answers1

0

Here's the literal answer to your question:

use std::{
    future::Future,
    pin::Pin,
    task::{Context, Poll},
};

pub struct Completions<F>
where
    F: Future<Output = ()>,
{
    pending: Vec<F>,
}

impl<F> Future for Completions<F>
where
    F: Future<Output = ()>,
{
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        // I copied this from Stack Overflow without reading the prose
        // that describes why this is or is not safe.
        // ... It's probably not safe.
        let first = unsafe { self.map_unchecked_mut(|this| &mut this.pending[0]) };
        first.poll(cx)
    }
}

However, this is very likely to be unsafe and introduce undefined behavior. The problem is that the requirements for pinning are complex and nuanced. Specifically, once pinned, a value may never be moved in memory, including when it is dropped. From the docs, emphasis mine:

This can be tricky, as witnessed by VecDeque<T>: the destructor of VecDeque<T> can fail to call drop on all elements if one of the destructors panics. This violates the Drop guarantee, because it can lead to elements being deallocated without their destructor being called. (VecDeque<T> has no pinning projections, so this does not cause unsoundness.)

I checked with taiki-e, the author of the pin-project crate. A lightly-edited quote:

Operations such as Vec(Deque)'s push, insert, remove, etc. can move elements. If you want to pin elements, these methods should not be called without Unpin after they have been pinned. The pin API actually blocks this.

If the destructor moves elements, it is unsound to pin the element returned by accessors like get_mut, front_mut without Unpin.

Make the element Unpin or use a collection that can handle !Unpin futures like FutureUnordered instead of VecDeque.

Applied directly, the safest way to do this is:

use pin_project::pin_project; // 1.0
use std::{
    future::Future,
    pin::Pin,
    task::{Context, Poll},
};

#[pin_project]
pub struct Completions<F>
where
    F: Unpin,
    F: Future<Output = ()>,
{
    #[pin]
    pending: Vec<F>,
}

impl<F> Future for Completions<F>
where
    F: Unpin,
    F: Future<Output = ()>,
{
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let this = self.project();
        let pending = this.pending.get_mut();
        let first = Pin::new(&mut pending[0]);
        first.poll(cx)
    }
}

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366