use std::sync::Arc;
use super::TaskExecutionError;
use super::TaskResult;
use super::task_handle_inner::TaskHandleInner;
use super::task_handle_state::TaskHandleState;
pub struct TaskCompletion<R, E> {
pub(crate) inner: Arc<TaskHandleInner<R, E>>,
}
impl<R, E> Clone for TaskCompletion<R, E> {
#[inline]
fn clone(&self) -> Self {
Self {
inner: Arc::clone(&self.inner),
}
}
}
impl<R, E> TaskCompletion<R, E> {
pub fn start(&self) -> bool {
self.inner.state.write(|state| {
if state.completed {
false
} else {
state.started = true;
true
}
})
}
#[inline]
pub fn complete(&self, result: TaskResult<R, E>) {
self.finish(result, |_| true);
}
#[inline]
pub fn start_and_complete<F>(&self, task: F) -> bool
where
F: FnOnce() -> TaskResult<R, E>,
{
if !self.start() {
return false;
}
self.complete(task());
true
}
#[inline]
pub fn cancel(&self) -> bool {
self.finish(Err(TaskExecutionError::Cancelled), |state| !state.started)
}
fn finish<F>(&self, result: TaskResult<R, E>, can_finish: F) -> bool
where
F: FnOnce(&TaskHandleState<R, E>) -> bool,
{
let (published, waker) = self.inner.state.write(|state| {
if state.completed || !can_finish(state) {
return (false, None);
}
state.result = Some(result);
state.completed = true;
self.inner.done.store(true);
(true, state.waker.take())
});
if !published {
return false;
}
self.inner.notify_completion();
if let Some(waker) = waker {
waker.wake();
}
true
}
}