use dpm_model::{Applicability, Key, Plan, WorkItemId, WorkStatus};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ApplicabilityChange {
pub work: WorkItemId,
pub key: Key,
pub status: WorkStatus,
pub in_flight: bool,
pub before: Option<Applicability>,
pub after: Option<Applicability>,
}
pub(super) fn changes(current: &Plan, proposed: &Plan) -> Vec<ApplicabilityChange> {
let before = current.applicability();
let after = proposed.applicability();
let mut ids: Vec<_> = before.keys().chain(after.keys()).copied().collect();
ids.sort();
ids.dedup();
let mut changes: Vec<_> = ids
.into_iter()
.filter(|id| before.get(id) != after.get(id))
.filter(|id| {
before.contains_key(id) && after.contains_key(id)
|| !is_plain(before.get(id).or(after.get(id)))
})
.filter_map(|id| {
let work = proposed
.work_items
.get(&id)
.or_else(|| current.work_items.get(&id))?;
Some(ApplicabilityChange {
work: id,
key: work.key.clone(),
status: work.execution.status,
in_flight: !matches!(
work.execution.status,
WorkStatus::Proposed | WorkStatus::Planned
),
before: before.get(&id).cloned(),
after: after.get(&id).cloned(),
})
})
.collect();
changes.sort_by(|a, b| a.key.cmp(&b.key));
changes
}
fn is_plain(state: Option<&Applicability>) -> bool {
state.is_none_or(Applicability::is_applicable)
}