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