qubit_function/tasks/callable_once/box_callable_once.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! Defines the `BoxCallableOnce` public type.
10
11#![allow(unused_imports)]
12
13use super::*;
14
15// ============================================================================
16// BoxCallableOnce
17// ============================================================================
18
19/// Box-based one-time callable.
20///
21/// `BoxCallableOnce<R, E>` stores a `Box<dyn FnOnce() -> Result<R, E>>` and can
22/// be executed only once. It is the boxed concrete implementation of
23/// [`CallableOnce`].
24///
25/// # Type Parameters
26///
27/// * `R` - The success value returned by the computation.
28/// * `E` - The error value returned when the computation fails.
29///
30/// # Examples
31///
32/// ```rust
33/// use qubit_function::{BoxCallableOnce, CallableOnce};
34///
35/// let task = BoxCallableOnce::new(|| Ok::<i32, String>(42));
36/// assert_eq!(task.call(), Ok(42));
37/// ```
38///
39/// # Author
40///
41/// Haixing Hu
42pub struct BoxCallableOnce<R, E> {
43 /// The one-time closure executed by this callable.
44 pub(super) function: Box<dyn FnOnce() -> Result<R, E>>,
45 /// The optional name of this callable.
46 pub(super) name: Option<String>,
47}
48
49impl<R, E> BoxCallableOnce<R, E> {
50 impl_common_new_methods!(
51 (FnOnce() -> Result<R, E> + 'static),
52 |function| Box::new(function),
53 "callable"
54 );
55
56 /// Creates a boxed callable from a one-time supplier.
57 ///
58 /// This is an explicit bridge from `SupplierOnce<Result<R, E>>` to
59 /// `CallableOnce<R, E>`.
60 ///
61 /// # Parameters
62 ///
63 /// * `supplier` - The supplier that produces the callable result.
64 ///
65 /// # Returns
66 ///
67 /// A new `BoxCallableOnce<R, E>`.
68 #[inline]
69 pub fn from_supplier<S>(supplier: S) -> Self
70 where
71 S: SupplierOnce<Result<R, E>> + 'static,
72 {
73 Self::new(move || supplier.get())
74 }
75
76 impl_common_name_methods!("callable");
77
78 /// Maps the success value of this callable.
79 ///
80 /// # Parameters
81 ///
82 /// * `mapper` - Function that transforms the success value.
83 ///
84 /// # Returns
85 ///
86 /// A new callable that applies `mapper` when this callable succeeds.
87 #[inline]
88 pub fn map<U, M>(self, mapper: M) -> BoxCallableOnce<U, E>
89 where
90 M: FnOnce(R) -> U + 'static,
91 R: 'static,
92 E: 'static,
93 {
94 let name = self.name;
95 let function = self.function;
96 BoxCallableOnce::new_with_optional_name(move || function().map(mapper), name)
97 }
98
99 /// Maps the error value of this callable.
100 ///
101 /// # Parameters
102 ///
103 /// * `mapper` - Function that transforms the error value.
104 ///
105 /// # Returns
106 ///
107 /// A new callable that applies `mapper` when this callable fails.
108 #[inline]
109 pub fn map_err<E2, M>(self, mapper: M) -> BoxCallableOnce<R, E2>
110 where
111 M: FnOnce(E) -> E2 + 'static,
112 R: 'static,
113 E: 'static,
114 {
115 let name = self.name;
116 let function = self.function;
117 BoxCallableOnce::new_with_optional_name(move || function().map_err(mapper), name)
118 }
119
120 /// Chains another fallible computation after this callable succeeds.
121 ///
122 /// # Parameters
123 ///
124 /// * `next` - Function that receives the success value and returns the next
125 /// result.
126 ///
127 /// # Returns
128 ///
129 /// A new callable that runs `next` only when this callable succeeds.
130 #[inline]
131 pub fn and_then<U, N>(self, next: N) -> BoxCallableOnce<U, E>
132 where
133 N: FnOnce(R) -> Result<U, E> + 'static,
134 R: 'static,
135 E: 'static,
136 {
137 let name = self.name;
138 let function = self.function;
139 BoxCallableOnce::new_with_optional_name(move || function().and_then(next), name)
140 }
141}
142
143impl<R, E> CallableOnce<R, E> for BoxCallableOnce<R, E> {
144 /// Executes the boxed callable.
145 #[inline]
146 fn call(self) -> Result<R, E> {
147 (self.function)()
148 }
149
150 impl_box_once_conversions!(BoxCallableOnce<R, E>, CallableOnce, FnOnce() -> Result<R, E>);
151
152 /// Converts this boxed callable into a boxed runnable while preserving its
153 /// name.
154 #[inline]
155 fn into_runnable(self) -> BoxRunnableOnce<E>
156 where
157 Self: Sized + 'static,
158 {
159 let name = self.name;
160 let function = self.function;
161 BoxRunnableOnce::new_with_optional_name(move || function().map(|_| ()), name)
162 }
163}
164
165impl<R, E> SupplierOnce<Result<R, E>> for BoxCallableOnce<R, E> {
166 /// Executes the boxed callable as a one-time supplier of `Result<R, E>`.
167 #[inline]
168 fn get(self) -> Result<R, E> {
169 self.call()
170 }
171}
172
173impl_closure_once_trait!(
174 CallableOnce<R, E>,
175 call,
176 BoxCallableOnce,
177 FnOnce() -> Result<R, E>
178);
179
180impl_function_debug_display!(BoxCallableOnce<R, E>);