Skip to main content

qubit_executor/executor/
direct_executor.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::sync::Arc;
11
12use qubit_function::Callable;
13
14use crate::{
15    TrackedTask,
16    hook::TaskHook,
17    service::SubmissionError,
18    task::spi::TaskEndpointPair,
19};
20
21use super::Executor;
22
23/// Executes tasks immediately on the caller thread.
24///
25/// This executor is useful for deterministic tests and simple composition
26/// where task execution should happen in the same call stack.
27#[derive(Clone)]
28pub struct DirectExecutor {
29    /// Hook notified about accepted task lifecycle events.
30    hook: Option<Arc<dyn TaskHook>>,
31}
32
33impl DirectExecutor {
34    /// Creates a direct executor without lifecycle hooks.
35    ///
36    /// # Returns
37    ///
38    /// A direct executor.
39    #[inline]
40    pub fn new() -> Self {
41        Self::default()
42    }
43
44    /// Returns a copy of this executor using the supplied task hook.
45    ///
46    /// # Parameters
47    ///
48    /// * `hook` - Hook notified about accepted task lifecycle events.
49    ///
50    /// # Returns
51    ///
52    /// This executor configured with `hook`.
53    #[inline]
54    pub fn with_hook(mut self, hook: Arc<dyn TaskHook>) -> Self {
55        self.hook = Some(hook);
56        self
57    }
58}
59
60impl Default for DirectExecutor {
61    /// Creates a direct executor without lifecycle hooks.
62    #[inline]
63    fn default() -> Self {
64        Self { hook: None }
65    }
66}
67
68impl Executor for DirectExecutor {
69    /// Executes the callable inline and returns an already completed handle.
70    ///
71    /// # Parameters
72    ///
73    /// * `task` - Callable to run on the caller thread.
74    ///
75    /// # Returns
76    ///
77    /// An already completed tracked task carrying the callable result.
78    #[inline]
79    fn call<C, R, E>(&self, task: C) -> Result<TrackedTask<R, E>, SubmissionError>
80    where
81        C: Callable<R, E> + Send + 'static,
82        R: Send + 'static,
83        E: Send + 'static,
84    {
85        let (handle, slot) =
86            TaskEndpointPair::with_optional_hook(self.hook.clone()).into_tracked_parts();
87        handle.accept();
88        slot.run(task);
89        Ok(handle)
90    }
91}