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