dpm_engine/change/
applicability.rs1use dpm_model::{Applicability, Key, Plan, WorkItemId, WorkStatus};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9pub struct ApplicabilityChange {
10 pub work: WorkItemId,
12 pub key: Key,
14 pub status: WorkStatus,
16 pub in_flight: bool,
18 pub before: Option<Applicability>,
20 pub after: Option<Applicability>,
22}
23
24pub(super) fn changes(current: &Plan, proposed: &Plan) -> Vec<ApplicabilityChange> {
25 let before = current.applicability();
26 let after = proposed.applicability();
27 let mut ids: Vec<_> = before.keys().chain(after.keys()).copied().collect();
28 ids.sort();
29 ids.dedup();
30 let mut changes: Vec<_> = ids
31 .into_iter()
32 .filter(|id| before.get(id) != after.get(id))
33 .filter(|id| {
34 before.contains_key(id) && after.contains_key(id)
35 || !is_plain(before.get(id).or(after.get(id)))
36 })
37 .filter_map(|id| {
38 let work = proposed
39 .work_items
40 .get(&id)
41 .or_else(|| current.work_items.get(&id))?;
42 Some(ApplicabilityChange {
43 work: id,
44 key: work.key.clone(),
45 status: work.execution.status,
46 in_flight: !matches!(
47 work.execution.status,
48 WorkStatus::Proposed | WorkStatus::Planned
49 ),
50 before: before.get(&id).cloned(),
51 after: after.get(&id).cloned(),
52 })
53 })
54 .collect();
55 changes.sort_by(|a, b| a.key.cmp(&b.key));
56 changes
57}
58
59fn is_plain(state: Option<&Applicability>) -> bool {
61 state.is_none_or(Applicability::is_applicable)
62}