codama_korok_plugins/
plugin.rs1use codama_errors::CodamaResult;
2use codama_korok_visitors::KorokVisitable;
3
4pub trait KorokPlugin {
5 fn on_initialized(&self, _visitable: &mut dyn KorokVisitable) -> CodamaResult<()> {
6 Ok(())
7 }
8
9 fn on_fields_set(&self, _visitable: &mut dyn KorokVisitable) -> CodamaResult<()> {
10 Ok(())
11 }
12
13 fn on_program_items_set(&self, _visitable: &mut dyn KorokVisitable) -> CodamaResult<()> {
14 Ok(())
15 }
16
17 fn on_root_node_set(&self, _visitable: &mut dyn KorokVisitable) -> CodamaResult<()> {
18 Ok(())
19 }
20}
21
22pub type ResolvePluginsResult<'a> = Box<dyn Fn(&mut dyn KorokVisitable) -> CodamaResult<()> + 'a>;
23
24pub fn resolve_plugins<'a>(plugins: &'a [Box<dyn KorokPlugin + 'a>]) -> ResolvePluginsResult<'a> {
26 Box::new(move |visitable: &mut dyn KorokVisitable| {
27 plugins
28 .iter()
29 .try_for_each(|plugin| plugin.on_initialized(visitable))?;
30 plugins
31 .iter()
32 .try_for_each(|plugin| plugin.on_fields_set(visitable))?;
33 plugins
34 .iter()
35 .try_for_each(|plugin| plugin.on_program_items_set(visitable))?;
36 plugins
37 .iter()
38 .try_for_each(|plugin| plugin.on_root_node_set(visitable))?;
39 Ok(())
40 })
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46 use codama_korok_visitors::KorokVisitor;
47 use std::{cell::RefCell, rc::Rc};
48
49 struct LoggingPluging {
50 id: String,
51 logs: Rc<RefCell<Vec<String>>>,
52 }
53 impl LoggingPluging {
54 fn new(id: &str, logs: Rc<RefCell<Vec<String>>>) -> Self {
55 Self {
56 id: id.into(),
57 logs,
58 }
59 }
60 }
61 impl KorokPlugin for LoggingPluging {
62 fn on_initialized(&self, _visitable: &mut dyn KorokVisitable) -> CodamaResult<()> {
63 self.logs
64 .borrow_mut()
65 .push(format!("Plugin {} - initialized", self.id));
66 Ok(())
67 }
68 fn on_fields_set(&self, _visitable: &mut dyn KorokVisitable) -> CodamaResult<()> {
69 self.logs
70 .borrow_mut()
71 .push(format!("Plugin {} - on_fields_set", self.id));
72 Ok(())
73 }
74 fn on_program_items_set(&self, _visitable: &mut dyn KorokVisitable) -> CodamaResult<()> {
75 self.logs
76 .borrow_mut()
77 .push(format!("Plugin {} - on_program_items_set", self.id));
78 Ok(())
79 }
80 fn on_root_node_set(&self, _visitable: &mut dyn KorokVisitable) -> CodamaResult<()> {
81 self.logs
82 .borrow_mut()
83 .push(format!("Plugin {} - on_root_node_set", self.id));
84 Ok(())
85 }
86 }
87
88 struct MockVisitable;
89 impl KorokVisitable for MockVisitable {
90 fn accept(&mut self, _visitor: &mut dyn KorokVisitor) -> CodamaResult<()> {
91 Ok(())
92 }
93 fn get_children(&mut self) -> Vec<&mut dyn KorokVisitable> {
94 Vec::new()
95 }
96 }
97
98 #[test]
99 fn test_resolve_plugins() -> CodamaResult<()> {
100 let logs = Rc::new(RefCell::new(Vec::new()));
101 let plugins: Vec<Box<dyn KorokPlugin>> = vec![
102 Box::new(LoggingPluging::new("A", logs.clone())),
103 Box::new(LoggingPluging::new("B", logs.clone())),
104 ];
105
106 let run_plugins = resolve_plugins(&plugins);
107 run_plugins(&mut MockVisitable)?;
108
109 assert_eq!(
110 logs.borrow().as_slice(),
111 &[
112 "Plugin A - initialized",
113 "Plugin B - initialized",
114 "Plugin A - on_fields_set",
115 "Plugin B - on_fields_set",
116 "Plugin A - on_program_items_set",
117 "Plugin B - on_program_items_set",
118 "Plugin A - on_root_node_set",
119 "Plugin B - on_root_node_set",
120 ]
121 );
122 Ok(())
123 }
124}