Skip to main content

spawn

Function spawn 

pub fn spawn(future: impl Future<Output = ()> + 'static) -> TaskHandle
Expand description

Create a new async background task.

This function allows creating a new async task in which Godot signals can be awaited, like it is possible in GDScript. If a reference to Self is not flexible enough regarding lifetimes, your function calling spawn() can capture the state in a Gd<Self> pointer instead. The TaskHandle that is returned provides synchronous introspection into the current state of the task.

Signals can be converted to futures in the following ways:

Signal typeSimple futureFallible future (handles freed object)
UntypedSignal::to_future()Signal::to_fallible_future()
TypedTypedSignal::to_future()TypedSignal::to_fallible_future()

§Panics

If called from any other thread than the main thread.

§Examples

An example using timers:

#[derive(GodotClass)]
#[class(init, base=Node)]
struct Game {
    base: Base<Node>,
}

#[godot_api]
impl Game {
    // Async sleep using Godot timers. Takes `Gd<Self>` by value, so no `&self`/`&mut self`
    // reference is held while the task is suspended at the await point.
    async fn sleep(this: Gd<Self>, duration: f64) {
        // To access object, use short-lived bind/bind_mut -> guard dropped after statement.
        this.bind().do_something();

        // Godot APIs don't need to go through bind/bind_mut at all.
        let timer = this.get_tree().create_timer(duration);

        // Await without holding any borrow on `this`. Keeping a bind()/bind_mut() guard
        // across an await point is problematic: while suspended, other access to the
        // object, for example through process(&mut self), will panic.
        timer.signals().timeout().to_future().await;
    }

    fn show_messages(&mut self) {
        // Obtain Gd<Self>, since the closure cannot capture `&mut self` due to lifetimes.
        // If this method is linked to a signal, consider using a #[func(gd_self)] parameter.
        let this = self.to_gd();

        // spawn() polls the future up to the first .await point, during which `&mut self` is
        // still held. base_mut() yields a guard that allows re-borrowing `self`, so the bind()
        // inside sleep() doesn't panic with "already bound".
        let _guard = self.base_mut();

        godot::task::spawn(async move {
            godot_print!("Start!");
            Self::sleep(this, 1.0).await;
            godot_print!("One second later!");
        });
    }
}

With typed signals:

#[derive(GodotClass)]
#[class(init)]
struct Building {
   base: Base<RefCounted>,
}

#[godot_api]
impl Building {
   #[signal]
   fn constructed(seconds: u32);
}

let house = Building::new_gd();
godot::task::spawn(async move {
    println!("Wait for construction...");

    // Emitted arguments can be fetched in tuple form.
    // If the signal has no parameters, you can skip `let` and just await the future.
    let (seconds,) = house.signals().constructed().to_future().await;

    println!("Construction complete after {seconds}s.");
});

With untyped signals:

let node = Node::new_alloc();
let signal = Signal::from_object_signal(&node, "signal");

godot::task::spawn(async move {
    println!("Starting task...");

    // Explicit generic arguments needed, here `()`:
    signal.to_future::<()>().await;

    println!("Node has changed: {}", node.get_name());
});