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