Skip to content

Function parameter lifetime in StreamExt::filter generic isn't good enoughΒ #2464

@ShadowJonathan

Description

@ShadowJonathan

I have this following call on a stream, to filter out elements asynchronously (sorry for the ugly encapsulation, async closures aren't a thing yet);

.filter(move |user_id| Box::pin(async move {!db.users.is_deactivated(user_id).await.unwrap_or(false)}))

The important part here is that .is_deactivated takes a borrowed UserId type, which is taken across await boundaries with the subsequent .await

However, rust complains about this...

error: lifetime may not live long enough
   --> src/database/rooms.rs:802:36
    |
802 |             .filter(move |user_id| Box::pin(async move {!db.users.is_deactivated(user_id).await.unwrap_or(false)}))
    |                           -------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
    |                           |      |
    |                           |      return type of closure `Pin<Box<impl futures::Future>>` contains a lifetime `'2`
    |                           has type `&'1 ruma::UserId`

...because the filter function signature doesn't explicitly specify the borrow lifetime as OK to be used for a little while longer;

    fn filter<Fut, F>(self, f: F) -> Filter<Self, Fut, F>
    where
        F: FnMut(&Self::Item) -> Fut,
        Fut: Future<Output = bool>,
        Self: Sized,
    {
        assert_stream::<Self::Item, _>(Filter::new(self, f))
    }

I think that altering it to this fixes it, but i'm not sure how that counts with API cleanliness and lifetime soundness;

    fn filter<'a, Fut, F>(self, f: F) -> Filter<Self, Fut, F>
    where
        F: FnMut(&'a Self::Item) -> Fut,
        Fut: Future<Output = bool> + 'a,
        Self::Item: 'a,
        Self: Sized,
    {
        assert_stream::<Self::Item, _>(Filter::new(self, f))
    }

Quickly inserting this seems to pop up a lot of other issues, so i'm only going to report this issue for now here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions