Skip to main content

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>);