use std::any::Any;
use std::fmt;
use std::time::Instant;
pub type TaskId = u64;
#[derive(Debug)]
pub enum TaskOutcome<T> {
Completed(T),
Panicked(PanicInfo),
}
impl<T> TaskOutcome<T> {
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> TaskOutcome<U> {
match self {
TaskOutcome::Completed(value) => TaskOutcome::Completed(f(value)),
TaskOutcome::Panicked(info) => TaskOutcome::Panicked(info),
}
}
}
#[derive(Debug)]
pub struct TaskResult<T> {
pub task_id: TaskId,
pub started_at: Option<Instant>,
pub finished_at: Instant,
pub outcome: TaskOutcome<T>,
}
impl<T> TaskResult<T> {
pub fn duration(&self) -> Option<std::time::Duration> {
self.started_at
.map(|start| self.finished_at.saturating_duration_since(start))
}
}
#[derive(Debug)]
pub struct TimedOutTask {
pub task_id: TaskId,
pub started_at: Option<Instant>,
}
impl TimedOutTask {
pub fn elapsed(&self) -> Option<std::time::Duration> {
self.started_at
.map(|start| Instant::now().saturating_duration_since(start))
}
}
#[derive(Clone)]
pub struct PanicInfo {
message: String,
}
impl PanicInfo {
pub fn from_payload(payload: Box<dyn Any + Send + 'static>) -> Self {
if let Some(s) = payload.downcast_ref::<&str>() {
Self { message: s.to_string() }
} else if let Some(s) = payload.downcast_ref::<String>() {
Self { message: s.clone() }
} else {
Self { message: "<non-string panic payload>".to_string() }
}
}
pub fn message(&self) -> &str {
&self.message
}
}
impl fmt::Debug for PanicInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PanicInfo").field("message", &self.message).finish()
}
}
impl fmt::Display for PanicInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message)
}
}
impl std::error::Error for PanicInfo {}