u_schedule/models/
task.rs1use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11
12use super::Activity;
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct Task {
24 pub id: String,
26 pub name: String,
28 pub category: String,
30 pub priority: i32,
32 pub deadline: Option<i64>,
34 pub release_time: Option<i64>,
36 pub activities: Vec<Activity>,
38 pub attributes: HashMap<String, String>,
40}
41
42impl Task {
43 pub fn new(id: impl Into<String>) -> Self {
45 Self {
46 id: id.into(),
47 name: String::new(),
48 category: String::new(),
49 priority: 0,
50 deadline: None,
51 release_time: None,
52 activities: Vec::new(),
53 attributes: HashMap::new(),
54 }
55 }
56
57 pub fn with_name(mut self, name: impl Into<String>) -> Self {
59 self.name = name.into();
60 self
61 }
62
63 pub fn with_category(mut self, category: impl Into<String>) -> Self {
65 self.category = category.into();
66 self
67 }
68
69 pub fn with_priority(mut self, priority: i32) -> Self {
71 self.priority = priority;
72 self
73 }
74
75 pub fn with_deadline(mut self, deadline_ms: i64) -> Self {
77 self.deadline = Some(deadline_ms);
78 self
79 }
80
81 pub fn with_release_time(mut self, release_ms: i64) -> Self {
83 self.release_time = Some(release_ms);
84 self
85 }
86
87 pub fn with_activity(mut self, activity: Activity) -> Self {
89 self.activities.push(activity);
90 self
91 }
92
93 pub fn with_attribute(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
95 self.attributes.insert(key.into(), value.into());
96 self
97 }
98
99 pub fn total_duration_ms(&self) -> i64 {
101 self.activities.iter().map(|a| a.duration.total_ms()).sum()
102 }
103
104 pub fn has_activities(&self) -> bool {
106 !self.activities.is_empty()
107 }
108
109 pub fn activity_count(&self) -> usize {
111 self.activities.len()
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118 use crate::models::ActivityDuration;
119
120 #[test]
121 fn test_task_builder() {
122 let task = Task::new("J1")
123 .with_name("Job 1")
124 .with_category("TypeA")
125 .with_priority(10)
126 .with_deadline(100_000)
127 .with_release_time(0)
128 .with_attribute("customer", "ACME");
129
130 assert_eq!(task.id, "J1");
131 assert_eq!(task.name, "Job 1");
132 assert_eq!(task.category, "TypeA");
133 assert_eq!(task.priority, 10);
134 assert_eq!(task.deadline, Some(100_000));
135 assert_eq!(task.release_time, Some(0));
136 assert_eq!(task.attributes.get("customer"), Some(&"ACME".to_string()));
137 }
138
139 #[test]
140 fn test_task_total_duration() {
141 let task = Task::new("J1")
142 .with_activity(
143 Activity::new("O1", "J1", 0).with_duration(ActivityDuration::fixed(1000)),
144 )
145 .with_activity(
146 Activity::new("O2", "J1", 1).with_duration(ActivityDuration::fixed(2000)),
147 );
148
149 assert_eq!(task.total_duration_ms(), 3000);
150 assert_eq!(task.activity_count(), 2);
151 assert!(task.has_activities());
152 }
153
154 #[test]
155 fn test_task_empty() {
156 let task = Task::new("empty");
157 assert_eq!(task.total_duration_ms(), 0);
158 assert!(!task.has_activities());
159 }
160}