feat(backup): implement mutation methods and specialized PartialEq for State
parent
3f00eee61e
commit
22a6e68c7c
|
@ -1,8 +1,4 @@
|
||||||
use std::{
|
use std::{borrow::Borrow, fmt, path::PathBuf};
|
||||||
borrow::Borrow,
|
|
||||||
fmt,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -153,14 +149,7 @@ impl Delta {
|
||||||
I: IntoIterator,
|
I: IntoIterator,
|
||||||
I::Item: Into<PathBuf>,
|
I::Item: Into<PathBuf>,
|
||||||
{
|
{
|
||||||
let dir: PathBuf = dir.into();
|
self.added.append_dir(dir, files);
|
||||||
let files = files.into_iter().map(Into::into);
|
|
||||||
|
|
||||||
if let Some(dir_files) = self.added.get_mut(&dir) {
|
|
||||||
dir_files.extend(files);
|
|
||||||
} else {
|
|
||||||
self.added.insert(dir, files.collect());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper around the `append_added` method for a builder-style construction of delta's
|
/// Wrapper around the `append_added` method for a builder-style construction of delta's
|
||||||
|
@ -179,14 +168,7 @@ impl Delta {
|
||||||
I: IntoIterator,
|
I: IntoIterator,
|
||||||
I::Item: Into<PathBuf>,
|
I::Item: Into<PathBuf>,
|
||||||
{
|
{
|
||||||
let dir: PathBuf = dir.into();
|
self.removed.append_dir(dir, files);
|
||||||
let files = files.into_iter().map(Into::into);
|
|
||||||
|
|
||||||
if let Some(dir_files) = self.removed.get_mut(&dir) {
|
|
||||||
dir_files.extend(files);
|
|
||||||
} else {
|
|
||||||
self.removed.insert(dir, files.collect());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper around the `append_removed` method for a builder-style construction of delta's
|
/// Wrapper around the `append_removed` method for a builder-style construction of delta's
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::Delta;
|
||||||
|
|
||||||
/// Struct that represents a current state for a backup. This struct acts as a smart pointer around
|
/// Struct that represents a current state for a backup. This struct acts as a smart pointer around
|
||||||
/// a HashMap.
|
/// a HashMap.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
pub struct State(HashMap<PathBuf, HashSet<PathBuf>>);
|
pub struct State(HashMap<PathBuf, HashSet<PathBuf>>);
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
|
@ -49,8 +49,52 @@ impl State {
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.0.values().all(|s| s.is_empty())
|
self.0.values().all(|s| s.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn append_dir<I>(&mut self, dir: impl Into<PathBuf>, files: I)
|
||||||
|
where
|
||||||
|
I: IntoIterator,
|
||||||
|
I::Item: Into<PathBuf>,
|
||||||
|
{
|
||||||
|
let dir = dir.into();
|
||||||
|
let files = files.into_iter().map(Into::into);
|
||||||
|
|
||||||
|
if let Some(dir_files) = self.0.get_mut(&dir) {
|
||||||
|
dir_files.extend(files);
|
||||||
|
} else {
|
||||||
|
self.0.insert(dir, files.collect());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_dir<I>(mut self, dir: impl Into<PathBuf>, files: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator,
|
||||||
|
I::Item: Into<PathBuf>,
|
||||||
|
{
|
||||||
|
self.append_dir(dir, files);
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for State {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
let self_non_empty = self.0.values().filter(|files| !files.is_empty()).count();
|
||||||
|
let other_non_empty = other.0.values().filter(|files| !files.is_empty()).count();
|
||||||
|
|
||||||
|
if self_non_empty != other_non_empty {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both states have the same number of non-empty directories, then comparing each
|
||||||
|
// directory of one with the other will only be true if their list of non-empty directories
|
||||||
|
// is identical.
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.all(|(dir, files)| files.is_empty() || other.0.get(dir).map_or(false, |v| v == files))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for State {}
|
||||||
|
|
||||||
impl<T> From<T> for State
|
impl<T> From<T> for State
|
||||||
where
|
where
|
||||||
T: IntoIterator,
|
T: IntoIterator,
|
||||||
|
@ -86,3 +130,33 @@ impl DerefMut for State {
|
||||||
&mut self.0
|
&mut self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_eq() {
|
||||||
|
let a = State::default().with_dir("dir1", ["file1", "file2"]);
|
||||||
|
let b = State::default().with_dir("dir1", ["file1", "file2"]);
|
||||||
|
|
||||||
|
assert_eq!(a, b);
|
||||||
|
|
||||||
|
let b = b.with_dir("dir2", ["file3"]);
|
||||||
|
|
||||||
|
assert_ne!(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_eq_empty_dirs() {
|
||||||
|
let a = State::default().with_dir("dir1", ["file1", "file2"]);
|
||||||
|
let b = State::default()
|
||||||
|
.with_dir("dir1", ["file1", "file2"])
|
||||||
|
.with_dir("dir2", Vec::<PathBuf>::new());
|
||||||
|
|
||||||
|
assert_eq!(a, b);
|
||||||
|
|
||||||
|
let b = b.with_dir("dir2", ["file3"]);
|
||||||
|
assert_ne!(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue