about summary refs log tree commit diff
path: root/src/history.rs
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2021-10-01 00:34:16 +0200
committerMel <einebeere@gmail.com>2021-10-01 00:34:16 +0200
commit3f5c5026909af023c8a3885a4a3d97c669302c1b (patch)
tree44c7e3e81d3b71ad6977afe4ac1596033b5834a6 /src/history.rs
parent8f700551fd3f98c7b9846af647a7318c171152a6 (diff)
downloadka-3f5c5026909af023c8a3885a4a3d97c669302c1b.tar.zst
ka-3f5c5026909af023c8a3885a4a3d97c669302c1b.zip
Global repository cursor
Diffstat (limited to 'src/history.rs')
-rw-r--r--src/history.rs112
1 files changed, 81 insertions, 31 deletions
diff --git a/src/history.rs b/src/history.rs
index 3f5e43f..c474143 100644
--- a/src/history.rs
+++ b/src/history.rs
@@ -1,6 +1,7 @@
 use std::{
     fs::File,
     io::{Read, Seek, Write},
+    path::PathBuf,
 };
 
 use serde::{Deserialize, Serialize};
@@ -10,8 +11,51 @@ use anyhow::{Context, Result};
 use crate::diff::ContentChange;
 
 #[derive(Serialize, Deserialize, Debug)]
+pub struct RepositoryHistory {
+    pub cursor: usize,
+    changes: Vec<RepositoryChange>,
+}
+
+impl RepositoryHistory {
+    pub fn from_file(file: &mut File) -> Result<RepositoryHistory> {
+        let mut buffer = Vec::new();
+        file.read_to_end(&mut buffer)
+            .context("Failed reading repository history.")?;
+
+        let repository_history = serde_json::from_slice::<RepositoryHistory>(&buffer);
+        repository_history.context("Corrupted repository history.")
+    }
+
+    pub fn write_to_file(&self, file: &mut File) -> anyhow::Result<()> {
+        let encoded: Vec<u8> = serde_json::to_vec(self)?;
+        file.rewind()?;
+        file.set_len(0)?;
+        file.write_all(encoded.as_ref())?;
+        Ok(())
+    }
+
+    pub fn add_change(&mut self, change: RepositoryChange) {
+        self.changes.push(change);
+    }
+}
+
+impl Default for RepositoryHistory {
+    fn default() -> Self {
+        Self {
+            cursor: 0,
+            changes: Vec::new(),
+        }
+    }
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub struct RepositoryChange {
+    pub affected_files: Vec<PathBuf>,
+    pub timestamp: u64,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
 pub struct FileHistory {
-    cursor: usize,
     changes: Vec<FileChange>,
 }
 
@@ -33,24 +77,30 @@ impl FileHistory {
         Ok(())
     }
 
-    pub fn cursor(&self) -> usize {
-        self.cursor
-    }
-
-    pub fn file_is_deleted(&self) -> bool {
-        match self.changes.last() {
-            Some(change) => match change {
-                FileChange::Deleted => true,
-                FileChange::Updated(_) => false,
+    pub fn is_file_deleted(&self, at_cursor: usize) -> bool {
+        match self
+            .changes
+            .iter()
+            .take_while(|c| c.change_index <= at_cursor)
+            .last()
+        {
+            Some(change) => match change.variant {
+                FileChangeVariant::Deleted => true,
+                FileChangeVariant::Updated(_) => false,
             },
             None => false,
         }
     }
 
-    pub fn get_content(&self) -> Vec<u8> {
+    pub fn get_content(&self, at_cursor: usize) -> Vec<u8> {
         let mut buffer = Vec::new();
-        for file_change in self.changes.iter().take(self.cursor + 1) {
-            if let FileChange::Updated(ref updated) = file_change {
+
+        for file_change in self
+            .changes
+            .iter()
+            .take_while(|change| change.change_index <= at_cursor)
+        {
+            if let FileChangeVariant::Updated(ref updated) = file_change.variant {
                 for change in updated.iter() {
                     change.apply(&mut buffer)
                 }
@@ -61,18 +111,6 @@ impl FileHistory {
         buffer
     }
 
-    pub fn set_cursor(&mut self, new_cursor: usize) {
-        if new_cursor < self.changes.len() {
-            self.cursor = new_cursor;
-        } else {
-            panic!(
-                "Out-of-bounds cursor for file history: {}, can be at most {}",
-                new_cursor,
-                self.changes.len() - 1
-            );
-        }
-    }
-
     pub fn add_change(&mut self, change: FileChange) {
         self.changes.push(change);
     }
@@ -81,14 +119,19 @@ impl FileHistory {
 impl Default for FileHistory {
     fn default() -> Self {
         Self {
-            cursor: 0,
             changes: Vec::new(),
         }
     }
 }
 
 #[derive(Serialize, Deserialize, Debug)]
-pub enum FileChange {
+pub struct FileChange {
+    pub change_index: usize,
+    pub variant: FileChangeVariant,
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+pub enum FileChangeVariant {
     Updated(Vec<ContentChange>),
     Deleted,
 }
@@ -107,19 +150,26 @@ mod tests {
         ];
 
         let mut history = FileHistory::default();
-        history.add_change(FileChange::Updated(Vec::new()));
+
+        history.add_change(FileChange {
+            change_index: 0,
+            variant: FileChangeVariant::Updated(Vec::new()),
+        });
 
         for old_index in 0..stages.len() - 1 {
             let old = stages[old_index].as_bytes();
             let new = stages[old_index + 1].as_bytes();
 
             let stage_difference = ContentChange::diff(old, new);
-            history.add_change(FileChange::Updated(stage_difference));
+
+            history.add_change(FileChange {
+                change_index: old_index + 1,
+                variant: FileChangeVariant::Updated(stage_difference),
+            });
         }
 
         for index in 0..stages.len() {
-            history.set_cursor(index);
-            assert_eq!(stages[index].as_bytes(), history.get_content());
+            assert_eq!(stages[index].as_bytes(), history.get_content(index));
         }
     }
 }