use serde::{Deserialize, Serialize};
use crate::config::{Config, MergeError, ValidationError};
#[cfg(feature = "edit")]
use crate::edit::ConfigEditError;
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
pub struct LinkConfig {
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_symbolic_links: Option<bool>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_hard_links: Option<bool>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_ref_links: Option<bool>,
}
impl LinkConfig {
pub fn is_empty(&self) -> bool {
self.allow_symbolic_links.is_none()
&& self.allow_hard_links.is_none()
&& self.allow_ref_links.is_none()
}
}
impl Config for LinkConfig {
fn get_extension_name(&self) -> String {
"link".to_string()
}
fn merge_config(self, other: &Self) -> Result<Self, MergeError> {
Ok(Self {
allow_symbolic_links: other.allow_symbolic_links.or(self.allow_symbolic_links),
allow_hard_links: other.allow_hard_links.or(self.allow_hard_links),
allow_ref_links: other.allow_ref_links.or(self.allow_ref_links),
})
}
fn validate(&self) -> Result<(), ValidationError> {
Ok(())
}
fn keys(&self) -> Vec<String> {
vec![
"allow-symbolic-links".to_string(),
"allow-hard-links".to_string(),
"allow-ref-links".to_string(),
]
}
#[cfg(feature = "edit")]
fn set(&mut self, key: &str, value: Option<String>) -> Result<(), ConfigEditError> {
let parse = |v: String| {
v.parse::<bool>()
.map_err(|e| ConfigEditError::BoolParseError {
key: key.to_string(),
source: e,
})
};
match key {
"allow-symbolic-links" => {
self.allow_symbolic_links = value.map(parse).transpose()?;
}
"allow-hard-links" => {
self.allow_hard_links = value.map(parse).transpose()?;
}
"allow-ref-links" => {
self.allow_ref_links = value.map(parse).transpose()?;
}
_ => {
return Err(ConfigEditError::UnknownKeyInner {
key: key.to_string(),
});
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_is_empty() {
assert!(LinkConfig::default().is_empty());
}
#[test]
fn merge_other_wins() {
let base = LinkConfig {
allow_symbolic_links: Some(true),
allow_hard_links: None,
allow_ref_links: Some(false),
};
let override_ = LinkConfig {
allow_symbolic_links: Some(false),
allow_hard_links: Some(true),
allow_ref_links: None,
};
let merged = base.merge_config(&override_).unwrap();
assert_eq!(merged.allow_symbolic_links, Some(false));
assert_eq!(merged.allow_hard_links, Some(true));
assert_eq!(merged.allow_ref_links, Some(false));
}
#[test]
fn deserialize_kebab_case() {
let toml = r#"
allow-symbolic-links = true
allow-hard-links = false
allow-ref-links = true
"#;
let config: LinkConfig = toml::from_str(toml).unwrap();
assert_eq!(config.allow_symbolic_links, Some(true));
assert_eq!(config.allow_hard_links, Some(false));
assert_eq!(config.allow_ref_links, Some(true));
}
}