95 lines
2.4 KiB
Rust
95 lines
2.4 KiB
Rust
use crate::backup::Delta;
|
|
use serde::{Deserialize, Serialize};
|
|
use std::borrow::Borrow;
|
|
use std::collections::{HashMap, HashSet};
|
|
use std::ops::{Deref, DerefMut};
|
|
use std::path::{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, Serialize, Deserialize)]
|
|
pub struct State(HashMap<PathBuf, HashSet<PathBuf>>);
|
|
|
|
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));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returns whether the provided relative path is part of the given state.
|
|
pub fn contains<P: AsRef<Path>>(&self, path: P) -> bool {
|
|
let path = path.as_ref();
|
|
|
|
self.0.iter().any(|(dir, files)| {
|
|
path.starts_with(dir) && files.contains(path.strip_prefix(dir).unwrap())
|
|
})
|
|
}
|
|
|
|
/// Returns whether the state is empty.
|
|
///
|
|
/// Note that this does not necessarily mean that the state does not contain any sets, but
|
|
/// rather that any sets that it does contain are also empty.
|
|
pub fn is_empty(&self) -> bool {
|
|
self.0.values().all(|s| s.is_empty())
|
|
}
|
|
}
|
|
|
|
impl<T> From<T> for State
|
|
where
|
|
T: IntoIterator,
|
|
T::Item: Borrow<Delta>,
|
|
{
|
|
fn from(deltas: T) -> Self {
|
|
let mut state = State::new();
|
|
|
|
for delta in deltas {
|
|
state.apply(delta.borrow());
|
|
}
|
|
|
|
state
|
|
}
|
|
}
|
|
|
|
impl AsRef<HashMap<PathBuf, HashSet<PathBuf>>> for State {
|
|
fn as_ref(&self) -> &HashMap<PathBuf, HashSet<PathBuf>> {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl Deref for State {
|
|
type Target = HashMap<PathBuf, HashSet<PathBuf>>;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl DerefMut for State {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
&mut self.0
|
|
}
|
|
}
|
|
|
|
impl Default for State {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|