scientific_workflow/study/
task.rs1use std::error::Error;
4
5use serde::de::DeserializeOwned;
6use serde_json::Value;
7
8use super::error::StudyError;
9use super::phase::{Task, TaskId, TaskKey};
10use super::renderer::{OneShotTaskHandle, TaskProgressHandle};
11
12pub type TaskResult = Result<(), Box<dyn Error + Send + Sync + 'static>>;
14
15pub(crate) type Workload = Box<dyn FnOnce(&TaskContext) -> TaskResult + Send + 'static>;
16
17enum TaskHandle {
18 Progress(TaskProgressHandle),
19 OneShot(OneShotTaskHandle),
20}
21
22pub struct TaskContext {
28 task: Task,
29 handle: TaskHandle,
30}
31
32impl TaskContext {
33 pub(crate) fn progress(task: Task, progress: TaskProgressHandle) -> Self {
34 Self {
35 task,
36 handle: TaskHandle::Progress(progress),
37 }
38 }
39
40 pub(crate) fn one_shot(task: Task, one_shot: OneShotTaskHandle) -> Self {
41 Self {
42 task,
43 handle: TaskHandle::OneShot(one_shot),
44 }
45 }
46
47 pub fn task(&self) -> &Task {
49 &self.task
50 }
51
52 pub fn key(&self) -> &TaskKey {
54 self.task.key()
55 }
56
57 pub fn id(&self) -> &TaskId {
59 self.task.id()
60 }
61
62 pub fn category(&self) -> &str {
64 self.task.category_name()
65 }
66
67 pub fn metadata(&self, key: &str) -> Option<&Value> {
69 self.task.metadata_value(key)
70 }
71
72 pub fn decode_metadata<T>(&self, key: &str) -> Result<T, StudyError>
74 where
75 T: DeserializeOwned,
76 {
77 self.task.decode_metadata(key)
78 }
79
80 pub fn set_target_iteration(&self, target: u64) -> Result<(), StudyError> {
82 self.required_progress()?.set_target_iteration(target)
83 }
84
85 pub fn set_iteration(&self, iteration: u64) -> Result<(), StudyError> {
87 self.required_progress()?.set_iteration(iteration)
88 }
89
90 pub fn should_continue(&self, iteration: u64) -> Result<bool, StudyError> {
92 self.required_progress()?.should_continue(iteration)
93 }
94
95 pub fn is_cancelled(&self) -> bool {
97 match &self.handle {
98 TaskHandle::Progress(progress) => progress.is_cancelled(),
99 TaskHandle::OneShot(one_shot) => one_shot.is_cancelled(),
100 }
101 }
102
103 pub fn set_detail(&self, detail: impl Into<String>) {
105 let detail = detail.into();
106 match &self.handle {
107 TaskHandle::Progress(progress) => progress.set_detail(detail),
108 TaskHandle::OneShot(one_shot) => one_shot.set_detail(detail),
109 }
110 }
111
112 pub fn report(&self, message: impl Into<String>) -> Result<(), StudyError> {
114 let message = message.into();
115 match &self.handle {
116 TaskHandle::Progress(progress) => progress.report(message),
117 TaskHandle::OneShot(one_shot) => one_shot.report(message),
118 }
119 }
120
121 pub(crate) fn complete(self) -> Result<(), StudyError> {
122 match self.handle {
123 TaskHandle::Progress(progress) => progress.complete(None),
124 TaskHandle::OneShot(one_shot) => {
125 one_shot.complete();
126 Ok(())
127 }
128 }
129 }
130
131 pub(crate) fn fail(self, reason: impl Into<String>) {
132 let reason = reason.into();
133 match self.handle {
134 TaskHandle::Progress(progress) => progress.fail(reason),
135 TaskHandle::OneShot(one_shot) => one_shot.fail(reason),
136 }
137 }
138
139 pub(crate) fn cancel(self, reason: impl Into<String>) {
140 let reason = reason.into();
141 match self.handle {
142 TaskHandle::Progress(progress) => progress.cancel(reason),
143 TaskHandle::OneShot(one_shot) => one_shot.cancel(reason),
144 }
145 }
146
147 fn required_progress(&self) -> Result<&TaskProgressHandle, StudyError> {
148 match &self.handle {
149 TaskHandle::Progress(progress) => Ok(progress),
150 TaskHandle::OneShot(_) => Err(StudyError::TaskModeMismatch {
151 task: self.key().to_string(),
152 requested: "progress",
153 actual: "one-shot",
154 }),
155 }
156 }
157}
158
159impl std::fmt::Debug for TaskContext {
160 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 formatter
162 .debug_struct("TaskContext")
163 .field("key", self.key())
164 .field("category", &self.category())
165 .field("mode", &self.task.mode())
166 .finish_non_exhaustive()
167 }
168}