Skip to main content

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