Spawn loop and select! on closure

⚓ Rust    📅 2025-08-08    👤 surdeus    👁️ 6      

surdeus

The block method works fine. I want to do exactly the same thing as the block method but by passing in a closure instead.

It seems that theoretically, this should be doable. The block method moves obj into the async move block and owns it and so is able to call it on each loop.

But I've tried many things on the closure approach and can't get it to work. with_closure has an identical signature. I want to be able to make run_closure a general method/function somewhere and so that's why I'm trying to make this work. It's a little different than this, but this is a simplified version to ask this question.

The overall goal is to be able to take any number and types of params that goes into some code and comes out a future that will return X (bool in this case) and so that's why a closure makes sense.

I might have found one solution that involves cloning everything in between the move and async move, but... the block function does not require obj to be Clone, so theoretically it shouldn't have to be, and it wouldn't work well for my case to require it.

(ignore the Arc<Self>'s, not pertinent to this question)

playground

use std::sync::Arc;

pub trait Rec<T>: Send + Sync + 'static {
    fn drum(&mut self) -> impl Future<Output = bool> + Send + Sync;
}

struct Test();

impl Test {
    pub fn block<T: Rec<T>>(arc_self: Arc<Self>, mut obj: T) {
        tokio::spawn(async move {
            loop {
                tokio::select! {
                    result = obj.drum() => {
                        if !result {
                            break;
                        }
                    }
                    // ...
                }
            }
        });
    }

    pub async fn with_closure<T: Rec<T>>(arc_self: Arc<Self>, mut obj: T) {
        Self::run_closure(arc_self, move || async move { obj.drum().await }).await;
    }

    pub async fn run_closure<F, Fut>(arc_self: Arc<Self>, mut task: F)
    where
        F: FnMut() -> Fut + Send + 'static,
        Fut: Future<Output = bool> + Send {
        tokio::spawn(async move {
            loop {
                tokio::select! {
                    result = task() => {
                        if !result {
                            break;
                        }
                    }
                    // ...
                }
            }
        });
    }
}

5 posts - 3 participants

Read full topic

🏷️ Rust_feed