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}