Skip to main content

qubit_function/tasks/
runnable.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # Runnable Types
10//!
11//! Provides fallible, reusable, zero-argument actions.
12//!
13//! A `Runnable<E>` is equivalent to `FnMut() -> Result<(), E>`, but uses
14//! task-oriented vocabulary. Use it when the operation's side effect matters
15//! and only success or failure should be reported.
16//!
17//! The trait itself does not require `Send`; concurrent executors should add
18//! `+ Send + 'static` at their API boundary.
19//!
20//! # Author
21//!
22//! Haixing Hu
23
24use std::cell::RefCell;
25use std::rc::Rc;
26use std::sync::Arc;
27
28use parking_lot::Mutex;
29
30use crate::{
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::macros::impl_supplier_debug_display,
40    suppliers::supplier::Supplier,
41    suppliers::supplier_once::SupplierOnce,
42    tasks::callable::BoxCallable,
43};
44
45mod box_runnable;
46pub use box_runnable::BoxRunnable;
47mod rc_runnable;
48pub use rc_runnable::RcRunnable;
49mod arc_runnable;
50pub use arc_runnable::ArcRunnable;
51
52// ============================================================================
53// Runnable Trait
54// ============================================================================
55
56/// A fallible, reusable, zero-argument action.
57///
58/// Conceptually, `Runnable<E>` matches [`FnMut`] `() -> Result<(), E>`, but
59/// uses task-oriented vocabulary. Prefer it when the operation's side effect
60/// matters and only success or failure need to be reported.
61///
62/// Each call borrows `self` mutably and returns [`Result::Ok`] with unit or
63/// [`Result::Err`] with `E`. Semantically, this is a specialization of
64/// [`SupplierOnce`]`<Result<(), E>>` for executable actions and deferred side
65/// effects.
66///
67/// The trait does not require [`Send`]. Concurrent executors should require
68/// `Runnable<E> + Send + 'static` (or similar) at their API boundary.
69///
70/// # Type Parameters
71///
72/// * `E` - The error value returned when the action fails.
73///
74/// # Examples
75///
76/// ```rust
77/// use qubit_function::Runnable;
78///
79/// let mut task = || Ok::<(), String>(());
80/// assert_eq!(task.run(), Ok(()));
81/// ```
82///
83/// # Author
84///
85/// Haixing Hu
86pub trait Runnable<E> {
87    /// Executes the action, borrowing `self` mutably.
88    ///
89    /// # Returns
90    ///
91    /// Returns `Ok(())` when the action succeeds, or `Err(E)` when it fails.
92    /// The exact error meaning is defined by the concrete runnable.
93    fn run(&mut self) -> Result<(), E>;
94
95    /// Converts this runnable into a boxed runnable.
96    ///
97    /// # Returns
98    ///
99    /// A `BoxRunnable<E>` that executes this runnable when `run()` is invoked.
100    fn into_box(mut self) -> BoxRunnable<E>
101    where
102        Self: Sized + 'static,
103    {
104        BoxRunnable::new(move || self.run())
105    }
106
107    /// Converts this runnable into a shared single-threaded runnable.
108    ///
109    /// # Returns
110    ///
111    /// An `RcRunnable<E>` that executes this runnable when `run()` is invoked.
112    fn into_rc(mut self) -> RcRunnable<E>
113    where
114        Self: Sized + 'static,
115    {
116        RcRunnable::new(move || self.run())
117    }
118
119    /// Converts this runnable into a shared thread-safe runnable.
120    ///
121    /// # Returns
122    ///
123    /// An `ArcRunnable<E>` that executes this runnable when `run()` is invoked.
124    fn into_arc(mut self) -> ArcRunnable<E>
125    where
126        Self: Sized + Send + 'static,
127    {
128        ArcRunnable::new(move || self.run())
129    }
130
131    /// Converts this runnable into a mutable closure.
132    ///
133    /// # Returns
134    ///
135    /// A closure implementing `FnMut() -> Result<(), E>`.
136    fn into_fn(mut self) -> impl FnMut() -> Result<(), E>
137    where
138        Self: Sized + 'static,
139    {
140        move || self.run()
141    }
142
143    /// Converts this runnable into a boxed runnable without consuming `self`.
144    ///
145    /// The method clones `self` and boxes the clone. Use this for cloneable
146    /// runnable values that need to be reused after boxing.
147    ///
148    /// # Returns
149    ///
150    /// A new `BoxRunnable<E>` built from a clone of this runnable.
151    fn to_box(&self) -> BoxRunnable<E>
152    where
153        Self: Clone + Sized + 'static,
154    {
155        self.clone().into_box()
156    }
157
158    /// Converts this runnable into a mutable closure without consuming `self`.
159    ///
160    /// The method clones `self` and returns a mutable closure that executes
161    /// the clone.
162    ///
163    /// # Returns
164    ///
165    /// A closure implementing `FnMut() -> Result<(), E>`.
166    fn to_fn(&self) -> impl FnMut() -> Result<(), E>
167    where
168        Self: Clone + Sized + 'static,
169    {
170        self.clone().into_fn()
171    }
172
173    /// Converts this runnable into a shared single-threaded runnable without
174    /// consuming `self`.
175    ///
176    /// The method clones `self` and wraps the clone.
177    ///
178    /// # Returns
179    ///
180    /// A new `RcRunnable<E>` built from a clone of this runnable.
181    fn to_rc(&self) -> RcRunnable<E>
182    where
183        Self: Clone + Sized + 'static,
184    {
185        self.clone().into_rc()
186    }
187
188    /// Converts this runnable into a shared thread-safe runnable without
189    /// consuming `self`.
190    ///
191    /// The method clones `self` and wraps the clone.
192    ///
193    /// # Returns
194    ///
195    /// A new `ArcRunnable<E>` built from a clone of this runnable.
196    fn to_arc(&self) -> ArcRunnable<E>
197    where
198        Self: Clone + Send + Sized + 'static,
199    {
200        self.clone().into_arc()
201    }
202
203    /// Converts this runnable into a callable returning unit.
204    ///
205    /// # Returns
206    ///
207    /// A `BoxCallable<(), E>` that executes this runnable and returns
208    /// `Ok(())` on success.
209    fn into_callable(self) -> BoxCallable<(), E>
210    where
211        Self: Sized + 'static,
212    {
213        let mut runnable = self;
214        BoxCallable::new(move || runnable.run())
215    }
216}