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}