Skip to main content

pfx_editor_doc/
stamp.rs

1pub const REMEMBERED: usize = 512;
2
3pub fn hash(text: &str) -> u64 {
4    text.bytes().fold(0xcbf2_9ce4_8422_2325, |hash, byte| {
5        (hash ^ u64::from(byte)).wrapping_mul(0x0000_0100_0000_01b3)
6    })
7}
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10pub struct Stamp {
11    pub len: u64,
12    pub hash: u64,
13}
14
15impl Stamp {
16    pub fn of(text: &str) -> Stamp {
17        Stamp {
18            len: text.len() as u64,
19            hash: hash(text),
20        }
21    }
22}
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub enum Seen {
26    Current,
27    Earlier,
28    Outside,
29}
30
31#[derive(Clone, Debug, PartialEq, Eq)]
32pub enum Disk {
33    Same,
34    Own,
35    Outside(String),
36    Missing,
37}
38
39#[derive(Clone, Debug, Default, PartialEq, Eq)]
40pub struct Own {
41    current: Option<Stamp>,
42    written: Vec<Stamp>,
43}
44
45impl Own {
46    pub fn read(&mut self, text: &str) {
47        self.current = Some(Stamp::of(text));
48    }
49
50    pub fn wrote(&mut self, text: &str) -> Stamp {
51        let stamp = Stamp::of(text);
52        self.current = Some(stamp);
53        self.written.retain(|known| *known != stamp);
54        self.written.push(stamp);
55        if self.written.len() > REMEMBERED {
56            self.written.remove(0);
57        }
58        stamp
59    }
60
61    pub fn current(&self) -> Option<Stamp> {
62        self.current
63    }
64
65    pub fn seen(&self, stamp: Stamp) -> Seen {
66        if self.current == Some(stamp) {
67            Seen::Current
68        } else if self.written.contains(&stamp) {
69            Seen::Earlier
70        } else {
71            Seen::Outside
72        }
73    }
74}
75
76#[cfg(test)]
77mod tests {
78    use super::*;
79
80    #[test]
81    fn a_stamp_is_the_length_and_the_hash() {
82        assert_eq!(Stamp::of(""), Stamp::of(""));
83        assert_ne!(Stamp::of("a = 1\n"), Stamp::of("a = 2\n"));
84        assert_eq!(Stamp::of("abc").len, 3);
85        assert_eq!(hash(""), 0xcbf2_9ce4_8422_2325);
86    }
87
88    #[test]
89    fn own_writes_are_told_from_outside_ones() {
90        let mut own = Own::default();
91        own.read("a = 1\n");
92        assert_eq!(own.seen(Stamp::of("a = 1\n")), Seen::Current);
93        own.wrote("a = 2\n");
94        own.wrote("a = 3\n");
95        assert_eq!(own.seen(Stamp::of("a = 3\n")), Seen::Current);
96        assert_eq!(own.seen(Stamp::of("a = 2\n")), Seen::Earlier);
97        assert_eq!(own.seen(Stamp::of("a = 1\n")), Seen::Outside);
98        assert_eq!(own.seen(Stamp::of("a = 4\n")), Seen::Outside);
99    }
100
101    #[test]
102    fn only_the_last_writes_are_remembered() {
103        let mut own = Own::default();
104        for step in 0..REMEMBERED + 2 {
105            own.wrote(&step.to_string());
106        }
107        assert_eq!(own.seen(Stamp::of("0")), Seen::Outside);
108        assert_eq!(own.seen(Stamp::of("2")), Seen::Earlier);
109    }
110}