Quick start
I see you’re curious of how coroutines looks like in Rust - let’s feed you some minimal example!
Installation
Add Moirai to the project:
cargo add moirai
Minimal code
First we create jobs runtime to spawn coroutines into:
use moirai::{coroutine::yield_now, job::JobLocation, jobs::Jobs};
use moirai_book_samples::{
game::{Game, GameState, GameStateChange},
utils::quit_if_jobs_completed,
};
use std::time::Duration;
fn main() {
let jobs = Jobs::default();
Game::new(Example { jobs }).run_blocking();
}
struct Example {
jobs: Jobs,
}
impl GameState for Example {
fn enter(&mut self) {
self.jobs.spawn(JobLocation::Local, async {
let mut counter = 0;
for _ in 0..10 {
counter += 1;
// Yield execution to allow other jobs to run.
yield_now().await;
}
println!("Counter: {:?}", counter);
});
}
fn frame(&mut self, _delta_time: Duration) -> GameStateChange {
self.jobs.run_local();
quit_if_jobs_completed(&self.jobs)
}
}
Then we spawn some job somewhere in game:
use moirai::{coroutine::yield_now, job::JobLocation, jobs::Jobs};
use moirai_book_samples::{
game::{Game, GameState, GameStateChange},
utils::quit_if_jobs_completed,
};
use std::time::Duration;
fn main() {
let jobs = Jobs::default();
Game::new(Example { jobs }).run_blocking();
}
struct Example {
jobs: Jobs,
}
impl GameState for Example {
fn enter(&mut self) {
self.jobs.spawn(JobLocation::Local, async {
let mut counter = 0;
for _ in 0..10 {
counter += 1;
// Yield execution to allow other jobs to run.
yield_now().await;
}
println!("Counter: {:?}", counter);
});
}
fn frame(&mut self, _delta_time: Duration) -> GameStateChange {
self.jobs.run_local();
quit_if_jobs_completed(&self.jobs)
}
}
In game loop we run pending local jobs queue, usually at the end of game frame:
use moirai::{coroutine::yield_now, job::JobLocation, jobs::Jobs};
use moirai_book_samples::{
game::{Game, GameState, GameStateChange},
utils::quit_if_jobs_completed,
};
use std::time::Duration;
fn main() {
let jobs = Jobs::default();
Game::new(Example { jobs }).run_blocking();
}
struct Example {
jobs: Jobs,
}
impl GameState for Example {
fn enter(&mut self) {
self.jobs.spawn(JobLocation::Local, async {
let mut counter = 0;
for _ in 0..10 {
counter += 1;
// Yield execution to allow other jobs to run.
yield_now().await;
}
println!("Counter: {:?}", counter);
});
}
fn frame(&mut self, _delta_time: Duration) -> GameStateChange {
self.jobs.run_local();
quit_if_jobs_completed(&self.jobs)
}
}
As you see, this is bare minimum needed to process coroutines in your game. Just a runtime running local jobs at the end of a game frame, and a spawned jobs in it - that’s all!