Skip to main content

terrain_forge/compose/
pipeline.rs

1//! Pipeline for sequential algorithm execution.
2//!
3//! This is the lightweight, algorithm-only pipeline (not the ops pipeline).
4
5use crate::{Algorithm, Cell, Grid};
6
7/// Sequential algorithm pipeline.
8///
9/// # Examples
10///
11/// ```
12/// use terrain_forge::Grid;
13/// use terrain_forge::compose::Pipeline;
14/// use terrain_forge::algorithms::{Bsp, CellularAutomata};
15///
16/// let mut grid = Grid::new(40, 30);
17/// let pipe = Pipeline::new()
18///     .then(Bsp::default())
19///     .then(CellularAutomata::default());
20/// pipe.execute(&mut grid, 42);
21/// ```
22pub struct Pipeline<C: Cell> {
23    steps: Vec<Box<dyn Algorithm<C> + Send + Sync>>,
24}
25
26impl<C: Cell> Pipeline<C> {
27    pub fn new() -> Self {
28        Self { steps: Vec::new() }
29    }
30
31    pub fn then<A: Algorithm<C> + 'static>(mut self, algorithm: A) -> Self {
32        self.steps.push(Box::new(algorithm));
33        self
34    }
35
36    pub fn execute(&self, grid: &mut Grid<C>, seed: u64) {
37        for (i, step) in self.steps.iter().enumerate() {
38            step.generate(grid, seed.wrapping_add(i as u64 * 1000));
39        }
40    }
41}
42
43impl<C: Cell> Default for Pipeline<C> {
44    fn default() -> Self {
45        Self::new()
46    }
47}
48
49impl<C: Cell> Algorithm<C> for Pipeline<C> {
50    fn generate(&self, grid: &mut Grid<C>, seed: u64) {
51        self.execute(grid, seed);
52    }
53
54    fn name(&self) -> &'static str {
55        "Pipeline"
56    }
57}