1use crate::{ActorId, WorkItem};
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use std::fmt;
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10#[serde(deny_unknown_fields)]
11pub struct Handoff {
12 pub from: ActorId,
14 pub to: ActorId,
16 pub actor: ActorId,
18 pub at: DateTime<Utc>,
20 pub reason: String,
22}
23
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
26#[serde(deny_unknown_fields)]
27pub struct ClaimRelease {
28 pub actor: ActorId,
30 pub at: DateTime<Utc>,
32 pub reason: String,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum Holding {
39 Owner,
41 OwnerUntil(DateTime<Utc>),
43 HandedTo(DateTime<Utc>),
45 HandedFrom(DateTime<Utc>),
47 Released(DateTime<Utc>),
49}
50
51impl fmt::Display for Holding {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 match self {
54 Self::Owner => write!(f, "owned the task at that time"),
55 Self::OwnerUntil(at) => write!(f, "owned the task then, until the handoff at {at}"),
56 Self::HandedTo(at) => write!(f, "received the task by the handoff at {at}"),
57 Self::HandedFrom(at) => write!(f, "held the task until the handoff at {at}"),
58 Self::Released(at) => write!(f, "released its claim on the task at {at}"),
59 }
60 }
61}
62
63impl WorkItem {
64 #[must_use]
69 pub fn held_by(&self, actor: &ActorId) -> bool {
70 self.execution.owner.as_ref() == Some(actor)
71 || self.execution.handoffs.iter().any(|h| h.from == *actor)
72 || self.execution.releases.iter().any(|r| r.actor == *actor)
73 }
74
75 #[must_use]
83 pub fn holding_at(&self, actor: &ActorId, at: DateTime<Utc>) -> Option<Holding> {
84 let earlier = self.execution.handoffs.iter().filter(|h| h.at <= at);
85 if let Some(h) = earlier.clone().find(|h| h.to == *actor) {
86 return Some(Holding::HandedTo(h.at));
87 }
88 if let Some(h) = earlier.clone().find(|h| h.from == *actor) {
89 return Some(Holding::HandedFrom(h.at));
90 }
91 if let Some(r) = self
92 .execution
93 .releases
94 .iter()
95 .find(|r| r.at <= at && r.actor == *actor)
96 {
97 return Some(Holding::Released(r.at));
98 }
99 match self.execution.handoffs.iter().find(|h| h.at > at) {
100 Some(later) if later.from == *actor => Some(Holding::OwnerUntil(later.at)),
101 None if self.execution.owner.as_ref() == Some(actor) => Some(Holding::Owner),
102 _ => None,
103 }
104 }
105}