use std::collections::HashMap;
use std::fmt;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use tokio::io;
pub use pile_config::Config as PileConfig;
use crate::newtypes::{NonEmptyPileName, PileName};
use crate::paths::{HoardPath, RelativePath, SystemPath};
pub mod iter;
pub mod pile_config;
#[derive(Debug, Error)]
pub enum Error {
#[error("failed to copy {src} to {dest}: {error}")]
CopyFile {
src: PathBuf,
dest: PathBuf,
#[source]
error: io::Error,
},
#[error("failed to create {path}: {error}")]
CreateDir {
path: PathBuf,
#[source]
error: io::Error,
},
#[error("cannot read directory {path}: {error}")]
ReadDir {
path: PathBuf,
#[source]
error: io::Error,
},
#[error("both source (\"{src}\") and destination (\"{dest}\") exist but are not both files or both directories")]
TypeMismatch {
src: PathBuf,
dest: PathBuf,
},
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[serde(rename_all = "lowercase")]
pub enum Direction {
Backup,
Restore,
}
impl fmt::Display for Direction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Backup => write!(f, "backup"),
Self::Restore => write!(f, "restore"),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Pile {
pub config: PileConfig,
pub path: Option<SystemPath>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MultipleEntries {
pub piles: HashMap<NonEmptyPileName, Pile>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[allow(variant_size_differences)]
pub enum Hoard {
Anonymous(Pile),
Named(MultipleEntries),
}
impl Hoard {
#[must_use]
#[tracing::instrument(name = "get_hoard_paths")]
pub fn get_paths(
&self,
hoards_root: HoardPath,
) -> Box<dyn Iterator<Item = (PileName, HoardPath, SystemPath)>> {
match self {
Hoard::Anonymous(pile) => match pile.path.clone() {
None => Box::new(std::iter::empty()),
Some(path) => Box::new(std::iter::once({
(PileName::anonymous(), hoards_root, path)
})),
},
Hoard::Named(named) => Box::new(named.piles.clone().into_iter().filter_map(
move |(name, pile)| {
pile.path.map(|path| {
let pile_hoard_root = hoards_root.join(&RelativePath::from(&name));
(name.into(), pile_hoard_root, path)
})
},
)),
}
}
#[must_use]
pub fn get_pile(&self, name: &PileName) -> Option<&Pile> {
match (name.as_ref(), self) {
(None, Self::Anonymous(pile)) => Some(pile),
(Some(name), Self::Named(map)) => map.piles.get(name),
_ => None,
}
}
}