Skip to main content

qubit_executor/task/
task_runner.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10use std::panic::{
11    AssertUnwindSafe,
12    catch_unwind,
13};
14
15use qubit_function::Callable;
16
17use super::{
18    TaskCompletion,
19    TaskExecutionError,
20    TaskResult,
21};
22
23/// Runner that executes a callable task with standard task-handle semantics.
24///
25/// `TaskRunner` owns the accepted callable, converts task failures and panics
26/// into [`TaskExecutionError`], and can publish the final result through a
27/// [`TaskCompletion`] endpoint.
28pub struct TaskRunner<C> {
29    /// Callable task owned by this runner.
30    task: C,
31}
32
33impl<C> TaskRunner<C> {
34    /// Creates a runner for the supplied callable task.
35    ///
36    /// # Parameters
37    ///
38    /// * `task` - Callable task to execute later.
39    ///
40    /// # Returns
41    ///
42    /// A runner that owns the callable task.
43    #[inline]
44    pub const fn new(task: C) -> Self {
45        Self { task }
46    }
47
48    /// Runs the callable and converts task failure and panic into a handle result.
49    ///
50    /// # Returns
51    ///
52    /// `Ok(R)` if the task succeeds. If the task returns `Err(E)` or panics, the
53    /// corresponding [`TaskExecutionError`] is returned.
54    pub fn call<R, E>(self) -> TaskResult<R, E>
55    where
56        C: Callable<R, E>,
57    {
58        let mut task = self.task;
59        match catch_unwind(AssertUnwindSafe(|| task.call())) {
60            Ok(Ok(value)) => Ok(value),
61            Ok(Err(err)) => Err(TaskExecutionError::Failed(err)),
62            Err(_) => Err(TaskExecutionError::Panicked),
63        }
64    }
65
66    /// Runs this task through a task completion endpoint.
67    ///
68    /// # Parameters
69    ///
70    /// * `completion` - Completion endpoint that publishes the final result.
71    ///
72    /// # Returns
73    ///
74    /// `true` if the task started and its result was published, or `false` if
75    /// the completion endpoint had already been completed by cancellation.
76    #[inline]
77    pub fn run<R, E>(self, completion: TaskCompletion<R, E>) -> bool
78    where
79        C: Callable<R, E>,
80    {
81        completion.start_and_complete(|| self.call())
82    }
83}