diff options
Diffstat (limited to 'src/history.rs')
| -rw-r--r-- | src/history.rs | 112 |
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)); } } } |
