use std::fmt::{self, Display, Formatter};
use super::super::ValidationCheck;
use super::super::paths::{
normalize_check_path_group, normalize_metadata_path, try_normalize_metadata_path,
};
impl ValidationCheck {
#[must_use]
pub fn code(&self) -> &'static str {
match self {
Self::AtLeastOneOf { .. } => "at_least_one_of",
Self::ExactlyOneOf { .. } => "exactly_one_of",
Self::MutuallyExclusive { .. } => "mutually_exclusive",
Self::RequiredWith { .. } => "required_with",
Self::RequiredIf { .. } => "required_if",
}
}
pub(in crate::metadata) fn normalize(self) -> Option<Self> {
match self {
Self::AtLeastOneOf { paths } => {
normalize_check_path_group(paths).map(|paths| Self::AtLeastOneOf { paths })
}
Self::ExactlyOneOf { paths } => {
normalize_check_path_group(paths).map(|paths| Self::ExactlyOneOf { paths })
}
Self::MutuallyExclusive { paths } => {
normalize_check_path_group(paths).map(|paths| Self::MutuallyExclusive { paths })
}
Self::RequiredWith { path, requires } => {
let path = normalize_metadata_path(&path);
let requires = normalize_check_path_group(requires)?;
Some(Self::RequiredWith { path, requires })
}
Self::RequiredIf {
path,
equals,
requires,
} => {
let path = normalize_metadata_path(&path);
let requires = normalize_check_path_group(requires)?;
Some(Self::RequiredIf {
path,
equals,
requires,
})
}
}
}
pub(in crate::metadata) fn prefixed(self, prefix: &str) -> Option<Self> {
let prefix = normalized_prefix(prefix);
if prefix.is_empty() {
return self.normalize();
}
let join = |path: String| {
if path.is_empty() {
prefix.clone()
} else {
format!("{prefix}.{path}")
}
};
match self {
Self::AtLeastOneOf { paths } => Some(Self::AtLeastOneOf {
paths: paths.into_iter().map(join).collect(),
})
.and_then(Self::normalize),
Self::ExactlyOneOf { paths } => Some(Self::ExactlyOneOf {
paths: paths.into_iter().map(join).collect(),
})
.and_then(Self::normalize),
Self::MutuallyExclusive { paths } => Some(Self::MutuallyExclusive {
paths: paths.into_iter().map(join).collect(),
})
.and_then(Self::normalize),
Self::RequiredWith { path, requires } => Some(Self::RequiredWith {
path: join(path),
requires: requires.into_iter().map(join).collect(),
})
.and_then(Self::normalize),
Self::RequiredIf {
path,
equals,
requires,
} => Some(Self::RequiredIf {
path: join(path),
equals,
requires: requires.into_iter().map(join).collect(),
})
.and_then(Self::normalize),
}
}
}
impl Display for ValidationCheck {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::AtLeastOneOf { paths } => {
write!(f, "at_least_one_of({})", paths.join(", "))
}
Self::ExactlyOneOf { paths } => {
write!(f, "exactly_one_of({})", paths.join(", "))
}
Self::MutuallyExclusive { paths } => {
write!(f, "mutually_exclusive({})", paths.join(", "))
}
Self::RequiredWith { path, requires } => {
write!(f, "required_with({path} -> {})", requires.join(", "))
}
Self::RequiredIf {
path,
equals,
requires,
} => write!(
f,
"required_if({path} == {equals} -> {})",
requires.join(", ")
),
}
}
}
fn normalized_prefix(prefix: &str) -> String {
if prefix.is_empty() {
return String::new();
}
try_normalize_metadata_path(prefix)
.ok()
.filter(|normalized| !normalized.is_empty())
.unwrap_or_else(|| prefix.to_owned())
}