Skip to main content

qubit_function/tasks/
callable.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//! # Callable Types
11//!
12//! Provides fallible, reusable, zero-argument computations.
13//!
14//! A `Callable<R, E>` is equivalent to `FnMut() -> Result<R, E>`, but uses
15//! task-oriented vocabulary. Use it when the operation is a computation or task
16//! whose success value matters. Use `Runnable<E>` when the operation only needs
17//! to report success or failure.
18//!
19//! The trait itself does not require `Send`; concurrent executors should add
20//! `+ Send + 'static` at their API boundary.
21//!
22
23use crate::{
24    tasks::callable_once::{
25        BoxCallableOnce,
26        LocalBoxCallableOnce,
27    },
28    tasks::runnable::BoxRunnable,
29};
30
31mod box_callable;
32pub use box_callable::BoxCallable;
33mod rc_callable;
34pub use rc_callable::RcCallable;
35mod arc_callable;
36pub use arc_callable::ArcCallable;
37
38// ============================================================================
39// Callable Trait
40// ============================================================================
41
42/// A fallible, reusable zero-argument computation.
43///
44/// Conceptually this is the same shape as `FnMut() -> Result<R, E>`: `call` takes
45/// `&mut self` and returns `Result<R, E>`, but the API uses task-oriented naming
46/// and helpers. In this crate it aligns with
47/// [`Supplier`](crate::suppliers::Supplier) of `Result<R, E>`—a fallible
48/// supplier—while emphasizing executable work rather than plain value production.
49///
50/// Choose **`Callable`** when callers need the success value `R`. When only
51/// success or failure matters, use [`Runnable`](crate::tasks::Runnable), whose
52/// success type is `()`.
53///
54/// # Type Parameters
55///
56/// * `R` - The success value returned by the computation.
57/// * `E` - The error value returned when the computation fails.
58///
59/// # Examples
60///
61/// ```rust
62/// use qubit_function::Callable;
63///
64/// let mut task = || Ok::<i32, String>(21 * 2);
65/// assert_eq!(task.call().expect("call should succeed"), 42);
66/// ```
67///
68pub trait Callable<R, E> {
69    /// Executes the computation, borrowing `self` mutably.
70    ///
71    /// # Returns
72    ///
73    /// Returns `Ok(R)` when the computation succeeds, or `Err(E)` when it
74    /// fails. The exact error meaning is defined by the concrete callable.
75    fn call(&mut self) -> Result<R, E>;
76
77    /// Converts this callable into a boxed callable.
78    ///
79    /// # Returns
80    ///
81    /// A `BoxCallable<R, E>` that executes this callable when `call()` is
82    /// invoked.
83    fn into_box(mut self) -> BoxCallable<R, E>
84    where
85        Self: Sized + 'static,
86    {
87        BoxCallable::new(move || self.call())
88    }
89
90    /// Converts this callable into an `Rc` callable.
91    ///
92    /// # Returns
93    ///
94    /// A `RcCallable<R, E>`.
95    fn into_rc(mut self) -> RcCallable<R, E>
96    where
97        Self: Sized + 'static,
98    {
99        RcCallable::new(move || self.call())
100    }
101
102    /// Converts this callable into an `Arc` callable.
103    ///
104    /// # Returns
105    ///
106    /// An `ArcCallable<R, E>`.
107    fn into_arc(mut self) -> ArcCallable<R, E>
108    where
109        Self: Sized + Send + 'static,
110    {
111        ArcCallable::new(move || self.call())
112    }
113
114    /// Converts this callable into a mutable closure.
115    ///
116    /// # Returns
117    ///
118    /// A closure implementing `FnMut() -> Result<R, E>`.
119    fn into_fn(mut self) -> impl FnMut() -> Result<R, E>
120    where
121        Self: Sized + 'static,
122    {
123        move || self.call()
124    }
125
126    /// Converts this callable into a boxed callable without consuming `self`.
127    ///
128    /// The method clones `self` and boxes the clone. Use this for cloneable
129    /// callable values that need to be reused after boxing.
130    ///
131    /// # Returns
132    ///
133    /// A new `BoxCallable<R, E>` built from a clone of this callable.
134    fn to_box(&self) -> BoxCallable<R, E>
135    where
136        Self: Clone + Sized + 'static,
137    {
138        self.clone().into_box()
139    }
140
141    /// Converts this callable into an `Rc` callable without consuming `self`.
142    ///
143    /// The method clones `self` and wraps the clone.
144    ///
145    /// # Returns
146    ///
147    /// A `RcCallable<R, E>`.
148    fn to_rc(&self) -> RcCallable<R, E>
149    where
150        Self: Clone + Sized + 'static,
151    {
152        self.clone().into_rc()
153    }
154
155    /// Converts this callable into an `Arc` callable without consuming `self`.
156    ///
157    /// The method clones `self` and wraps the clone.
158    ///
159    /// # Returns
160    ///
161    /// An `ArcCallable<R, E>`.
162    fn to_arc(&self) -> ArcCallable<R, E>
163    where
164        Self: Clone + Send + Sized + 'static,
165    {
166        self.clone().into_arc()
167    }
168
169    /// Converts this callable into a mutable closure without consuming `self`.
170    ///
171    /// The method clones `self` and returns a closure that executes the clone
172    /// on each call.
173    ///
174    /// # Returns
175    ///
176    /// A closure implementing `FnMut() -> Result<R, E>`.
177    fn to_fn(&self) -> impl FnMut() -> Result<R, E>
178    where
179        Self: Clone + Sized + 'static,
180    {
181        self.clone().into_fn()
182    }
183
184    /// Converts this callable into a one-time callable.
185    ///
186    /// The returned callable consumes itself on each invocation.
187    ///
188    /// # Returns
189    ///
190    /// A `BoxCallableOnce<R, E>`.
191    fn into_once(mut self) -> BoxCallableOnce<R, E>
192    where
193        Self: Sized + Send + 'static,
194    {
195        BoxCallableOnce::new(move || self.call())
196    }
197
198    /// Converts this callable into a local one-time callable.
199    ///
200    /// The returned callable consumes itself on each invocation and may hold
201    /// non-`Send` captures.
202    ///
203    /// # Returns
204    ///
205    /// A `LocalBoxCallableOnce<R, E>`.
206    fn into_local_once(mut self) -> LocalBoxCallableOnce<R, E>
207    where
208        Self: Sized + 'static,
209    {
210        LocalBoxCallableOnce::new(move || self.call())
211    }
212
213    /// Converts this callable into a one-time callable without consuming
214    /// `self`.
215    ///
216    /// The method clones `self` and returns a one-time callable.
217    ///
218    /// # Returns
219    ///
220    /// A `BoxCallableOnce<R, E>`.
221    fn to_once(&self) -> BoxCallableOnce<R, E>
222    where
223        Self: Clone + Send + Sized + 'static,
224    {
225        self.clone().into_once()
226    }
227
228    /// Converts this callable into a local one-time callable without consuming
229    /// `self`.
230    ///
231    /// The method clones `self` and returns a local one-time callable.
232    ///
233    /// # Returns
234    ///
235    /// A `LocalBoxCallableOnce<R, E>`.
236    fn to_local_once(&self) -> LocalBoxCallableOnce<R, E>
237    where
238        Self: Clone + Sized + 'static,
239    {
240        self.clone().into_local_once()
241    }
242
243    /// Converts this callable into a runnable by discarding the success value.
244    ///
245    /// The returned runnable preserves errors and maps any `Ok(R)` to
246    /// `Ok(())`.
247    ///
248    /// # Returns
249    ///
250    /// A `BoxRunnable<E>` that executes this callable and discards its success
251    /// value.
252    fn into_runnable(mut self) -> BoxRunnable<E>
253    where
254        Self: Sized + 'static,
255    {
256        BoxRunnable::new(move || self.call().map(|_| ()))
257    }
258}