Skip to main content

qubit_function/tasks/runnable_with/
box_runnable_with.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! Defines the `BoxRunnableWith` public type.
10
11#![allow(unused_imports)]
12
13use super::*;
14
15/// Box-based runnable with mutable input.
16///
17/// `BoxRunnableWith<T, E>` stores a
18/// `Box<dyn FnMut(&mut T) -> Result<(), E>>` and can be called repeatedly.
19///
20/// # Author
21///
22/// Haixing Hu
23pub struct BoxRunnableWith<T, E> {
24    /// The stateful closure executed by this runnable.
25    pub(super) function: Box<dyn FnMut(&mut T) -> Result<(), E>>,
26    /// The optional name of this runnable.
27    pub(super) name: Option<String>,
28}
29
30impl<T, E> BoxRunnableWith<T, E> {
31    impl_common_new_methods!(
32        (FnMut(&mut T) -> Result<(), E> + 'static),
33        |function| Box::new(function),
34        "runnable-with"
35    );
36
37    impl_common_name_methods!("runnable-with");
38
39    /// Chains another runnable after this runnable succeeds.
40    ///
41    /// # Parameters
42    ///
43    /// * `next` - The runnable to execute after this runnable succeeds.
44    ///
45    /// # Returns
46    ///
47    /// A runnable executing both actions in sequence.
48    #[inline]
49    pub fn and_then<N>(self, next: N) -> BoxRunnableWith<T, E>
50    where
51        N: RunnableWith<T, E> + 'static,
52        T: 'static,
53        E: 'static,
54    {
55        let name = self.name;
56        let mut function = self.function;
57        let mut next = next;
58        BoxRunnableWith::new_with_optional_name(
59            move |input| {
60                function(input)?;
61                next.run_with(input)
62            },
63            name,
64        )
65    }
66
67    /// Runs this runnable before a callable.
68    ///
69    /// The callable is not executed if this runnable returns `Err`.
70    ///
71    /// # Parameters
72    ///
73    /// * `callable` - The callable to execute after this runnable succeeds.
74    ///
75    /// # Returns
76    ///
77    /// A callable producing the second computation's result.
78    #[inline]
79    pub fn then_callable_with<R, C>(self, callable: C) -> BoxCallableWith<T, R, E>
80    where
81        C: crate::tasks::callable_with::CallableWith<T, R, E> + 'static,
82        T: 'static,
83        R: 'static,
84        E: 'static,
85    {
86        let name = self.name;
87        let mut function = self.function;
88        let mut callable = callable;
89        BoxCallableWith::new_with_optional_name(
90            move |input| {
91                function(input)?;
92                callable.call_with(input)
93            },
94            name,
95        )
96    }
97}
98
99impl<T, E> RunnableWith<T, E> for BoxRunnableWith<T, E> {
100    /// Executes the boxed runnable with mutable input.
101    #[inline]
102    fn run_with(&mut self, input: &mut T) -> Result<(), E> {
103        (self.function)(input)
104    }
105
106    impl_box_conversions!(
107        BoxRunnableWith<T, E>,
108        RcRunnableWith,
109        FnMut(&mut T) -> Result<(), E>
110    );
111
112    /// Converts this boxed runnable into a boxed callable while preserving its
113    /// name.
114    #[inline]
115    fn into_callable_with(self) -> BoxCallableWith<T, (), E>
116    where
117        Self: Sized + 'static,
118    {
119        let name = self.name;
120        let mut function = self.function;
121        BoxCallableWith::new_with_optional_name(
122            move |input| {
123                function(input)?;
124                Ok(())
125            },
126            name,
127        )
128    }
129}