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}