use super::fields::{AssemblyChoice, PolicyField, SymmetryPolicy};
use super::profile::AnalysisPolicy;
use crate::diagnostic::{Code, Diagnostic};
impl AnalysisPolicy {
pub fn check_consistency(&self) -> Result<(), Diagnostic> {
let conflict = |reason: &str| {
Err(Diagnostic::new(Code::E6004)
.with_context(
"fields",
format!(
"{}, {}",
PolicyField::Assembly.name(),
PolicyField::Symmetry.name()
),
)
.with_context("assembly", assembly_name(&self.assembly))
.with_context("symmetry", symmetry_name(self.symmetry))
.with_context("reason", reason))
};
match (&self.assembly, self.symmetry) {
(AssemblyChoice::AsymmetricUnit, SymmetryPolicy::None)
| (
AssemblyChoice::Biological(_),
SymmetryPolicy::None | SymmetryPolicy::BiologicalAssembly,
) => Ok(()),
(
AssemblyChoice::Crystal { radius },
SymmetryPolicy::None | SymmetryPolicy::Crystallographic,
) => {
if radius.is_finite() && *radius > 0.0 {
Ok(())
} else {
Err(Diagnostic::new(Code::E6016)
.with_context("radius", radius.to_string())
.with_context("reason", "a crystal radius must be positive and finite"))
}
}
(AssemblyChoice::AsymmetricUnit, SymmetryPolicy::Crystallographic) => conflict(
"crystallographic copies need AssemblyChoice::Crystal, whose radius bounds them",
),
(AssemblyChoice::AsymmetricUnit, SymmetryPolicy::BiologicalAssembly) => conflict(
"biological-assembly copies need AssemblyChoice::Biological, which names the assembly",
),
(AssemblyChoice::Biological(_), SymmetryPolicy::Crystallographic) => {
conflict("a biological assembly is not generated by crystal symmetry")
}
(AssemblyChoice::Crystal { .. }, SymmetryPolicy::BiologicalAssembly) => {
conflict("crystal contacts are not a biological assembly")
}
}
}
}
fn assembly_name(choice: &AssemblyChoice) -> String {
match choice {
AssemblyChoice::AsymmetricUnit => "asymmetric-unit".to_owned(),
AssemblyChoice::Biological(id) => format!("biological:{id}"),
AssemblyChoice::Crystal { radius } => format!("crystal:{radius}"),
}
}
const fn symmetry_name(policy: SymmetryPolicy) -> &'static str {
match policy {
SymmetryPolicy::None => "none",
SymmetryPolicy::Crystallographic => "crystallographic",
SymmetryPolicy::BiologicalAssembly => "biological-assembly",
}
}
#[cfg(test)]
#[path = "consistency_tests.rs"]
mod tests;