qubit_function/tasks/callable_once/box_callable_once.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 `BoxCallableOnce` public type.
12
13use crate::{
14 functions::macros::impl_function_debug_display,
15 macros::{
16 impl_box_once_conversions,
17 impl_common_name_methods,
18 impl_common_new_methods,
19 },
20 suppliers::supplier_once::SupplierOnce,
21 tasks::{
22 callable_once::{
23 CallableOnce,
24 LocalBoxCallableOnce,
25 },
26 runnable_once::{
27 BoxRunnableOnce,
28 LocalBoxRunnableOnce,
29 },
30 },
31};
32
33// ============================================================================
34// BoxCallableOnce
35// ============================================================================
36
37/// Box-based one-time callable.
38///
39/// `BoxCallableOnce<R, E>` stores a
40/// `Box<dyn FnOnce() -> Result<R, E> + Send>` and can be executed only once.
41/// It is the boxed concrete implementation of [`CallableOnce`] for task
42/// objects that may be moved across threads.
43///
44/// # Type Parameters
45///
46/// * `R` - The success value returned by the computation.
47/// * `E` - The error value returned when the computation fails.
48///
49/// # Examples
50///
51/// ```rust
52/// use qubit_function::{BoxCallableOnce, CallableOnce};
53///
54/// let task = BoxCallableOnce::new(|| Ok::<i32, String>(42));
55/// assert_eq!(task.call(), Ok(42));
56/// ```
57///
58pub struct BoxCallableOnce<R, E> {
59 /// The one-time closure executed by this callable.
60 pub(super) function: Box<dyn FnOnce() -> Result<R, E> + Send>,
61 /// The optional name of this callable.
62 pub(super) name: Option<String>,
63}
64
65impl<R, E> BoxCallableOnce<R, E> {
66 impl_common_new_methods!(
67 (FnOnce() -> Result<R, E> + Send + 'static),
68 |function| Box::new(function),
69 "callable"
70 );
71
72 /// Creates a boxed callable from a one-time supplier.
73 ///
74 /// This is an explicit bridge from `SupplierOnce<Result<R, E>>` to
75 /// `CallableOnce<R, E>`.
76 ///
77 /// # Parameters
78 ///
79 /// * `supplier` - The supplier that produces the callable result.
80 ///
81 /// # Returns
82 ///
83 /// A new `BoxCallableOnce<R, E>`.
84 #[inline]
85 pub fn from_supplier<S>(supplier: S) -> Self
86 where
87 S: SupplierOnce<Result<R, E>> + Send + 'static,
88 {
89 Self::new(move || supplier.get())
90 }
91
92 impl_common_name_methods!("callable");
93
94 /// Maps the success value of this callable.
95 ///
96 /// # Parameters
97 ///
98 /// * `mapper` - Function that transforms the success value.
99 ///
100 /// # Returns
101 ///
102 /// A new callable that applies `mapper` when this callable succeeds.
103 #[inline]
104 pub fn map<U, M>(self, mapper: M) -> BoxCallableOnce<U, E>
105 where
106 M: FnOnce(R) -> U + Send + 'static,
107 R: 'static,
108 E: 'static,
109 {
110 let name = self.name;
111 let function = self.function;
112 BoxCallableOnce::new_with_optional_name(move || function().map(mapper), name)
113 }
114
115 /// Maps the error value of this callable.
116 ///
117 /// # Parameters
118 ///
119 /// * `mapper` - Function that transforms the error value.
120 ///
121 /// # Returns
122 ///
123 /// A new callable that applies `mapper` when this callable fails.
124 #[inline]
125 pub fn map_err<E2, M>(self, mapper: M) -> BoxCallableOnce<R, E2>
126 where
127 M: FnOnce(E) -> E2 + Send + 'static,
128 R: 'static,
129 E: 'static,
130 {
131 let name = self.name;
132 let function = self.function;
133 BoxCallableOnce::new_with_optional_name(move || function().map_err(mapper), name)
134 }
135
136 /// Chains another fallible computation after this callable succeeds.
137 ///
138 /// # Parameters
139 ///
140 /// * `next` - Function that receives the success value and returns the next
141 /// result.
142 ///
143 /// # Returns
144 ///
145 /// A new callable that runs `next` only when this callable succeeds.
146 #[inline]
147 pub fn and_then<U, N>(self, next: N) -> BoxCallableOnce<U, E>
148 where
149 N: FnOnce(R) -> Result<U, E> + Send + 'static,
150 R: 'static,
151 E: 'static,
152 {
153 let name = self.name;
154 let function = self.function;
155 BoxCallableOnce::new_with_optional_name(move || function().and_then(next), name)
156 }
157}
158
159impl<R, E> CallableOnce<R, E> for BoxCallableOnce<R, E> {
160 /// Executes the boxed callable.
161 #[inline]
162 fn call(self) -> Result<R, E> {
163 (self.function)()
164 }
165
166 impl_box_once_conversions!(BoxCallableOnce<R, E>, CallableOnce, FnOnce() -> Result<R, E>);
167
168 /// Converts this boxed callable into a boxed runnable while preserving its
169 /// name.
170 #[inline]
171 fn into_runnable(self) -> BoxRunnableOnce<E>
172 where
173 Self: Sized + 'static,
174 {
175 let name = self.name;
176 let function = self.function;
177 BoxRunnableOnce::new_with_optional_name(move || function().map(|_| ()), name)
178 }
179
180 /// Converts this boxed callable into a local boxed callable while
181 /// preserving its name.
182 #[inline]
183 fn into_local_box(self) -> LocalBoxCallableOnce<R, E>
184 where
185 Self: Sized + 'static,
186 {
187 let name = self.name;
188 let function = self.function;
189 LocalBoxCallableOnce::new_with_optional_name(function, name)
190 }
191
192 /// Converts this boxed callable into a local boxed runnable while
193 /// preserving its name.
194 #[inline]
195 fn into_local_runnable(self) -> LocalBoxRunnableOnce<E>
196 where
197 Self: Sized + 'static,
198 {
199 let name = self.name;
200 let function = self.function;
201 LocalBoxRunnableOnce::new_with_optional_name(move || function().map(|_| ()), name)
202 }
203}
204
205impl<R, E> SupplierOnce<Result<R, E>> for BoxCallableOnce<R, E> {
206 /// Executes the boxed callable as a one-time supplier of `Result<R, E>`.
207 #[inline]
208 fn get(self) -> Result<R, E> {
209 self.call()
210 }
211}
212
213impl<F, R, E> CallableOnce<R, E> for F
214where
215 F: FnOnce() -> Result<R, E>,
216{
217 /// Executes the closure as a one-time callable.
218 #[inline]
219 fn call(self) -> Result<R, E> {
220 self()
221 }
222}
223
224impl_function_debug_display!(BoxCallableOnce<R, E>);