Skip to main content

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