Skip to main content

qubit_function/tasks/
callable.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # Callable Types
10//!
11//! Provides fallible, reusable, zero-argument computations.
12//!
13//! A `Callable<R, E>` is equivalent to `FnMut() -> Result<R, E>`, but uses
14//! task-oriented vocabulary. Use it when the operation is a computation or task
15//! whose success value matters. Use `Runnable<E>` when the operation only needs
16//! to report success or failure.
17//!
18//! The trait itself does not require `Send`; concurrent executors should add
19//! `+ Send + 'static` at their API boundary.
20//!
21//! # Author
22//!
23//! Haixing Hu
24
25use std::cell::RefCell;
26use std::rc::Rc;
27use std::sync::Arc;
28
29use parking_lot::Mutex;
30
31use crate::{
32    functions::macros::impl_function_debug_display,
33    macros::{
34        impl_arc_conversions,
35        impl_box_conversions,
36        impl_closure_trait,
37        impl_common_name_methods,
38        impl_common_new_methods,
39        impl_rc_conversions,
40    },
41    suppliers::supplier::Supplier,
42    tasks::callable_once::BoxCallableOnce,
43    tasks::runnable::BoxRunnable,
44};
45
46// ============================================================================
47// Callable Trait
48// ============================================================================
49
50/// A fallible, reusable zero-argument computation.
51///
52/// Conceptually this is the same shape as `FnMut() -> Result<R, E>`: `call` takes
53/// `&mut self` and returns `Result<R, E>`, but the API uses task-oriented naming
54/// and helpers. In this crate it aligns with [`Supplier`] of `Result<R, E>`—a
55/// fallible supplier—while emphasizing executable work rather than plain value
56/// production.
57///
58/// Choose **`Callable`** when callers need the success value `R`. When only
59/// success or failure matters, use [`Runnable`](crate::tasks::Runnable), whose
60/// success type is `()`.
61///
62/// # Type Parameters
63///
64/// * `R` - The success value returned by the computation.
65/// * `E` - The error value returned when the computation fails.
66///
67/// # Examples
68///
69/// ```rust
70/// use qubit_function::Callable;
71///
72/// let mut task = || Ok::<i32, String>(21 * 2);
73/// assert_eq!(task.call().expect("call should succeed"), 42);
74/// ```
75///
76/// # Author
77///
78/// Haixing Hu
79pub trait Callable<R, E> {
80    /// Executes the computation, borrowing `self` mutably.
81    ///
82    /// # Returns
83    ///
84    /// Returns `Ok(R)` when the computation succeeds, or `Err(E)` when it
85    /// fails. The exact error meaning is defined by the concrete callable.
86    fn call(&mut self) -> Result<R, E>;
87
88    /// Converts this callable into a boxed callable.
89    ///
90    /// # Returns
91    ///
92    /// A `BoxCallable<R, E>` that executes this callable when `call()` is
93    /// invoked.
94    fn into_box(mut self) -> BoxCallable<R, E>
95    where
96        Self: Sized + 'static,
97    {
98        BoxCallable::new(move || self.call())
99    }
100
101    /// Converts this callable into an `Rc` callable.
102    ///
103    /// # Returns
104    ///
105    /// A `RcCallable<R, E>`.
106    fn into_rc(mut self) -> RcCallable<R, E>
107    where
108        Self: Sized + 'static,
109    {
110        RcCallable::new(move || self.call())
111    }
112
113    /// Converts this callable into an `Arc` callable.
114    ///
115    /// # Returns
116    ///
117    /// An `ArcCallable<R, E>`.
118    fn into_arc(mut self) -> ArcCallable<R, E>
119    where
120        Self: Sized + Send + 'static,
121    {
122        ArcCallable::new(move || self.call())
123    }
124
125    /// Converts this callable into a mutable closure.
126    ///
127    /// # Returns
128    ///
129    /// A closure implementing `FnMut() -> Result<R, E>`.
130    fn into_fn(mut self) -> impl FnMut() -> Result<R, E>
131    where
132        Self: Sized + 'static,
133    {
134        move || self.call()
135    }
136
137    /// Converts this callable into a boxed callable without consuming `self`.
138    ///
139    /// The method clones `self` and boxes the clone. Use this for cloneable
140    /// callable values that need to be reused after boxing.
141    ///
142    /// # Returns
143    ///
144    /// A new `BoxCallable<R, E>` built from a clone of this callable.
145    fn to_box(&self) -> BoxCallable<R, E>
146    where
147        Self: Clone + Sized + 'static,
148    {
149        self.clone().into_box()
150    }
151
152    /// Converts this callable into an `Rc` callable without consuming `self`.
153    ///
154    /// The method clones `self` and wraps the clone.
155    ///
156    /// # Returns
157    ///
158    /// A `RcCallable<R, E>`.
159    fn to_rc(&self) -> RcCallable<R, E>
160    where
161        Self: Clone + Sized + 'static,
162    {
163        self.clone().into_rc()
164    }
165
166    /// Converts this callable into an `Arc` callable without consuming `self`.
167    ///
168    /// The method clones `self` and wraps the clone.
169    ///
170    /// # Returns
171    ///
172    /// An `ArcCallable<R, E>`.
173    fn to_arc(&self) -> ArcCallable<R, E>
174    where
175        Self: Clone + Send + Sized + 'static,
176    {
177        self.clone().into_arc()
178    }
179
180    /// Converts this callable into a mutable closure without consuming `self`.
181    ///
182    /// The method clones `self` and returns a closure that executes the clone
183    /// on each call.
184    ///
185    /// # Returns
186    ///
187    /// A closure implementing `FnMut() -> Result<R, E>`.
188    fn to_fn(&self) -> impl FnMut() -> Result<R, E>
189    where
190        Self: Clone + Sized + 'static,
191    {
192        self.clone().into_fn()
193    }
194
195    /// Converts this callable into a one-time callable.
196    ///
197    /// The returned callable consumes itself on each invocation.
198    ///
199    /// # Returns
200    ///
201    /// A `BoxCallableOnce<R, E>`.
202    fn into_once(mut self) -> BoxCallableOnce<R, E>
203    where
204        Self: Sized + 'static,
205    {
206        BoxCallableOnce::new(move || self.call())
207    }
208
209    /// Converts this callable into a one-time callable without consuming
210    /// `self`.
211    ///
212    /// The method clones `self` and returns a one-time callable.
213    ///
214    /// # Returns
215    ///
216    /// A `BoxCallableOnce<R, E>`.
217    fn to_once(&self) -> BoxCallableOnce<R, E>
218    where
219        Self: Clone + Sized + 'static,
220    {
221        self.clone().into_once()
222    }
223
224    /// Converts this callable into a runnable by discarding the success value.
225    ///
226    /// The returned runnable preserves errors and maps any `Ok(R)` to
227    /// `Ok(())`.
228    ///
229    /// # Returns
230    ///
231    /// A `BoxRunnable<E>` that executes this callable and discards its success
232    /// value.
233    fn into_runnable(mut self) -> BoxRunnable<E>
234    where
235        Self: Sized + 'static,
236    {
237        BoxRunnable::new(move || self.call().map(|_| ()))
238    }
239}
240
241// ============================================================================
242// BoxCallable
243// ============================================================================
244
245/// Box-based callable.
246///
247/// `BoxCallable<R, E>` stores a `Box<dyn FnMut() -> Result<R, E>>` and can be
248/// called repeatedly. It is the boxed concrete implementation of
249/// [`Callable`].
250///
251/// # Type Parameters
252///
253/// * `R` - The success value returned by the computation.
254/// * `E` - The error value returned when the computation fails.
255///
256/// # Example
257///
258/// ```rust
259/// use qubit_function::{BoxCallable, Callable};
260///
261/// let mut task = BoxCallable::new(|| Ok::<i32, String>(42));
262/// assert_eq!(task.call().expect("call should succeed"), 42);
263/// ```
264///
265/// # Author
266///
267/// Haixing Hu
268pub struct BoxCallable<R, E> {
269    /// The stateful closure executed by this callable.
270    function: Box<dyn FnMut() -> Result<R, E>>,
271    /// The optional name of this callable.
272    name: Option<String>,
273}
274
275impl<R, E> BoxCallable<R, E> {
276    impl_common_new_methods!(
277        (FnMut() -> Result<R, E> + 'static),
278        |function| Box::new(function),
279        "callable"
280    );
281
282    /// Creates a boxed callable from a reusable supplier.
283    ///
284    /// This is an explicit bridge from `Supplier<Result<R, E>>` to
285    /// `Callable<R, E>`.
286    ///
287    /// # Parameters
288    ///
289    /// * `supplier` - The supplier that produces the callable result.
290    ///
291    /// # Returns
292    ///
293    /// A new `BoxCallable<R, E>`.
294    #[inline]
295    pub fn from_supplier<S>(supplier: S) -> Self
296    where
297        S: Supplier<Result<R, E>> + 'static,
298    {
299        Self::new(move || supplier.get())
300    }
301
302    impl_common_name_methods!("callable");
303
304    /// Maps the success value of this callable.
305    ///
306    /// # Parameters
307    ///
308    /// * `mapper` - Function that transforms the success value.
309    ///
310    /// # Returns
311    ///
312    /// A new callable that applies `mapper` when this callable succeeds.
313    #[inline]
314    pub fn map<U, M>(self, mut mapper: M) -> BoxCallable<U, E>
315    where
316        M: FnMut(R) -> U + 'static,
317        R: 'static,
318        E: 'static,
319    {
320        let name = self.name;
321        let mut function = self.function;
322        BoxCallable::new_with_optional_name(move || function().map(&mut mapper), name)
323    }
324
325    /// Maps the error value of this callable.
326    ///
327    /// # Parameters
328    ///
329    /// * `mapper` - Function that transforms the error value.
330    ///
331    /// # Returns
332    ///
333    /// A new callable that applies `mapper` when this callable fails.
334    #[inline]
335    pub fn map_err<E2, M>(self, mut mapper: M) -> BoxCallable<R, E2>
336    where
337        M: FnMut(E) -> E2 + 'static,
338        R: 'static,
339        E: 'static,
340    {
341        let name = self.name;
342        let mut function = self.function;
343        BoxCallable::new_with_optional_name(move || function().map_err(&mut mapper), name)
344    }
345
346    /// Chains another fallible computation after this callable succeeds.
347    ///
348    /// # Parameters
349    ///
350    /// * `next` - Function that receives the success value and returns the next
351    ///   result.
352    ///
353    /// # Returns
354    ///
355    /// A new callable that runs `next` only when this callable succeeds.
356    #[inline]
357    pub fn and_then<U, N>(self, next: N) -> BoxCallable<U, E>
358    where
359        N: FnMut(R) -> Result<U, E> + 'static,
360        R: 'static,
361        E: 'static,
362    {
363        let name = self.name;
364        let mut function = self.function;
365        let mut next = next;
366        BoxCallable::new_with_optional_name(
367            move || {
368                let value = function()?;
369                next(value)
370            },
371            name,
372        )
373    }
374}
375
376impl<R, E> Callable<R, E> for BoxCallable<R, E> {
377    /// Executes the boxed callable.
378    #[inline]
379    fn call(&mut self) -> Result<R, E> {
380        (self.function)()
381    }
382
383    impl_box_conversions!(
384        BoxCallable<R, E>,
385        RcCallable,
386        FnMut() -> Result<R, E>,
387        BoxCallableOnce
388    );
389
390    /// Converts this boxed callable into a boxed runnable while preserving its
391    /// name.
392    #[inline]
393    fn into_runnable(self) -> BoxRunnable<E>
394    where
395        Self: Sized + 'static,
396    {
397        let name = self.name;
398        let mut function = self.function;
399        BoxRunnable::new_with_optional_name(move || function().map(|_| ()), name)
400    }
401}
402
403// ============================================================================
404// RcCallable
405// ============================================================================
406
407/// Single-threaded shared callable.
408///
409/// `RcCallable<R, E>` stores a `Rc<RefCell<dyn FnMut() -> Result<R, E>>>` and
410/// can be called repeatedly through shared ownership.
411///
412/// # Type Parameters
413///
414/// * `R` - The success value returned by the computation.
415/// * `E` - The error value returned when the computation fails.
416///
417/// # Author
418///
419/// Haixing Hu
420pub struct RcCallable<R, E> {
421    /// The stateful closure executed by this callable.
422    function: Rc<RefCell<dyn FnMut() -> Result<R, E>>>,
423    /// The optional name of this callable.
424    name: Option<String>,
425}
426
427impl<R, E> Clone for RcCallable<R, E> {
428    #[inline]
429    fn clone(&self) -> Self {
430        Self {
431            function: Rc::clone(&self.function),
432            name: self.name.clone(),
433        }
434    }
435}
436
437impl<R, E> RcCallable<R, E> {
438    impl_common_new_methods!(
439        (FnMut() -> Result<R, E> + 'static),
440        |function| Rc::new(RefCell::new(function)),
441        "callable"
442    );
443
444    /// Creates an `RcCallable` from a reusable supplier.
445    ///
446    /// # Parameters
447    ///
448    /// * `supplier` - The supplier that produces the callable result.
449    ///
450    /// # Returns
451    ///
452    /// A new `RcCallable<R, E>`.
453    #[inline]
454    pub fn from_supplier<S>(supplier: S) -> Self
455    where
456        S: Supplier<Result<R, E>> + 'static,
457    {
458        Self::new(move || supplier.get())
459    }
460
461    impl_common_name_methods!("callable");
462}
463
464impl<R, E> Callable<R, E> for RcCallable<R, E> {
465    /// Executes the shared callable.
466    #[inline]
467    fn call(&mut self) -> Result<R, E> {
468        (self.function.borrow_mut())()
469    }
470
471    impl_rc_conversions!(
472        RcCallable<R, E>,
473        BoxCallable,
474        BoxCallableOnce,
475        FnMut() -> Result<R, E>
476    );
477
478    /// Converts this shared callable into a boxed runnable while preserving its
479    /// name.
480    #[inline]
481    fn into_runnable(self) -> BoxRunnable<E>
482    where
483        Self: Sized + 'static,
484    {
485        let name = self.name;
486        let function = self.function;
487        BoxRunnable::new_with_optional_name(move || (function.borrow_mut())().map(|_| ()), name)
488    }
489}
490
491// ============================================================================
492// ArcCallable
493// ============================================================================
494
495/// Thread-safe callable.
496///
497/// `ArcCallable<R, E>` stores a `Arc<Mutex<dyn FnMut() -> Result<R, E> + Send>>`
498/// and can be called repeatedly across threads.
499///
500/// # Type Parameters
501///
502/// * `R` - The success value returned by the computation.
503/// * `E` - The error value returned when the computation fails.
504///
505/// # Author
506///
507/// Haixing Hu
508pub struct ArcCallable<R, E> {
509    /// The stateful closure executed by this callable.
510    function: Arc<Mutex<dyn FnMut() -> Result<R, E> + Send>>,
511    /// The optional name of this callable.
512    name: Option<String>,
513}
514
515impl<R, E> Clone for ArcCallable<R, E> {
516    #[inline]
517    fn clone(&self) -> Self {
518        Self {
519            function: Arc::clone(&self.function),
520            name: self.name.clone(),
521        }
522    }
523}
524
525impl<R, E> ArcCallable<R, E> {
526    impl_common_new_methods!(
527        (FnMut() -> Result<R, E> + Send + 'static),
528        |function| Arc::new(Mutex::new(function)),
529        "callable"
530    );
531
532    /// Creates an `ArcCallable` from a reusable supplier.
533    ///
534    /// # Parameters
535    ///
536    /// * `supplier` - The supplier that produces the callable result.
537    ///
538    /// # Returns
539    ///
540    /// A new `ArcCallable<R, E>`.
541    #[inline]
542    pub fn from_supplier<S>(supplier: S) -> Self
543    where
544        S: Supplier<Result<R, E>> + Send + 'static,
545    {
546        Self::new(move || supplier.get())
547    }
548
549    impl_common_name_methods!("callable");
550}
551
552impl<R, E> Callable<R, E> for ArcCallable<R, E> {
553    /// Executes the thread-safe callable.
554    #[inline]
555    fn call(&mut self) -> Result<R, E> {
556        (self.function.lock())()
557    }
558
559    impl_arc_conversions!(
560        ArcCallable<R, E>,
561        BoxCallable,
562        RcCallable,
563        BoxCallableOnce,
564        FnMut() -> Result<R, E>
565    );
566
567    /// Converts this shared callable into a boxed runnable while preserving its
568    /// name.
569    #[inline]
570    fn into_runnable(self) -> BoxRunnable<E>
571    where
572        Self: Sized + 'static,
573    {
574        let name = self.name;
575        let function = self.function;
576        BoxRunnable::new_with_optional_name(move || (function.lock())().map(|_| ()), name)
577    }
578}
579
580impl_closure_trait!(
581    Callable<R, E>,
582    call,
583    BoxCallableOnce,
584    FnMut() -> Result<R, E>
585);
586
587impl_function_debug_display!(BoxCallable<R, E>);
588impl_function_debug_display!(RcCallable<R, E>);
589impl_function_debug_display!(ArcCallable<R, E>);