diff --git a/src/backup/delta.rs b/src/backup/delta.rs index b90ddfb..61ceb1c 100644 --- a/src/backup/delta.rs +++ b/src/backup/delta.rs @@ -63,24 +63,6 @@ impl Delta { out } - /// Modify the given state by applying this delta's changes to it - pub fn apply(&self, state: &mut HashMap>) { - // First we add new files, then we remove the old ones - for (dir, added) in self.added.iter() { - if let Some(current) = state.get_mut(dir) { - current.extend(added.iter().cloned()); - } else { - state.insert(dir.clone(), added.clone()); - } - } - - for (dir, removed) in self.removed.iter() { - if let Some(current) = state.get_mut(dir) { - current.retain(|k| !removed.contains(k)); - } - } - } - // Calculate the difference between this delta and the other delta. // // The difference simply means removing all adds and removes that are also performed in the diff --git a/src/backup/manager/mod.rs b/src/backup/manager/mod.rs index 72743b7..0c25aad 100644 --- a/src/backup/manager/mod.rs +++ b/src/backup/manager/mod.rs @@ -4,7 +4,7 @@ mod meta; pub use config::ManagerConfig; pub use meta::MetaManager; -use super::Backup; +use super::{Backup, State}; use crate::other; use chrono::SubsecRound; use chrono::Utc; @@ -72,10 +72,10 @@ where let mut backup = if !current_chain.is_empty() { let previous_backup = current_chain.last().unwrap(); - let state = Backup::state(current_chain); + let previous_state = State::from(current_chain.iter().map(|b| &b.delta)); Backup::create_from( - state, + previous_state, previous_backup.start_time, &self.backup_dir, &self.dirs, diff --git a/src/backup/mod.rs b/src/backup/mod.rs index 4515ba1..0b5e322 100644 --- a/src/backup/mod.rs +++ b/src/backup/mod.rs @@ -2,11 +2,13 @@ mod delta; mod io_ext; pub mod manager; mod path; +mod state; use delta::Delta; pub use manager::Manager; pub use manager::ManagerConfig; pub use manager::MetaManager; +pub use state::State; use chrono::Utc; use flate2::read::GzDecoder; @@ -14,7 +16,7 @@ use flate2::write::GzEncoder; use flate2::Compression; use path::PathExt; use serde::{Deserialize, Serialize}; -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use std::fmt; use std::fs::File; use std::io; @@ -61,18 +63,6 @@ impl Backup { self.metadata = Some(metadata); } - /// Resolve the state of the list of backups by applying their deltas in-order to an initially - /// empty state. - pub fn state(backups: &Vec) -> HashMap> { - let mut state: HashMap> = HashMap::new(); - - for backup in backups { - backup.delta.apply(&mut state); - } - - state - } - /// Create a new Full backup, populated with the given directories. /// /// # Arguments @@ -141,7 +131,7 @@ impl Backup { /// /// The `Backup` instance describing this new backup. pub fn create_from>( - previous_state: HashMap>, + previous_state: State, previous_start_time: chrono::DateTime, backup_dir: P, dirs: &Vec<(PathBuf, PathBuf)>, diff --git a/src/backup/state.rs b/src/backup/state.rs new file mode 100644 index 0000000..fa60738 --- /dev/null +++ b/src/backup/state.rs @@ -0,0 +1,70 @@ +use crate::backup::Delta; +use std::borrow::Borrow; +use std::collections::{HashMap, HashSet}; +use std::ops::Deref; +use std::path::PathBuf; + +/// Struct that represents a current state for a backup. This struct acts as a smart pointer around +/// a HashMap. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct State(HashMap>); + +impl State { + pub fn new() -> Self { + State(HashMap::new()) + } + + /// Apply the delta to the current state. + pub fn apply(&mut self, delta: &Delta) { + // First we add new files, then we remove the old ones + for (dir, added) in delta.added.iter() { + if let Some(current) = self.0.get_mut(dir) { + current.extend(added.iter().cloned()); + } else { + self.0.insert(dir.clone(), added.clone()); + } + } + + for (dir, removed) in delta.removed.iter() { + if let Some(current) = self.0.get_mut(dir) { + current.retain(|k| !removed.contains(k)); + } + } + } +} + +impl From for State +where + T: IntoIterator, + T::Item: Borrow, +{ + fn from(deltas: T) -> Self { + let mut state = State::new(); + + for delta in deltas { + state.apply(delta.borrow()); + } + + state + } +} + +impl AsRef>> for State { + fn as_ref(&self) -> &HashMap> { + &self.0 + } +} + +impl Deref for State { + type Target = HashMap>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Default for State { + fn default() -> Self { + Self::new() + } +}