Skip to main content

blockworx_store/
recent.rs

1//! The documents to offer reopening, most recent first.
2//!
3//! Two functions rather than a list type, because the two shells hold the
4//! list in the two spellings their hosts remember a document by — a path in
5//! the eframe storage DB, a [`DocumentRef`](crate::storage::DocumentRef) in
6//! `localStorage` — and what they must agree on is the *policy*: newest
7//! first, mentioned once, and short.
8
9/// How many are kept. A short list is the point: the menu is a shortcut,
10/// not a history.
11pub const REMEMBERED: usize = 8;
12
13/// Put `named` at the front, where reopening it moves it back to.
14pub fn remember<T: PartialEq + Clone>(list: &mut Vec<T>, named: &T) {
15    forget(list, named);
16    list.insert(0, named.clone());
17    list.truncate(REMEMBERED);
18}
19
20/// Drop `named` — what opening a document that is gone or unreadable does,
21/// so a dead entry is offered once and not twice.
22pub fn forget<T: PartialEq>(list: &mut Vec<T>, named: &T) {
23    list.retain(|kept| kept != named);
24}
25
26#[cfg(test)]
27mod tests {
28    use super::*;
29
30    #[test]
31    fn the_list_is_most_recent_first_deduplicated_and_bounded() {
32        let mut list: Vec<String> = Vec::new();
33        for n in 0..(REMEMBERED + 3) {
34            remember(&mut list, &format!("d{n}"));
35        }
36        assert_eq!(list.len(), REMEMBERED);
37        assert_eq!(list[0], "d10", "newest first");
38
39        remember(&mut list, &"d10".to_owned());
40        assert_eq!(
41            list.iter().filter(|kept| *kept == "d10").count(),
42            1,
43            "reopening a remembered document mentions it once, not twice",
44        );
45        assert_eq!(list[0], "d10", "and moves it back to the front");
46
47        forget(&mut list, &"d10".to_owned());
48        assert!(!list.contains(&"d10".to_owned()));
49    }
50}