1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
//! Computes the next state.

use processor::{Processor, ProcessorResult};
use world::World;

pub struct Simulation {
    procs: Vec<Box<Processor>>,
}

impl Simulation {
    /// Creates an empty simulation.
    pub fn new() -> Simulation {
        Simulation { procs: Vec::new() }
    }

    /// Creates an initialized simulation using the [builder pattern][bp].
    ///
    /// [bp]: https://doc.rust-lang.org/book/method-syntax.html#builder-pattern
    pub fn build() -> SimBuilder {
        SimBuilder::new()
    }

    /// Adds a new processor to the simulation.
    pub fn add_processor<T: Processor + 'static>(&mut self, p: T) -> ProcessorResult {
        self.procs.push(Box::new(p));
        Ok(())
    }

    /// Computes the next state of the world using the given processors.
    pub fn step(&mut self, world: World) -> World {
        let mut next_state = world;

        // TODO: Rich possibilities for multithreading here.
        for p in self.procs.iter_mut() {
            p.process();
        }

        next_state
    }
}

/// Consuming builder for easily constructing a new simulations.
pub struct SimBuilder {
    errors: Vec<String>,
    sim: Simulation,
}

impl SimBuilder {
    /// Starts building a new simulation.
    pub fn new() -> SimBuilder {
        SimBuilder {
            errors: Vec::new(),
            sim: Simulation::new(),
        }
    }

    /// Add a given processor to the simulation.
    pub fn with<T: Processor + 'static>(mut self, p: T) -> SimBuilder {
        let r = self.sim.add_processor(p);
        if let Err(e) = r {
            self.errors.push(e);
        }
        self
    }

    /// Returns the newly-built simulation or a list of any errors the
    /// processors may have encountered.
    pub fn done(self) -> Result<Simulation, Vec<String>> {
        if self.errors.is_empty() {
            Ok(self.sim)
        } else {
            Err(self.errors)
        }
    }
}