use core::mem::transmute;
use super::{
TaskExecutionError,
TaskResult,
};
pub(crate) const TASK_STATUS_COUNT: usize = 7;
#[repr(usize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TaskStatus {
Pending = 0,
Running = 1,
Succeeded = 2,
Failed = 3,
Panicked = 4,
Cancelled = 5,
Dropped = 6,
}
impl TaskStatus {
#[inline]
pub const fn is_done(self) -> bool {
matches!(
self,
Self::Succeeded | Self::Failed | Self::Panicked | Self::Cancelled | Self::Dropped
)
}
#[inline]
pub(crate) const fn as_usize(self) -> usize {
self as usize
}
#[inline]
pub(crate) const fn from_usize(value: usize) -> Self {
if value >= TASK_STATUS_COUNT {
panic!("invalid task status code");
}
unsafe { transmute::<usize, Self>(value) }
}
#[inline]
pub(crate) const fn from_result<R, E>(result: &TaskResult<R, E>) -> Self {
match result {
Ok(_) => Self::Succeeded,
Err(TaskExecutionError::Failed(_)) => Self::Failed,
Err(TaskExecutionError::Panicked) => Self::Panicked,
Err(TaskExecutionError::Cancelled) => Self::Cancelled,
Err(TaskExecutionError::Dropped) => Self::Dropped,
}
}
}
#[cfg(test)]
mod compact_encoding_tests {
use super::{
TASK_STATUS_COUNT,
TaskStatus,
};
#[test]
fn task_status_as_usize_matches_stable_discriminants() {
assert_eq!(TaskStatus::Pending.as_usize(), 0);
assert_eq!(TaskStatus::Running.as_usize(), 1);
assert_eq!(TaskStatus::Succeeded.as_usize(), 2);
assert_eq!(TaskStatus::Failed.as_usize(), 3);
assert_eq!(TaskStatus::Panicked.as_usize(), 4);
assert_eq!(TaskStatus::Cancelled.as_usize(), 5);
assert_eq!(TaskStatus::Dropped.as_usize(), 6);
}
#[test]
fn task_status_from_usize_restores_each_variant() {
let variants = [
TaskStatus::Pending,
TaskStatus::Running,
TaskStatus::Succeeded,
TaskStatus::Failed,
TaskStatus::Panicked,
TaskStatus::Cancelled,
TaskStatus::Dropped,
];
for status in variants {
assert_eq!(TaskStatus::from_usize(status.as_usize()), status);
}
}
#[test]
fn task_status_round_trip_all_codes_in_range() {
for code in 0..TASK_STATUS_COUNT {
let status = TaskStatus::from_usize(code);
assert_eq!(status.as_usize(), code);
assert_eq!(TaskStatus::from_usize(code), status);
}
}
#[test]
#[should_panic(expected = "invalid task status code")]
fn task_status_from_usize_panics_at_upper_boundary() {
TaskStatus::from_usize(TASK_STATUS_COUNT);
}
#[test]
#[should_panic(expected = "invalid task status code")]
fn task_status_from_usize_panics_on_invalid_large_code() {
TaskStatus::from_usize(usize::MAX);
}
#[test]
fn task_status_variant_count_matches_constant() {
assert_eq!(
TaskStatus::Dropped as usize + 1,
TASK_STATUS_COUNT,
"last discriminant + 1 must equal TASK_STATUS_COUNT"
);
}
}