From 3f5c5026909af023c8a3885a4a3d97c669302c1b Mon Sep 17 00:00:00 2001 From: Mel Date: Fri, 1 Oct 2021 00:34:16 +0200 Subject: Global repository cursor --- src/history.rs | 112 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 81 insertions(+), 31 deletions(-) (limited to 'src/history.rs') 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}; @@ -9,9 +10,52 @@ use anyhow::{Context, Result}; use crate::diff::ContentChange; +#[derive(Serialize, Deserialize, Debug)] +pub struct RepositoryHistory { + pub cursor: usize, + changes: Vec, +} + +impl RepositoryHistory { + pub fn from_file(file: &mut File) -> Result { + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer) + .context("Failed reading repository history.")?; + + let repository_history = serde_json::from_slice::(&buffer); + repository_history.context("Corrupted repository history.") + } + + pub fn write_to_file(&self, file: &mut File) -> anyhow::Result<()> { + let encoded: Vec = 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, + pub timestamp: u64, +} + #[derive(Serialize, Deserialize, Debug)] pub struct FileHistory { - cursor: usize, changes: Vec, } @@ -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 { + pub fn get_content(&self, at_cursor: usize) -> Vec { 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), 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)); } } } -- cgit 1.4.1