symp 0.5.0

symlink farm manager that utilizes configuration files to define symlink mappings
use std::collections::{HashMap, HashSet};

use serde::{Deserialize, Serialize};

mod default_values {
    const SOURCE_ROOT: &str = ".";
    const DESTINATION_ROOT: &str = "/";

    pub fn source_root() -> String {
        SOURCE_ROOT.to_string()
    }

    pub fn destination_root() -> String {
        DESTINATION_ROOT.to_string()
    }
}

#[derive(Debug, Deserialize)]
pub struct Config {
    #[serde(default)]
    pub defaults: Defaults,
    #[serde(default)]
    pub packages: HashMap<String, Package>,
}

#[derive(Debug, Default, Deserialize)]
pub struct Defaults {
    #[serde(default)]
    pub packages: PackageDefaults,
}

#[derive(Debug, Default, Deserialize)]
pub struct PackageDefaults {
    #[serde(default)]
    pub existing_file_policy: ExistingFilePolicy,
    #[serde(default = "default_values::source_root")]
    pub source_root: String,
    #[serde(default = "default_values::destination_root")]
    pub destination_root: String,
}

#[derive(Debug, Deserialize)]
pub struct Package {
    #[serde(default)]
    pub existing_file_policy: Option<ExistingFilePolicy>,
    #[serde(default)]
    pub source_root: Option<String>,
    #[serde(default)]
    pub destination_root: Option<String>,
    #[serde(default)]
    pub profiles: HashSet<String>,
    #[serde(default)]
    pub links: HashSet<Link>,
}

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum ExistingFilePolicy {
    #[default]
    Error,
    Backup,
    Replace,
    Skip,
}

#[derive(Debug, Hash, PartialEq, Eq, Deserialize)]
pub struct Link {
    pub source: String,
    pub destination: String,
}