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