use std::cell::RefCell;
use std::fmt::Debug;
pub type TaskId = usize;
pub trait LocalContext<I>: Debug {
fn should_cancel_tasks(&self) -> bool;
fn submit_task(&self, input: I) -> TaskId;
#[cfg(test)]
fn thread_index(&self) -> usize;
}
#[derive(Debug)]
pub struct Context<'a, I> {
meta: TaskMeta,
local: Option<&'a dyn LocalContext<I>>,
subtask_ids: RefCell<Option<Vec<TaskId>>>,
}
impl<'a, I> Context<'a, I> {
pub fn empty() -> Self {
Self {
meta: TaskMeta::default(),
local: None,
subtask_ids: RefCell::new(None),
}
}
pub fn new(meta: TaskMeta, local: Option<&'a dyn LocalContext<I>>) -> Self {
Self {
meta,
local,
subtask_ids: RefCell::new(None),
}
}
pub fn task_id(&self) -> TaskId {
self.meta.id()
}
pub fn attempt(&self) -> u8 {
self.meta.attempt()
}
pub fn is_cancelled(&self) -> bool {
self.local
.as_ref()
.map(|local| local.should_cancel_tasks())
.unwrap_or(false)
}
pub fn submit(&self, input: I) -> Result<(), I> {
if let Some(local) = self.local.as_ref() {
let task_id = local.submit_task(input);
self.subtask_ids
.borrow_mut()
.get_or_insert_default()
.push(task_id);
Ok(())
} else {
Err(input)
}
}
#[cfg(test)]
pub fn thread_index(&self) -> Option<usize> {
self.local.map(|local| local.thread_index())
}
pub(crate) fn into_parts(self) -> (TaskMeta, Option<Vec<TaskId>>) {
(self.meta, self.subtask_ids.into_inner())
}
}
#[derive(Clone, Debug, Default)]
pub struct TaskMeta {
id: TaskId,
#[cfg(feature = "local-batch")]
weight: u32,
#[cfg(feature = "retry")]
attempt: u8,
}
impl TaskMeta {
pub fn new(id: TaskId) -> Self {
TaskMeta {
id,
..Default::default()
}
}
#[cfg(feature = "local-batch")]
pub fn with_weight(task_id: TaskId, weight: u32) -> Self {
TaskMeta {
id: task_id,
weight,
..Default::default()
}
}
pub fn id(&self) -> TaskId {
self.id
}
pub fn attempt(&self) -> u8 {
#[cfg(feature = "retry")]
return self.attempt;
#[cfg(not(feature = "retry"))]
return 0;
}
#[cfg(feature = "retry")]
pub(crate) fn inc_attempt(&mut self) {
self.attempt += 1;
}
pub fn weight(&self) -> u32 {
#[cfg(feature = "local-batch")]
return self.weight;
#[cfg(not(feature = "local-batch"))]
return 0;
}
}
impl From<TaskId> for TaskMeta {
fn from(value: TaskId) -> Self {
TaskMeta::new(value)
}
}
#[cfg(all(test, feature = "retry"))]
impl TaskMeta {
pub fn with_attempt(task_id: TaskId, attempt: u8) -> Self {
Self {
id: task_id,
attempt,
..Default::default()
}
}
}