use core::marker::PhantomData;
use super::id_and_context::{TaskContext, TaskId};
use super::traits::Task;
pub struct BaseTask<F, R> {
pub(super) func: F,
pub(super) context: TaskContext,
pub(super) _phantom: PhantomData<R>,
}
impl<F, R> BaseTask<F, R>
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
pub fn new(func: F, context: TaskContext) -> Self {
Self {
func,
context,
_phantom: PhantomData,
}
}
}
pub struct Closure<F, R> {
base: BaseTask<F, R>,
}
impl<F, R> Closure<F, R>
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
pub fn new(func: F, context: TaskContext) -> Self {
Self {
base: BaseTask::new(func, context),
}
}
pub fn then<G, S>(self, continuation: G) -> Chained<Self, G>
where
G: FnOnce(R) -> S + Send + 'static,
S: Send + 'static,
{
Chained::new(self, continuation)
}
pub fn map<G, S>(self, mapper: G) -> Mapped<Self, G>
where
G: FnOnce(R) -> S + Send + 'static,
S: Send + 'static,
{
Mapped::new(self, mapper)
}
}
impl<F, R> Task for Closure<F, R>
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
type Output = R;
fn execute(self) -> Self::Output {
(self.base.func)()
}
fn context(&self) -> &TaskContext {
&self.base.context
}
}
pub struct Chained<T, F> {
task: T,
continuation: F,
context: TaskContext,
}
impl<T, F> Chained<T, F> {
pub fn new(task: T, continuation: F) -> Self
where
T: Task,
{
let _context = task.context().clone();
Self {
task,
continuation,
context: _context,
}
}
}
impl<T, F, U> Task for Chained<T, F>
where
T: Task,
F: FnOnce(T::Output) -> U + Send + 'static,
U: Send + 'static,
{
type Output = U;
fn execute(self) -> Self::Output {
let result = self.task.execute();
(self.continuation)(result)
}
fn context(&self) -> &TaskContext {
&self.context
}
fn is_stealable(&self) -> bool {
self.task.is_stealable()
}
fn estimated_cost(&self) -> u32 {
self.task.estimated_cost() + 1
}
}
pub struct Mapped<T, F> {
task: T,
mapper: F,
context: TaskContext,
}
impl<T, F> Mapped<T, F> {
pub fn new(task: T, mapper: F) -> Self
where
T: Task,
{
let _context = task.context().clone();
Self {
task,
mapper,
context: _context,
}
}
}
impl<T, F, U> Task for Mapped<T, F>
where
T: Task,
F: FnOnce(T::Output) -> U + Send + 'static,
U: Send + 'static,
{
type Output = U;
fn execute(self) -> Self::Output {
let result = self.task.execute();
(self.mapper)(result)
}
fn context(&self) -> &TaskContext {
&self.context
}
fn is_stealable(&self) -> bool {
self.task.is_stealable()
}
fn estimated_cost(&self) -> u32 {
self.task.estimated_cost()
}
}
#[allow(clippy::module_name_repetitions)]
pub struct TaskBuilder {
context: TaskContext,
}
impl TaskBuilder {
#[must_use]
pub fn new() -> Self {
Self {
context: TaskContext::new(TaskId::new(0)),
}
}
#[must_use]
pub fn priority(mut self, priority: crate::Priority) -> Self {
self.context.priority = priority;
self
}
#[must_use]
pub fn name(mut self, name: &'static str) -> Self {
self.context.name = Some(name);
self
}
#[must_use]
pub fn with_id(mut self, id: TaskId) -> Self {
self.context.id = id;
self
}
pub fn build<F, R>(self, func: F) -> Closure<F, R>
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
Closure::new(func, self.context)
}
}
impl Default for TaskBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct Parameterized<F, P> {
function: Option<F>,
parameters: Option<P>,
context: TaskContext,
}
impl<F, P> Parameterized<F, P> {
pub fn new(func: F, params: P, context: TaskContext) -> Self {
Self {
function: Some(func),
parameters: Some(params),
context,
}
}
}
impl<F, P, R> Task for Parameterized<F, P>
where
F: FnOnce(P) -> R + Send + 'static,
P: Send + 'static,
R: Send + 'static,
{
type Output = R;
fn execute(mut self) -> Self::Output {
let func = self.function.take().expect("Task already executed");
let params = self.parameters.take().expect("Parameters already used");
func(params)
}
fn context(&self) -> &TaskContext {
&self.context
}
}
pub struct Group {
tasks: Vec<Box<dyn FnOnce() + Send + 'static>>,
context: TaskContext,
}
impl Group {
#[must_use]
pub fn new(id: TaskId) -> Self {
Self {
tasks: Vec::new(),
context: TaskContext::new(id),
}
}
pub fn add_task<F>(&mut self, task_fn: F)
where
F: FnOnce() + Send + 'static,
{
self.tasks.push(Box::new(move || {
task_fn();
}));
}
#[must_use]
pub fn len(&self) -> usize {
self.tasks.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.tasks.is_empty()
}
}
impl Task for Group {
type Output = ();
fn execute(self) -> Self::Output {
for task_fn in self.tasks {
task_fn();
}
}
fn context(&self) -> &TaskContext {
&self.context
}
#[allow(clippy::cast_possible_truncation)]
fn estimated_cost(&self) -> u32 {
self.tasks.len() as u32
}
}
pub struct Spawner<F> {
spawner: Option<F>,
context: TaskContext,
}
impl<F> Spawner<F> {
pub fn new(spawner: F, context: TaskContext) -> Self {
Self {
spawner: Some(spawner),
context,
}
}
}
impl<F> Task for Spawner<F>
where
F: FnOnce() + Send + 'static,
{
type Output = ();
fn execute(mut self) -> Self::Output {
if let Some(spawner) = self.spawner.take() {
spawner();
}
}
fn context(&self) -> &TaskContext {
&self.context
}
}