1use std::fmt;
2use std::ops::{Deref, DerefMut};
3
4pub struct Editor<Node, State, Input> {
6 state: State,
8 blocks: Vec<Box<dyn Block<Node = Node, State = State, Input = Input>>>,
10 fallback_block: Option<Box<dyn Block<Node = Node, State = State, Input = Input>>>,
12}
13impl<Node, State, Input> Editor<Node, State, Input> {
14 pub fn new(state: State) -> Self {
16 Editor {
17 state,
18 blocks: Vec::new(),
19 fallback_block: None,
20 }
21 }
22 pub fn command<C: Command<State>>(&mut self, cmd: C) {
24 cmd.execute(&mut self.state)
25 }
26 pub fn add_block<B: Block<Node = Node, State = State, Input = Input> + 'static>(
28 &mut self,
29 block: B,
30 ) {
31 self.blocks.push(Box::new(block))
32 }
33
34 pub fn set_fallback_block(
36 &mut self,
37 block: Box<dyn Block<Node = Node, State = State, Input = Input>>,
38 ) {
39 self.fallback_block = Some(block);
40 }
41}
42
43impl<Node, State, Input> fmt::Debug for Editor<Node, State, Input>
44where
45 State: fmt::Debug,
46{
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 f.debug_struct("Editor")
49 .field("state", &self.state)
50 .field("blocks", &self.blocks.len())
51 .finish()
52 }
53}
54
55impl<Node, State, Input> Deref for Editor<Node, State, Input> {
56 type Target = State;
57
58 fn deref(&self) -> &Self::Target {
59 &self.state
60 }
61}
62
63impl<Node, State, Input> DerefMut for Editor<Node, State, Input> {
64 fn deref_mut(&mut self) -> &mut Self::Target {
65 &mut self.state
66 }
67}
68#[allow(unused_variables)]
70pub trait Block {
71 type Input;
72 type Node;
73 type State;
74 fn hook(&self, editor: &mut Editor<Self::Node, Self::State, Self::Input>) {}
76
77 fn accepts(&self, input: &Self::Input) -> bool {
79 false
80 }
81 fn parse(
83 &self,
84 editor: &Editor<Self::Node, Self::State, Self::Input>,
85 input: &Self::Input,
86 ) -> Self::Node;
87}
88
89
90pub trait Command<State> {
92 fn execute(&self, state: &mut State);
93}
94
95
96pub fn process_nodes<N, S, I, Iter: IntoIterator<Item = I>>(
104 editor: &Editor<N, S, I>,
105 children: Iter,
106) -> Vec<N> {
107 let blocks = &editor.blocks;
108 let mut parsed_nodes = Vec::new();
109 let children: Vec<I> = children.into_iter().collect();
110 for i in 0..children.len() {
111 if let Some(node) = children.get(i) {
112 let mut accepted = false;
113
114 for block in blocks {
115 if block.accepts(node) {
116 parsed_nodes.push(block.parse(editor, node));
117 accepted = true;
118 break;
119 }
120 }
121 if !accepted && editor.fallback_block.is_some() {
123 parsed_nodes.push(editor.fallback_block.as_ref().unwrap().parse(editor, node));
124 }
125 }
126 }
127
128 parsed_nodes
129}
130
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[derive(Debug, PartialEq, Eq)]
138 struct TestState {
139 value: i32,
140 }
141
142 struct TestBlock;
144
145 impl Block for TestBlock {
146 type Input = i32;
147 type Node = i32;
148 type State = TestState;
149
150 fn accepts(&self, input: &i32) -> bool {
151 *input % 2 == 0
152 }
153
154 fn parse(&self, _editor: &Editor<Self::Node, Self::State, Self::Input>, input: &i32) -> i32 {
155 *input * 2
156 }
157 }
158
159 struct TestCommand;
161
162 impl Command<TestState> for TestCommand {
163 fn execute(&self, state: &mut TestState) {
164 state.value += 1;
165 }
166 }
167
168 #[test]
169 fn test_editor_new() {
170 let editor: Editor<i32, TestState, i32> = Editor::new(TestState { value: 42 });
171 assert_eq!(editor.state.value, 42);
172 }
173
174 #[test]
175 fn test_editor_command() {
176 let mut editor: Editor<i32, TestState, i32> = Editor::new(TestState { value: 0 });
177 let command = TestCommand;
178 editor.command(command);
179 assert_eq!(editor.state.value, 1);
180 }
181
182 #[test]
183 fn test_editor_add_block() {
184 let mut editor: Editor<i32, TestState, i32> = Editor::new(TestState { value: 0 });
185 let block = TestBlock;
186 editor.add_block(block);
187 let input = 4;
188 let parsed_nodes = process_nodes(&editor, vec![input]);
189 assert_eq!(parsed_nodes, vec![8]); }
191
192 #[test]
193 fn test_editor_set_fallback_block() {
194 let mut editor: Editor<i32, TestState, i32> = Editor::new(TestState { value: 0 });
195 let fallback_block = Box::new(TestBlock);
196 editor.set_fallback_block(fallback_block);
197 let input = 3; let parsed_nodes = process_nodes(&editor, vec![input]);
199 assert_eq!(parsed_nodes, vec![6]); }
201
202 #[test]
203 fn test_process_nodes_no_blocks() {
204 let editor: Editor<i32, TestState, i32> = Editor::new(TestState { value: 0 });
205 let input = 5;
206 let parsed_nodes: Vec<_> = process_nodes(&editor, vec![input]);
207 assert_eq!(parsed_nodes, vec![]); }
209}