1use std::collections::HashMap;
2
3use crate::turtle::TurtleContainer;
4use crate::{ArenaId, LSystem};
5
6#[cfg(feature = "image_renderer")]
7pub use crate::image_renderer::ImageRendererOptionsBuilder;
8
9#[cfg(feature = "image_renderer")]
10pub use crate::image_renderer::VideoRendererOptionsBuilder;
11
12pub trait Renderer<S> {
13 type Output;
15
16 fn render(self, system: &LSystem, options: &S) -> Self::Output;
18}
19
20pub struct TurtleRenderer<Q: TurtleContainer> {
21 pub(crate) state: Q,
22 state_actions: HashMap<ArenaId, Box<dyn Fn(&mut Q)>>,
23 aliases: HashMap<ArenaId, ArenaId>,
24}
25
26impl<Q: TurtleContainer> TurtleRenderer<Q> {
27 pub fn new(state: Q) -> Self {
28 Self {
29 state,
30 state_actions: HashMap::new(),
31 aliases: HashMap::new(),
32 }
33 }
34
35 pub fn register<F: 'static + Fn(&mut Q)>(&mut self, arena_id: ArenaId, modifier: F) {
36 self.aliases.insert(arena_id, arena_id);
37 self.state_actions.insert(arena_id, Box::from(modifier));
38 }
39
40 pub fn register_multiple<F: 'static + Fn(&mut Q)>(
41 &mut self,
42 arena_ids: &[ArenaId],
43 modifier: F,
44 ) {
45 if let Some(id) = arena_ids.first() {
46 for aliased_id in arena_ids.iter() {
48 self.aliases.insert(*aliased_id, *id);
49 }
50
51 self.register(*id, modifier);
53 }
54 }
55
56 pub(crate) fn compute(&mut self, system_state: &[ArenaId]) {
57 for arena_id in system_state {
58 if self.aliases.contains_key(arena_id) {
59 let alias = self.aliases[arena_id];
61
62 if self.state_actions.contains_key(&alias) {
65 self.state_actions[&alias](&mut self.state);
66 }
67 }
68 }
69 }
70}
71
72#[derive(Default)]
75pub struct DataRendererOptions {}
76
77impl<Q: TurtleContainer> Renderer<DataRendererOptions> for TurtleRenderer<Q> {
78 type Output = Vec<(i32, i32, i32, i32)>;
79
80 fn render(mut self, system: &LSystem, _options: &DataRendererOptions) -> Self::Output {
81 self.compute(system.get_state());
83
84 self.state.inner().inner().lines().to_vec()
86 }
87}