qubit_function/tasks/runnable_once/local_box_runnable_once.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 ******************************************************************************/
10// qubit-style: allow explicit-imports
11//! Defines the `LocalBoxRunnableOnce` public type.
12
13use crate::{
14 macros::{
15 impl_common_name_methods,
16 impl_common_new_methods,
17 },
18 suppliers::{
19 macros::impl_supplier_debug_display,
20 supplier_once::SupplierOnce,
21 },
22 tasks::{
23 callable_once::{
24 CallableOnce,
25 LocalBoxCallableOnce,
26 },
27 runnable_once::RunnableOnce,
28 },
29};
30
31// ============================================================================
32// LocalBoxRunnableOnce
33// ============================================================================
34
35/// Local box-based one-time runnable.
36///
37/// `LocalBoxRunnableOnce<E>` stores a `Box<dyn FnOnce() -> Result<(), E>>` and
38/// can be executed only once on the local thread. Use
39/// [`BoxRunnableOnce`](crate::tasks::runnable_once::BoxRunnableOnce) when the
40/// runnable must be movable across threads.
41///
42/// # Type Parameters
43///
44/// * `E` - The error value returned when the action fails.
45///
46pub struct LocalBoxRunnableOnce<E> {
47 /// The one-time closure executed by this runnable.
48 pub(super) function: Box<dyn FnOnce() -> Result<(), E>>,
49 /// The optional name of this runnable.
50 pub(super) name: Option<String>,
51}
52
53impl<E> LocalBoxRunnableOnce<E> {
54 impl_common_new_methods!(
55 (FnOnce() -> Result<(), E> + 'static),
56 |function| Box::new(function),
57 "local runnable"
58 );
59
60 /// Creates a local boxed runnable from a one-time supplier.
61 ///
62 /// This is an explicit bridge from `SupplierOnce<Result<(), E>>` to
63 /// `RunnableOnce<E>` without requiring `Send`.
64 ///
65 /// # Parameters
66 ///
67 /// * `supplier` - The supplier that produces the runnable result.
68 ///
69 /// # Returns
70 ///
71 /// A new `LocalBoxRunnableOnce<E>`.
72 #[inline]
73 pub fn from_supplier<S>(supplier: S) -> Self
74 where
75 S: SupplierOnce<Result<(), E>> + 'static,
76 {
77 Self::new(move || supplier.get())
78 }
79
80 impl_common_name_methods!("local runnable");
81
82 /// Chains another runnable after this runnable succeeds.
83 ///
84 /// The second runnable is not executed if this runnable returns `Err`.
85 ///
86 /// # Parameters
87 ///
88 /// * `next` - The runnable to execute after this runnable succeeds.
89 ///
90 /// # Returns
91 ///
92 /// A new local runnable executing both actions in sequence.
93 #[inline]
94 pub fn and_then<N>(self, next: N) -> LocalBoxRunnableOnce<E>
95 where
96 N: RunnableOnce<E> + 'static,
97 E: 'static,
98 {
99 let name = self.name;
100 let function = self.function;
101 LocalBoxRunnableOnce::new_with_optional_name(
102 move || {
103 function()?;
104 next.run()
105 },
106 name,
107 )
108 }
109
110 /// Runs this runnable before a local callable.
111 ///
112 /// The callable is not executed if this runnable returns `Err`.
113 ///
114 /// # Parameters
115 ///
116 /// * `callable` - The callable to execute after this runnable succeeds.
117 ///
118 /// # Returns
119 ///
120 /// A local callable producing the second computation's result.
121 #[inline]
122 pub fn then_callable<R, C>(self, callable: C) -> LocalBoxCallableOnce<R, E>
123 where
124 C: CallableOnce<R, E> + 'static,
125 R: 'static,
126 E: 'static,
127 {
128 let name = self.name;
129 let function = self.function;
130 LocalBoxCallableOnce::new_with_optional_name(
131 move || {
132 function()?;
133 callable.call()
134 },
135 name,
136 )
137 }
138}
139
140impl<E> RunnableOnce<E> for LocalBoxRunnableOnce<E> {
141 /// Executes the local boxed runnable.
142 #[inline]
143 fn run(self) -> Result<(), E> {
144 (self.function)()
145 }
146
147 /// Converts this local boxed runnable into itself.
148 #[inline]
149 fn into_local_box(self) -> LocalBoxRunnableOnce<E>
150 where
151 Self: Sized + 'static,
152 {
153 self
154 }
155
156 /// Extracts the underlying local one-time closure.
157 #[inline]
158 fn into_fn(self) -> impl FnOnce() -> Result<(), E>
159 where
160 Self: Sized + 'static,
161 {
162 self.function
163 }
164
165 /// Converts this local boxed runnable into a local boxed callable while
166 /// preserving its name.
167 #[inline]
168 fn into_local_callable(self) -> LocalBoxCallableOnce<(), E>
169 where
170 Self: Sized + 'static,
171 {
172 let name = self.name;
173 let function = self.function;
174 LocalBoxCallableOnce::new_with_optional_name(function, name)
175 }
176}
177
178impl<E> SupplierOnce<Result<(), E>> for LocalBoxRunnableOnce<E> {
179 /// Executes the local boxed runnable as a one-time supplier of
180 /// `Result<(), E>`.
181 #[inline]
182 fn get(self) -> Result<(), E> {
183 self.run()
184 }
185}
186
187impl_supplier_debug_display!(LocalBoxRunnableOnce<E>);