1pub mod text_buffer {
41 use std::collections::{HashMap, VecDeque};
42 use std::{cell::RefCell, rc::Rc};
43
44 #[derive(Debug)]
45 pub struct Node {
46 neighbors: RefCell<HashMap<char, Rc<Node>>>,
47 pub depth: usize,
48 pub key: char,
49 value: RefCell<Option<String>>,
50 }
51
52 impl Default for Node {
53 fn default() -> Self {
54 Self::new('\0', 0)
55 }
56 }
57
58 impl Node {
59 pub fn new(key: char, depth: usize) -> Self {
61 Self {
62 neighbors: HashMap::new().into(),
63 depth,
64 key,
65 value: None.into(),
66 }
67 }
68
69 pub fn insert(&self, sequence: Vec<char>, value: String) {
71 if let Some(character) = sequence.clone().first() {
72 let new_node = Rc::new(Self::new(*character, self.depth + 1));
73
74 self.neighbors
75 .borrow()
76 .get(character)
77 .unwrap_or(&new_node)
78 .insert(sequence.into_iter().skip(1).collect(), value);
79
80 self.neighbors
81 .borrow_mut()
82 .entry(*character)
83 .or_insert(new_node);
84 } else {
85 *self.value.borrow_mut() = Some(value);
86 };
87 }
88
89 pub fn goto(&self, character: char) -> Option<Rc<Self>> {
91 self.neighbors.borrow().get(&character).map(Rc::clone)
92 }
93
94 pub fn take(&self) -> Option<String> {
96 self.value.borrow().as_ref().map(ToOwned::to_owned)
97 }
98
99 pub fn is_root(&self) -> bool {
101 self.depth == 0
102 }
103 }
104
105 #[derive(Clone)]
106 pub struct Cursor {
107 buffer: VecDeque<Rc<Node>>,
108 root: Rc<Node>,
109 }
110
111 impl Cursor {
112 pub fn new(root: Node, capacity: usize) -> Self {
114 Self {
115 buffer: VecDeque::with_capacity(capacity),
116 root: Rc::new(root),
117 }
118 }
119 pub fn hit(&mut self, character: char) -> Option<String> {
121 let node = self
122 .buffer
123 .iter()
124 .last()
125 .unwrap_or(&Rc::new(Node::new('\0', 0)))
126 .goto(character)
127 .or_else(|| {
128 self.insert(Rc::new(Node::new('\0', 0)));
130 self.root.goto(character)
132 })
133 .unwrap_or(Rc::new(Node::new(character, 0)));
134
135 let out = node.take();
136 self.insert(node);
137
138 out
139 }
140
141 fn insert(&mut self, node: Rc<Node>) {
142 if self.buffer.len() == self.buffer.capacity() {
143 self.buffer.pop_front();
144 }
145 self.buffer.push_back(node);
146 }
147
148 pub fn undo(&mut self) -> Option<String> {
150 let node = self.buffer.pop_back();
151
152 node.and_then(|node| {
153 if node.key == '\0' {
154 self.undo()
155 } else {
156 node.take()
157 }
158 })
159 }
160
161 pub fn state(&self) -> (Option<String>, usize, char) {
163 self.buffer
164 .iter()
165 .last()
166 .map(|n| (n.take(), n.depth, n.key))
167 .unwrap_or_default()
168 }
169
170 pub fn to_sequence(&self) -> Vec<char> {
172 self.buffer.iter().map(|node| node.key).collect()
173 }
174
175 pub fn clear(&mut self) {
177 self.buffer.clear();
178 }
179
180 pub fn is_empty(&self) -> bool {
182 return self.buffer.iter().filter(|c| c.key != '\0').count() == 0;
183 }
184 }
185}
186
187pub mod utils {
188 use crate::text_buffer;
189 use std::{fs, io};
190
191 pub fn load_data(file_path: &str) -> Result<Vec<Vec<String>>, io::Error> {
193 let data = fs::read_to_string(file_path)?;
194 let data = data
195 .trim()
196 .split('\n')
197 .map(|line| {
198 line.split_whitespace()
199 .filter(|token| !token.is_empty())
200 .map(ToOwned::to_owned)
201 .collect()
202 })
203 .collect();
204 Ok(data)
205 }
206
207 pub fn build_map(data: Vec<[&str; 2]>) -> text_buffer::Node {
209 let root = text_buffer::Node::default();
210
211 data.iter().for_each(|e| {
212 root.insert(e[0].chars().collect(), e[1].to_owned());
213 });
214
215 root
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 #[test]
222 fn test_load_data() {
223 use crate::utils;
224
225 utils::load_data("data/sample.txt")
226 .unwrap()
227 .iter()
228 .for_each(|pair| assert_eq!(pair.len(), 2));
229 }
230
231 #[test]
232 fn test_build_map() {
233 use crate::utils;
234
235 let data = vec![["af11", "ɑ̀ɑ̀"], ["?.", "ʔ"]];
236 utils::build_map(data);
237
238 let data = utils::load_data("data/sample.txt").unwrap();
239 utils::build_map(
240 data.iter()
241 .map(|e| [e[0].as_str(), e[1].as_str()])
242 .collect(),
243 );
244 }
245
246 #[test]
247 fn test_node() {
248 use crate::text_buffer;
249
250 let root = text_buffer::Node::default();
251
252 assert!(root.is_root());
253
254 root.insert(vec!['a', 'f'], "ɑ".to_owned());
255 root.insert(vec!['a', 'f', '1'], "ɑ̀".to_owned());
256
257 assert!(root.goto('a').is_some());
258 assert!(!root.goto('a').unwrap().is_root());
259 assert!(root.goto('b').is_none());
260
261 let node = root.goto('a').and_then(|e| e.goto('f'));
262 assert_eq!(node.as_ref().unwrap().take(), Some("ɑ".to_owned()));
263
264 let node = node.and_then(|e| e.goto('1'));
265 assert_eq!(node.as_ref().unwrap().take(), Some("ɑ̀".to_owned()));
266 }
267
268 #[test]
269 fn test_cursor() {
270 use crate::text_buffer;
271 use crate::utils;
272
273 macro_rules! hit {
274 ( $cursor:ident $( $c:expr ),* ) => (
275 $( $cursor.hit($c); )*
276 );
277 }
278
279 macro_rules! undo {
280 ( $cursor:ident $occ:expr ) => {
281 (0..$occ).into_iter().for_each(|_| {
282 $cursor.undo();
283 });
284 };
285 }
286
287 let data = utils::load_data("data/sample.txt").unwrap();
288 let root = utils::build_map(
289 data.iter()
290 .map(|e| [e[0].as_str(), e[1].as_str()])
291 .collect(),
292 );
293
294 let mut cursor = text_buffer::Cursor::new(root, 8);
295
296 assert_eq!(cursor.state(), (None, 0, '\0'));
297
298 hit!(cursor '2', 'i', 'a', 'f');
299 assert_eq!(cursor.to_sequence(), vec!['\0', '2', 'i', 'a', 'f']);
300
301 assert_eq!(cursor.state(), (Some("íɑ́".to_owned()), 4, 'f'));
302
303 undo!(cursor 1);
304 assert_eq!(cursor.to_sequence(), vec!['\0', '2', 'i', 'a']);
305
306 undo!(cursor 1);
307 cursor.hit('e');
308 assert_eq!(cursor.to_sequence(), vec!['\0', '2', 'i', 'e']);
309
310 undo!(cursor 2);
311 hit!(cursor 'o', 'o');
312 assert_eq!(cursor.to_sequence(), vec!['\0', '2', 'o', 'o']);
313
314 undo!(cursor 3);
315 assert_eq!(cursor.to_sequence(), vec!['\0']);
316
317 hit!(cursor '2', '2', 'u', 'a');
318 assert_eq!(
319 cursor.to_sequence(),
320 vec!['\0', '\0', '2', '\0', '2', 'u', 'a']
321 );
322 undo!(cursor 4);
323 assert_eq!(cursor.to_sequence(), vec!['\0', '\0']);
324 assert!(cursor.is_empty());
325 undo!(cursor 1);
326 assert_eq!(cursor.to_sequence(), vec![]);
327
328 hit!(
329 cursor
330 'a', 'a', '2', 'a', 'e', 'a', '2', 'f', 'a',
331 '2', '2', 'x', 'x', '2', 'i', 'a', '2', '2', '_', 'f',
332 '2', 'a', '2', 'a', '_'
333 );
334 assert_eq!(
335 cursor.to_sequence(),
336 vec!['f', '\0', '2', 'a', '\0', '2', 'a', '_']
337 );
338
339 cursor.clear();
340 assert_eq!(cursor.to_sequence(), vec![]);
341 }
342}