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}