use std::sync::Arc;
use qubit_function::Callable;
use super::{
TaskResult,
running_task_slot::RunningTaskSlot,
task_runner::TaskRunner,
task_state::TaskState,
};
pub struct TaskSlot<R, E> {
pub(crate) state: Option<Arc<TaskState<R, E>>>,
}
impl<R, E> TaskSlot<R, E> {
#[inline]
fn state(&self) -> &TaskState<R, E> {
self.state
.as_deref()
.expect("task slot state should be present")
}
#[inline]
pub fn accept(&self) {
let _accepted_now = self.state().accept();
}
#[inline]
pub fn cancel_unstarted(mut self) -> bool {
self.state
.take()
.is_some_and(|state| state.try_cancel_pending())
}
pub fn try_start(mut self) -> Result<RunningTaskSlot<R, E>, Self> {
if !self.start() {
return Err(self);
}
let state = self
.state
.take()
.expect("started task slot state should be present");
Ok(RunningTaskSlot::new(state))
}
pub(crate) fn start(&self) -> bool {
self.state().try_start(self.state().is_accepted())
}
#[inline]
pub(crate) fn start_and_complete<F>(self, task: F) -> bool
where
F: FnOnce() -> TaskResult<R, E>,
{
let Ok(running) = self.try_start() else {
return false;
};
running.complete(task())
}
#[inline]
pub fn run<C>(self, task: C) -> bool
where
C: Callable<R, E>,
{
self.start_and_complete(|| TaskRunner::new(task).call())
}
}
impl<R, E> Drop for TaskSlot<R, E> {
#[inline]
fn drop(&mut self) {
if let Some(state) = &self.state {
let _ignored = state.try_drop_unfinished(state.is_accepted());
}
}
}