qubit_executor/task/
task_status.rs1use core::mem::transmute;
12
13use super::{
14 TaskExecutionError,
15 TaskResult,
16};
17
18pub(crate) const TASK_STATUS_COUNT: usize = 7;
20
21#[repr(usize)]
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum TaskStatus {
28 Pending = 0,
30 Running = 1,
32 Succeeded = 2,
34 Failed = 3,
36 Panicked = 4,
38 Cancelled = 5,
40 Dropped = 6,
43}
44
45impl TaskStatus {
46 #[inline]
53 pub const fn is_done(self) -> bool {
54 matches!(
55 self,
56 Self::Succeeded | Self::Failed | Self::Panicked | Self::Cancelled | Self::Dropped
57 )
58 }
59
60 #[inline]
66 pub(crate) const fn as_usize(self) -> usize {
67 self as usize
68 }
69
70 #[inline]
84 pub(crate) const fn from_usize(value: usize) -> Self {
85 if value >= TASK_STATUS_COUNT {
86 panic!("invalid task status code");
87 }
88 unsafe { transmute::<usize, Self>(value) }
89 }
90
91 #[inline]
101 pub(crate) const fn from_result<R, E>(result: &TaskResult<R, E>) -> Self {
102 match result {
103 Ok(_) => Self::Succeeded,
104 Err(TaskExecutionError::Failed(_)) => Self::Failed,
105 Err(TaskExecutionError::Panicked) => Self::Panicked,
106 Err(TaskExecutionError::Cancelled) => Self::Cancelled,
107 Err(TaskExecutionError::Dropped) => Self::Dropped,
108 }
109 }
110}
111
112#[cfg(test)]
113mod compact_encoding_tests {
114 use super::{
115 TASK_STATUS_COUNT,
116 TaskStatus,
117 };
118
119 #[test]
120 fn task_status_as_usize_matches_stable_discriminants() {
121 assert_eq!(TaskStatus::Pending.as_usize(), 0);
122 assert_eq!(TaskStatus::Running.as_usize(), 1);
123 assert_eq!(TaskStatus::Succeeded.as_usize(), 2);
124 assert_eq!(TaskStatus::Failed.as_usize(), 3);
125 assert_eq!(TaskStatus::Panicked.as_usize(), 4);
126 assert_eq!(TaskStatus::Cancelled.as_usize(), 5);
127 assert_eq!(TaskStatus::Dropped.as_usize(), 6);
128 }
129
130 #[test]
131 fn task_status_from_usize_restores_each_variant() {
132 let variants = [
133 TaskStatus::Pending,
134 TaskStatus::Running,
135 TaskStatus::Succeeded,
136 TaskStatus::Failed,
137 TaskStatus::Panicked,
138 TaskStatus::Cancelled,
139 TaskStatus::Dropped,
140 ];
141 for status in variants {
142 assert_eq!(TaskStatus::from_usize(status.as_usize()), status);
143 }
144 }
145
146 #[test]
147 fn task_status_round_trip_all_codes_in_range() {
148 for code in 0..TASK_STATUS_COUNT {
149 let status = TaskStatus::from_usize(code);
150 assert_eq!(status.as_usize(), code);
151 assert_eq!(TaskStatus::from_usize(code), status);
152 }
153 }
154
155 #[test]
156 #[should_panic(expected = "invalid task status code")]
157 fn task_status_from_usize_panics_at_upper_boundary() {
158 TaskStatus::from_usize(TASK_STATUS_COUNT);
159 }
160
161 #[test]
162 #[should_panic(expected = "invalid task status code")]
163 fn task_status_from_usize_panics_on_invalid_large_code() {
164 TaskStatus::from_usize(usize::MAX);
165 }
166
167 #[test]
169 fn task_status_variant_count_matches_constant() {
170 assert_eq!(
171 TaskStatus::Dropped as usize + 1,
172 TASK_STATUS_COUNT,
173 "last discriminant + 1 must equal TASK_STATUS_COUNT"
174 );
175 }
176}