use std::fmt;
use crate::gmns::types::ZoneID;
#[derive(Debug, Clone)]
pub enum InvalidInputReason {
NoZones,
NoCentroids {
zone_count: usize,
missing_ids: Vec<ZoneID>,
},
ZeroAttributes { zone_ids: Vec<ZoneID> },
ZeroProductions {
total_pop: f64,
total_emp: f64,
total_hh: f64,
},
ZeroAttractions {
total_pop: f64,
total_emp: f64,
total_hh: f64,
},
DisconnectedComponents { components: Vec<Vec<ZoneID>> },
}
impl fmt::Display for InvalidInputReason {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InvalidInputReason::NoZones => {
write!(f, "no zones provided: at least one zone is required")
}
InvalidInputReason::NoCentroids {
zone_count,
missing_ids,
} => {
write!(
f,
"no zone centroids found in network: {} zones provided but none have a \
corresponding centroid node (zone_id on a network node); missing zone IDs: {:?}",
zone_count, missing_ids
)
}
InvalidInputReason::ZeroAttributes { zone_ids } => {
write!(
f,
"all zones have zero population, employment, and households: \
trip generation will produce zero demand; affected zone IDs: {:?}",
zone_ids
)
}
InvalidInputReason::ZeroProductions {
total_pop,
total_emp,
total_hh,
} => {
write!(
f,
"trip generation produced zero total productions: \
check production coefficients \
(total_pop={:.1}, total_emp={:.1}, total_hh={:.1})",
total_pop, total_emp, total_hh
)
}
InvalidInputReason::ZeroAttractions {
total_pop,
total_emp,
total_hh,
} => {
write!(
f,
"trip generation produced zero total attractions: \
check attraction coefficients \
(total_pop={:.1}, total_emp={:.1}, total_hh={:.1})",
total_pop, total_emp, total_hh
)
}
InvalidInputReason::DisconnectedComponents { components } => {
let parts: Vec<String> = components
.iter()
.map(|c| format!("{:?}", c))
.collect();
write!(
f,
"{} disconnected zone components detected: Furness requires every zone \
to exchange trips with every other zone; each component must be \
modeled separately; components: [{}]",
components.len(),
parts.join(", ")
)
}
}
}
}
#[derive(Debug, Clone)]
pub enum PipelineError {
MissingResult(String),
InvalidConfig(String),
InvalidInput(InvalidInputReason),
}
impl fmt::Display for PipelineError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PipelineError::MissingResult(msg) => {
write!(f, "missing result: {}", msg)
}
PipelineError::InvalidConfig(msg) => {
write!(f, "invalid config: {}", msg)
}
PipelineError::InvalidInput(reason) => {
write!(f, "invalid input: {}", reason)
}
}
}
}