Recursive async trait method

Hello,
I'm fighting the type system to get the following done, restricting further and further as per the compiler recommendations, but I'm now stuck because entries isn't Send.

pub trait Entry : Send {
    // ...
}

pub trait Storage: Send where Self: 'static {
    type E: Entry;

    fn entries(
        &self,
        dir_id: Option<&str>,
    ) -> impl std::future::Future<Output = Result<impl Iterator<Item = Result<Self::E>>>> + Send;

    fn discover<'a>(
        self: Arc<Self>,
        dir_id: Option<&'a str>,
        tx: Sender<Result<Self::E>>,
    ) -> BoxFuture<'a, Result<()>> 
    where 
        Self: 'a,
        <Self as Storage>::E: 'static,
        Self: Sync,
    {
        Box::pin(async move {
            let this = self.clone();
            let entries = this.entries(dir_id).await?;

            for entry in entries {
                let dir_id = {
                    let mut dir_id: Option<String> = None;
                    if let Ok(entry) = &entry {
                        if entry.is_dir() {
                            dir_id = Some(entry.id().to_owned());
                        }
                    }
                    dir_id
                };

                tx.send(entry).await.unwrap();

                if let Some(dir_id) = dir_id {
                    let tx = tx.clone();
                    let this2 = this.clone();
                    tokio::spawn(async move { 
                        this2.discover(Some(&dir_id), tx).await;
                    });
                }
            }
            Ok(())
        })
    }
}

Is there a way to achieve this? If possible with less restrictions...

It's hard to troubleshoot these sort of things without either the full error message from the compiler, with all the context it gives (i.e. run cargo check and copy and paste the output), or a complete example we can compile ourselves (preferably in the Rust Playground).

But it looks to me like you're missing a Send bound on your impl Iterator<Item = Result<Self::E>> — that is, change it to impl Iterator<Item = Result<Self::E>> + Send. The iterator has to be Send since you are awaiting inside of the loop over that iterator.

1 Like

Thanks for the answer. Your assumption is correct!
Here is a link to the playground for reference.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.