afrim_memory/
lib.rs

1#![deny(missing_docs)]
2//! Data structure to make handling of sequential code more convenient.
3//!
4//! It takes sequential codes and generates a text buffer that will be used to easily get a
5//! corresponding character through an input.
6//!
7//! # Notes
8//! - sequence: A sequential code corresponding to a character.
9//!     Eg. af1 = "ɑ̀"
10//! - input: The user input (or a set of sequences).
11//!     Eg. ngaf7 nkwe2e2 ka7meru7n
12//! - text buffer: The memory where our text data will be stored.
13//! - node: A node in the text buffer.
14//!
15//! # Example
16//!
17//! ```
18//! use afrim_memory::{Node, utils};
19//!
20//! // Builds a TextBuffer.
21//! let text_buffer = Node::default();
22//! text_buffer.insert(vec!['a', 'f'], "ɑ".to_owned());
23//! text_buffer.insert(vec!['a', 'f', '1'], "ɑ̀".to_owned());
24//!
25//! // Bulk insertion of data in the TextBuffer.
26//! let data = vec![vec!["af11", "ɑ̀ɑ̀"], vec!["?.", "ʔ"]];
27//! let text_buffer = utils::build_map(data);
28//!
29//! // Traverses the tree.
30//! let node = text_buffer.goto('a').and_then(|node| node.goto('f')).and_then(|node| node.goto('1')).and_then(|node| node.goto('1'));
31//! assert_eq!(node.unwrap().take(), Some("ɑ̀ɑ̀".to_owned()));
32//! ```
33//!
34//! # Example: in reading data through a file
35//!
36//! ```no_run
37//! use afrim_memory::utils;
38//!
39//! // Import data from a string.
40//! let data = "a1 à\ne2 é";
41//! let data = utils::load_data(data);
42//! let text_buffer = utils::build_map(data);
43//! ```
44//!
45//! # Example: with the usage of a cursor
46//!
47//! ```
48//! use afrim_memory::{Cursor, Node};
49//! use std::rc::Rc;
50//!
51//! // Build a TextBuffer.
52//! let text_buffer = Node::default();
53//! text_buffer.insert(vec!['i', '-'], "ɨ".to_owned());
54//! text_buffer.insert(vec!['i', '-', '3'], "ɨ̄".to_owned());
55//!
56//! // Builds the cursor.
57//! let memory = Rc::new(text_buffer);
58//! let mut cursor = Cursor::new(memory, 16);
59//!
60//! // Moves the cursor through the input.
61//! let input = "i-3";
62//! input.chars().for_each(|c| { cursor.hit(c); });
63//! // Verify the current state.
64//! assert_eq!(cursor.state(), (Some("ɨ̄".to_owned()), 3, '3'));
65//!
66//! // Undo the last insertion.
67//! assert_eq!(cursor.undo(), Some("ɨ̄".to_owned()));
68//! // Verify the current state.
69//! assert_eq!(cursor.state(), (Some("ɨ".to_owned()), 2, '-'));
70//! ```
71//!
72//! [`TextBuffer`]: https://en.wikipedia.org/wiki/Text_buffer
73
74use std::collections::{HashMap, VecDeque};
75use std::{cell::RefCell, fmt, rc::Rc};
76pub mod utils;
77
78/// A node in the text buffer.
79///
80/// ```text
81///              0 ----------------> The root node
82///             / \
83///           'g' 's' -------------> Node: Rc<Node>
84///           /     \
85///   "ɣ" = '+'     'h' -----------> Node: Rc<Node>
86///                   \
87///                   '+' = "ʃ" ---> Node that holds a value
88/// ```
89#[derive(Clone, Debug)]
90pub struct Node {
91    children: RefCell<HashMap<char, Rc<Node>>>,
92    /// Depth of the node.
93    pub depth: usize,
94    /// Character holded by the node.
95    pub key: char,
96    value: RefCell<Option<String>>,
97}
98
99impl Default for Node {
100    /// Create a root node.
101    ///
102    /// A root node always holds a null character as key and is recommanded to use
103    /// to initialize the text buffer. You should always use it to create a text buffer because the
104    /// internal code can change.
105    ///
106    /// # Example
107    ///
108    /// ```
109    /// use afrim_memory::Node;
110    ///
111    /// // It's recommanded to use it, to initialize your text buffer.
112    /// let text_buffer = Node::default();
113    /// // Not recommanded.
114    /// let another_text_buffer = Node::new('\0', 0);
115    ///
116    /// assert!(text_buffer.is_root());
117    /// assert!(another_text_buffer.is_root());
118    /// ```
119    fn default() -> Self {
120        Self::new('\0', 0)
121    }
122}
123
124impl Node {
125    /// Initializes a new node in the text buffer.
126    ///
127    /// Can also be used to initialize the text buffer (not recommanded).
128    /// Uses [`Node::default`](crate::Node::default) instead.
129    ///
130    /// # Example
131    ///
132    /// ```
133    /// use afrim_memory::Node;
134    ///
135    /// let text_buffer = Node::new('\0', 0);
136    ///
137    /// // You cannot assign directly a value to a node.
138    /// // But, an alternative is as below.
139    /// let node = Node::new('u', 0);
140    /// node.insert(vec![], "ʉ̠̀".to_owned());
141    /// assert_eq!(node.take(), Some("ʉ̠̀".to_owned()));
142    /// ```
143    ///
144    /// **Note**: Early, [`Node::new`](crate::Node::new) was the only way to initialize a text
145    /// buffer but it has been replaced by [`Node::default`](crate::Node::default)
146    /// which is now more adapted for this use case.
147    pub fn new(key: char, depth: usize) -> Self {
148        Self {
149            children: HashMap::new().into(),
150            depth,
151            key,
152            value: None.into(),
153        }
154    }
155
156    /// Inserts a sequence in the text buffer.
157    ///
158    /// # Example
159    ///
160    /// ```
161    /// use afrim_memory::Node;
162    ///
163    /// let text_buffer = Node::default();
164    /// text_buffer.insert(vec!['.', 't'], "ṫ".to_owned());
165    ///
166    /// let node = text_buffer.goto('.').and_then(|node| node.goto('t'));
167    /// assert_eq!(node.unwrap().take(), Some("ṫ".to_owned()));
168    /// ```
169    pub fn insert(&self, sequence: Vec<char>, value: String) {
170        if let Some(character) = sequence.first() {
171            self.children
172                .borrow_mut()
173                .entry(*character)
174                .or_insert_with(|| Rc::new(Self::new(*character, self.depth + 1)))
175                .insert(sequence.into_iter().skip(1).collect(), value);
176        } else {
177            *self.value.borrow_mut() = Some(value);
178        };
179    }
180
181    /// Moves from the current node to his child.
182    ///
183    /// Useful to go through a sequence.
184    ///
185    /// # Example
186    ///
187    /// ```
188    /// use afrim_memory::Node;
189    ///
190    /// let text_buffer = Node::default();
191    /// text_buffer.insert(vec!['o', '/'], "ø".to_owned());
192    /// text_buffer.insert(vec!['o', '*'], "ɔ".to_owned());
193    /// text_buffer.insert(vec!['o', '1'], "ò".to_owned());
194    /// text_buffer.insert(vec!['o', '*', '~'], "ɔ̃".to_owned());
195    ///
196    /// // let sequence = ['o', '*', '~'];
197    /// let node = text_buffer.goto('o').unwrap();
198    /// assert_eq!(node.take(), None);
199    /// let node = node.goto('*').unwrap();
200    /// assert_eq!(node.take(), Some("ɔ".to_owned()));
201    /// let node = node.goto('~').unwrap();
202    /// assert_eq!(node.take(), Some("ɔ̃".to_owned()));
203    /// ```
204    pub fn goto(&self, character: char) -> Option<Rc<Self>> {
205        self.children.borrow().get(&character).map(Rc::clone)
206    }
207
208    /// Extracts the value of the node.
209    ///
210    /// A node in the text buffer don't always holds a value.
211    /// Hence, his value is optional.
212    ///
213    /// # Example
214    ///
215    /// ```
216    /// use afrim_memory::Node;
217    ///
218    /// let text_buffer = Node::default();
219    /// text_buffer.insert(vec!['1', 'c'], "c̀".to_string());
220    ///
221    /// let node = text_buffer.goto('1').unwrap();
222    /// assert_eq!(node.take(), None);
223    /// let node = node.goto('c').unwrap();
224    /// assert_eq!(node.take(), Some("c̀".to_owned()));
225    /// ```
226    pub fn take(&self) -> Option<String> {
227        self.value.borrow().as_ref().map(ToOwned::to_owned)
228    }
229
230    /// Returns true is the node is at the initial depth.
231    ///
232    /// Useful when dealing with the [`Cursor`].
233    /// Will permit to know the beginning and the end of a sequence.
234    ///
235    /// # Example
236    ///
237    /// ```
238    /// use afrim_memory::{Cursor, Node};
239    ///
240    /// let text_buffer = Node::default();
241    /// text_buffer.insert(vec!['e', '2' ], "é".to_owned());
242    /// text_buffer.insert(vec!['i', '7' ], "ǐ".to_owned());
243    ///
244    /// assert!(text_buffer.is_root());
245    /// let node = text_buffer.goto('e').unwrap();
246    /// assert!(!node.is_root());
247    ///
248    /// ```
249    pub fn is_root(&self) -> bool {
250        self.depth == 0
251    }
252}
253
254/// The Cursor permits to keep a track of the different positions while moving in
255/// the text buffer.
256///
257/// ```text
258/// '\0' - 'k' - '\0' - 'w' - '\0'  '\0'  '\0' - '\'' - 'n' - 'i' - '7' |--> 0
259///                            |    /|    /                             |
260///                            |   / |   /                              |
261///                           'e' / 'e' /                               |--> 1
262///                            | /   | /                                |
263///                           '2'   '2'                                 |--> 2
264///                                                                     |
265///                                                                     | depth
266///                                                                     v
267/// ```
268///
269/// # Example
270///
271/// ```
272/// use afrim_memory::{Cursor, Node};
273/// use std::rc::Rc;
274///
275/// let text_buffer = Node::default();
276/// text_buffer.insert(vec!['e', '2'], "é".to_owned());
277/// text_buffer.insert(vec!['i', '7'], "ǐ".to_owned());
278///
279/// // We build our cursor.
280/// let memory = Rc::new(text_buffer);
281/// let mut cursor = Cursor::new(memory, 16);
282/// let input = "nkwe2e2'ni7";
283/// input.chars().for_each(|c| { cursor.hit(c); });
284///
285/// assert_eq!(
286///     cursor.to_sequence(),
287///     vec![
288///         'k', '\0', 'w', '\0', 'e', '2', '\0', 'e', '2', '\0',
289///         '\'', '\0', 'n', '\0', 'i', '7'
290///     ]
291/// );
292/// ```
293///
294/// Note the partitioning of this input. The cursor can browse through the memory based
295/// on an input and save a track of his positions. It's useful when we want handle
296/// backspace operations in an input method engine.
297#[derive(Clone)]
298pub struct Cursor {
299    buffer: VecDeque<Rc<Node>>,
300    root: Rc<Node>,
301}
302
303impl fmt::Debug for Cursor {
304    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305        self.to_sequence().fmt(f)
306    }
307}
308
309impl Cursor {
310    /// Initializes the cursor of a text buffer.
311    ///
312    /// `capacity` is the number of hit that the cursor can track. The cursor follows the FIFO
313    /// rule. If the capacity is exceeded, the oldest hit will be discarded.
314    ///
315    /// **Note**: Be careful when you set this capacity. We recommend to select a capacity equal or
316    /// greater than the maximun sequence length that you want handle.
317    ///
318    /// # Example
319    ///
320    /// ```
321    /// use afrim_memory::{Cursor, Node};
322    /// use std::rc::Rc;
323    ///
324    /// let text_buffer = Node::default();
325    /// let memory = Rc::new(text_buffer);
326    ///
327    /// // A cursor of our text buffer.
328    /// let cursor = Cursor::new(memory, 16);
329    /// ```
330    ///
331    /// **Note**: It's recommended to initialize the text buffer with
332    /// [`Node::default`](crate::Node::default) to evict unexpected behaviors.
333    pub fn new(root: Rc<Node>, capacity: usize) -> Self {
334        Self {
335            buffer: VecDeque::with_capacity(capacity),
336            root,
337        }
338    }
339
340    /// Enters a character in the sequence and returns his corresponding out.
341    ///
342    /// Permits to simulate the user typing in the input method engine.
343    /// For each character entered, the cursor will move through the text buffer in looking of the
344    /// corresponding sequence. If the sequence is got (end on a value), his value will be returned.
345    ///
346    /// # Example
347    ///
348    /// ```
349    /// use afrim_memory::{Cursor, Node};
350    /// use std::rc::Rc;
351    ///
352    /// let text_buffer = Node::default();
353    /// text_buffer.insert(vec!['o', 'e'], "œ".to_owned());
354    /// let memory = Rc::new(text_buffer);
355    ///
356    /// let mut cursor = Cursor::new(memory, 16);
357    /// // let input= "coeur";
358    /// assert_eq!(cursor.hit('c'), None);
359    /// assert_eq!(cursor.hit('o'), None);
360    /// assert_eq!(cursor.hit('e'), Some("œ".to_owned()));
361    /// assert_eq!(cursor.hit('u'), None);
362    /// assert_eq!(cursor.hit('r'), None);
363    ///
364    /// assert_eq!(cursor.to_sequence(), vec!['\0', 'c', '\0', 'o', 'e', '\0', 'u', '\0', 'r']);
365    /// ```
366    ///
367    /// **Note**:
368    /// - The `\0` at the index 0, marks the beginning of a new sequence and the end of a
369    /// old. It also represents the root node.
370    /// - A character don't necessary need to be in the text buffer. The cursor will create a
371    /// tempory node to represent it in his internal memory. All characters not present in the text
372    /// buffer will be at the same depth that the root node.
373    pub fn hit(&mut self, character: char) -> Option<String> {
374        let node = self
375            .buffer
376            .iter()
377            .last()
378            .and_then(|node| node.goto(character))
379            .or_else(|| {
380                // We end the current sequence
381                self.insert(Rc::new(Node::default()));
382                // and start a new one
383                self.root.goto(character)
384            })
385            .unwrap_or_else(|| Rc::new(Node::new(character, 0)));
386
387        let out = node.take();
388        self.insert(node);
389
390        out
391    }
392
393    fn insert(&mut self, node: Rc<Node>) {
394        if self.buffer.len() == self.buffer.capacity() {
395            self.buffer.pop_front();
396        }
397        self.buffer.push_back(node);
398    }
399
400    /// Removes the last node and returns his corresponding out.
401    /// Or simplily, undo the previous hit.
402    ///
403    /// Useful to simulate a backspace operation.
404    ///
405    /// # Example
406    ///
407    /// ```
408    /// use afrim_memory::{Cursor, Node};
409    /// use std::rc::Rc;
410    ///
411    /// let text_buffer = Node::default();
412    /// text_buffer.insert(vec!['o', 'e'], "œ".to_owned());
413    /// let memory = Rc::new(text_buffer);
414    ///
415    /// let mut cursor = Cursor::new(memory, 16);
416    /// // let input = "coeur";
417    /// assert_eq!(cursor.hit('c'), None);
418    /// assert_eq!(cursor.hit('o'), None);
419    /// assert_eq!(cursor.hit('e'), Some("œ".to_owned()));
420    /// assert_eq!(cursor.hit('u'), None);
421    /// assert_eq!(cursor.hit('r'), None);
422    ///
423    /// // Undo
424    /// assert_eq!(cursor.undo(), None);
425    /// assert_eq!(cursor.undo(), None);
426    /// assert_eq!(cursor.undo(), Some("œ".to_owned()));
427    /// assert_eq!(cursor.undo(), None);
428    /// assert_eq!(cursor.undo(), None);
429    ///
430    /// assert_eq!(cursor.to_sequence(), vec!['\0']);
431    /// ```
432    ///
433    /// **Note**: Look at the `\0` at the end. It represents the root node, and the start of a
434    /// new sequence. Even if you remove it until obtain an empty buffer, the cursor will add it
435    /// before each new sequence. You can considere it as a delimiter between two sequences. But if
436    /// you want clear or verify if the buffer is empty, you can use [Cursor::clear](crate::Cursor::clear) or [Cursor::is_empty](crate::Cursor::is_empty).
437    pub fn undo(&mut self) -> Option<String> {
438        let node = self.buffer.pop_back();
439
440        node.and_then(|node| {
441            if node.key == '\0' {
442                self.undo()
443            } else {
444                node.take()
445            }
446        })
447    }
448
449    /// Resumes at the current sequence.
450    ///
451    /// By removing the end marker of the current sequence, this method allows the cursor
452    /// to continue using it as an ongoing sequence.
453    ///
454    /// # Example
455    ///
456    /// ```
457    /// use afrim_memory::{Cursor, Node};
458    /// use std::rc::Rc;
459    ///
460    /// let text_buffer = Node::default();
461    /// text_buffer.insert(vec!['c', '_'], "ç".to_owned());
462    /// let memory = Rc::new(text_buffer);
463    ///
464    /// let mut cursor = Cursor::new(memory, 8);
465    /// cursor.hit('c');
466    /// cursor.hit('c');
467    /// cursor.undo();
468    /// assert_eq!(cursor.to_sequence(), vec!['\0', 'c', '\0']);
469    ///
470    /// // We want the next hit to reuse this sequence.
471    /// cursor.resume();
472    /// assert_eq!(cursor.to_sequence(), vec!['\0', 'c']);
473    /// assert_eq!(cursor.hit('_'), Some("ç".to_owned()).to_owned());
474    /// ```
475    pub fn resume(&mut self) {
476        if self
477            .buffer
478            .iter()
479            .last()
480            .map_or(false, |node| node.is_root())
481        {
482            self.buffer.pop_back();
483        }
484    }
485
486    /// Returns the current state of the cursor.
487    ///
488    /// Permits to know the current position in the memory and also the last hit.
489    ///
490    /// # Example
491    ///
492    /// ```
493    /// use afrim_memory::{Cursor, Node};
494    /// use std::rc::Rc;
495    ///
496    /// let text_buffer = Node::default();
497    /// text_buffer.insert(vec!['o', '/'], "ø".to_owned());
498    /// let memory = Rc::new(text_buffer);
499    ///
500    /// let mut cursor = Cursor::new(memory, 8);
501    /// // The cursor starts always at the root node.
502    /// assert_eq!(cursor.state(), (None, 0, '\0'));
503    /// cursor.hit('o');
504    /// assert_eq!(cursor.state(), (None, 1, 'o'));
505    /// ```
506    pub fn state(&self) -> (Option<String>, usize, char) {
507        self.buffer
508            .iter()
509            .last()
510            .map(|n| (n.take(), n.depth, n.key))
511            .unwrap_or_default()
512    }
513
514    /// Returns the current sequence in the cursor.
515    ///
516    /// It's always useful to know what is inside the memory of the cursor for debugging / logging.
517    /// The
518    ///
519    /// # Example
520    ///
521    /// ```
522    /// use afrim_memory::{Cursor, Node};
523    /// use std::rc::Rc;
524    ///
525    /// let text_buffer = Node::default();
526    /// text_buffer.insert(vec!['.', '.', 'z'], "z̈".to_owned());
527    /// let memory = Rc::new(text_buffer);
528    ///
529    /// let mut cursor = Cursor::new(memory, 8);
530    /// "z..z".chars().for_each(|c| { cursor.hit(c); });
531    ///
532    /// assert_eq!(cursor.to_sequence(), vec!['\0', 'z', '\0', '.', '.', 'z']);
533    /// ```
534    pub fn to_sequence(&self) -> Vec<char> {
535        self.buffer.iter().map(|node| node.key).collect()
536    }
537
538    /// Clear the memory of the cursor.
539    ///
540    /// In clearing the internal buffer, all the tracking information will be lost.
541    ///
542    /// # Example
543    ///
544    /// ```
545    /// use afrim_memory::{Cursor, Node};
546    /// use std::rc::Rc;
547    ///
548    /// let text_buffer = Node::default();
549    /// let memory = Rc::new(text_buffer);
550    /// let mut cursor = Cursor::new(memory, 8);
551    ///
552    /// "hello".chars().for_each(|c| { cursor.hit(c); });
553    /// assert!(!cursor.is_empty());
554    ///
555    /// cursor.clear();
556    /// assert!(cursor.is_empty());
557    /// ```
558    pub fn clear(&mut self) {
559        self.buffer.clear();
560    }
561
562    /// Verify if the cursor is empty.
563    ///
564    /// # Example
565    ///
566    /// ```
567    /// use afrim_memory::{Cursor, Node};
568    /// use std::rc::Rc;
569    ///
570    /// let text_buffer = Node::default();
571    /// let memory = Rc::new(text_buffer);
572    ///
573    /// let mut cursor = Cursor::new(memory, 8);
574    /// assert!(cursor.is_empty());
575    ///
576    /// cursor.hit('a');
577    /// assert!(!cursor.is_empty());
578    /// ```
579    pub fn is_empty(&self) -> bool {
580        return self.buffer.iter().filter(|c| c.key != '\0').count() == 0;
581    }
582}
583
584#[cfg(test)]
585mod tests {
586    #[test]
587    fn test_node() {
588        use crate::Node;
589
590        let root = Node::default();
591
592        assert!(root.is_root());
593
594        root.insert(vec!['a', 'f'], "ɑ".to_owned());
595        root.insert(vec!['a', 'f', '1'], "ɑ̀".to_owned());
596
597        assert!(root.goto('a').is_some());
598        assert!(!root.goto('a').unwrap().is_root());
599        assert!(root.goto('b').is_none());
600
601        let node = root.goto('a').and_then(|e| e.goto('f'));
602        assert_eq!(node.as_ref().unwrap().take(), Some("ɑ".to_owned()));
603
604        let node = node.and_then(|e| e.goto('1'));
605        assert_eq!(node.as_ref().unwrap().take(), Some("ɑ̀".to_owned()));
606    }
607
608    #[test]
609    fn test_cursor() {
610        use crate::{utils, Cursor};
611        use std::rc::Rc;
612
613        macro_rules! hit {
614            ( $cursor:ident $( $c:expr ),* ) => (
615                $( $cursor.hit($c); )*
616            );
617        }
618
619        macro_rules! undo {
620            ( $cursor:ident $occ:expr ) => {
621                (0..$occ).into_iter().for_each(|_| {
622                    $cursor.undo();
623                });
624            };
625        }
626
627        let data = include_str!("../data/sample.txt");
628        let root = utils::build_map(utils::load_data(data));
629
630        let mut cursor = Cursor::new(Rc::new(root), 8);
631
632        assert_eq!(cursor.state(), (None, 0, '\0'));
633
634        hit!(cursor '2', 'i', 'a', 'f');
635        assert_eq!(cursor.to_sequence(), vec!['\0', '2', 'i', 'a', 'f']);
636
637        assert_eq!(cursor.state(), (Some("íɑ́".to_owned()), 4, 'f'));
638
639        undo!(cursor 1);
640        assert_eq!(cursor.to_sequence(), vec!['\0', '2', 'i', 'a']);
641
642        // Cursor::resume
643        hit!(cursor 'x');
644        assert_eq!(cursor.to_sequence(), vec!['\0', '2', 'i', 'a', '\0', 'x']);
645        undo!(cursor 1);
646        cursor.resume();
647        hit!(cursor 'f');
648        assert_eq!(cursor.to_sequence(), vec!['\0', '2', 'i', 'a', 'f']);
649
650        undo!(cursor 2);
651        cursor.hit('e');
652        assert_eq!(cursor.to_sequence(), vec!['\0', '2', 'i', 'e']);
653
654        undo!(cursor 2);
655        hit!(cursor 'o', 'o');
656        assert_eq!(cursor.to_sequence(), vec!['\0', '2', 'o', 'o']);
657
658        undo!(cursor 3);
659        assert_eq!(cursor.to_sequence(), vec!['\0']);
660
661        hit!(cursor '2', '2', 'u', 'a');
662        assert_eq!(
663            cursor.to_sequence(),
664            vec!['\0', '\0', '2', '\0', '2', 'u', 'a']
665        );
666        undo!(cursor 4);
667        assert_eq!(cursor.to_sequence(), vec!['\0', '\0']);
668        assert!(cursor.is_empty());
669        undo!(cursor 1);
670        assert_eq!(cursor.to_sequence(), vec![]);
671
672        hit!(
673            cursor
674            'a', 'a', '2', 'a', 'e', 'a', '2', 'f', 'a',
675            '2', '2', 'x', 'x', '2', 'i', 'a', '2', '2', '_', 'f',
676            '2', 'a', '2', 'a', '_'
677        );
678        assert_eq!(
679            cursor.to_sequence(),
680            vec!['f', '\0', '2', 'a', '\0', '2', 'a', '_']
681        );
682
683        assert_eq!(
684            format!("{:?}", cursor),
685            format!("{:?}", cursor.to_sequence())
686        );
687
688        cursor.clear();
689        assert_eq!(cursor.to_sequence(), vec![]);
690    }
691}