use crate::Plan;
use thiserror::Error;
mod conditions;
mod dependency;
mod entities;
mod events;
mod graph;
mod instructions;
mod provisional;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
pub enum EstimateError {
#[error("estimate values must be finite")]
NonFinite,
#[error("optimistic duration must be non-negative")]
Negative,
#[error("estimate must satisfy optimistic <= likely <= pessimistic")]
Unordered,
}
#[derive(Debug, Error)]
pub enum ValidationError {
#[error("invalid {entity} {id}: {reason}")]
Invalid {
entity: &'static str,
id: String,
reason: String,
},
#[error("invalid estimate for work {work}: {source}")]
Estimate {
work: crate::WorkItemId,
#[source]
source: EstimateError,
},
}
pub(crate) fn invalid(
entity: &'static str,
id: impl std::fmt::Display,
reason: impl Into<String>,
) -> ValidationError {
ValidationError::Invalid {
entity,
id: id.to_string(),
reason: reason.into(),
}
}
impl Plan {
pub fn validate(&self) -> Result<(), ValidationError> {
if self.format_version != 3 {
return Err(invalid(
"plan format",
self.workspace.id,
format!("unsupported version {}; expected 3", self.format_version),
));
}
for work in self.work_items.values() {
if !work.order.is_valid() {
return Err(invalid(
"work order",
work.id,
"order requires 1..128 digits and a nonzero final digit",
));
}
}
crate::asset::validate(self)?;
entities::validate(self)?;
crate::tracking::validate(self)?;
graph::validate(self)?;
conditions::validate(self)?;
dependency::validate(self)?;
crate::calendar::validate::validate(self)?;
provisional::validate(self)
}
}
#[cfg(test)]
mod tests;