///|
/// A runner supplied by the host for one independent dependency wave.
///
/// The graph planner never shares a mutable ready queue between waves. A
/// native caller can implement this trait with a thread pool, while a WASM
/// caller can dispatch the whole wave to its host scheduler.
pub(open) trait WaveExecutor {
fn run_wave(Self, Array[BuildEdge], Map[String, Rule]) -> Result[
Array[String],
String,
]
}
///|
pub(all) struct DryRunWaveExecutor {}
///|
pub impl WaveExecutor for DryRunWaveExecutor with fn run_wave(
self : DryRunWaveExecutor,
edges : Array[BuildEdge],
rules : Map[String, Rule],
) -> Result[Array[String], String] {
let _ = self
let commands : Array[String] = []
for edge in edges {
match edge.render_command(rules) {
Ok(command) => commands.push(command)
Err(error) => return Err(error)
}
}
Ok(commands)
}
///|
/// Execute independent waves without a shared mutable queue or lock.
pub fn[E : WaveExecutor] Scheduler::run_parallel_waves(
self : Scheduler[E],
target : String,
) -> Result[Array[String], String] {
let commands : Array[String] = []
match self.graph.parallel_waves(target) {
Err(error) => Err(error)
Ok(waves) => {
for wave in waves {
match self.executor.run_wave(wave, self.graph.rules) {
Ok(wave_commands) =>
for command in wave_commands {
commands.push(command)
}
Err(error) => return Err(error)
}
}
Ok(commands)
}
}
}