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
45// ============================================================================
46// Runnable Trait
47// ============================================================================
48
49/// A fallible, reusable, zero-argument action.
50///
51/// Conceptually, `Runnable<E>` matches [`FnMut`] `() -> Result<(), E>`, but
52/// uses task-oriented vocabulary. Prefer it when the operation's side effect
53/// matters and only success or failure need to be reported.
54///
55/// Each call borrows `self` mutably and returns [`Result::Ok`] with unit or
56/// [`Result::Err`] with `E`. Semantically, this is a specialization of
57/// [`SupplierOnce`]`<Result<(), E>>` for executable actions and deferred side
58/// effects.
59///
60/// The trait does not require [`Send`]. Concurrent executors should require
61/// `Runnable<E> + Send + 'static` (or similar) at their API boundary.
62///
63/// # Type Parameters
64///
65/// * `E` - The error value returned when the action fails.
66///
67/// # Examples
68///
69/// ```rust
70/// use qubit_function::Runnable;
71///
72/// let mut task = || Ok::<(), String>(());
73/// assert_eq!(task.run(), Ok(()));
74/// ```
75///
76/// # Author
77///
78/// Haixing Hu
79pub trait Runnable<E> {
80    /// Executes the action, borrowing `self` mutably.
81    ///
82    /// # Returns
83    ///
84    /// Returns `Ok(())` when the action succeeds, or `Err(E)` when it fails.
85    /// The exact error meaning is defined by the concrete runnable.
86    fn run(&mut self) -> Result<(), E>;
87
88    /// Converts this runnable into a boxed runnable.
89    ///
90    /// # Returns
91    ///
92    /// A `BoxRunnable<E>` that executes this runnable when `run()` is invoked.
93    fn into_box(mut self) -> BoxRunnable<E>
94    where
95        Self: Sized + 'static,
96    {
97        BoxRunnable::new(move || self.run())
98    }
99
100    /// Converts this runnable into a shared single-threaded runnable.
101    ///
102    /// # Returns
103    ///
104    /// An `RcRunnable<E>` that executes this runnable when `run()` is invoked.
105    fn into_rc(mut self) -> RcRunnable<E>
106    where
107        Self: Sized + 'static,
108    {
109        RcRunnable::new(move || self.run())
110    }
111
112    /// Converts this runnable into a shared thread-safe runnable.
113    ///
114    /// # Returns
115    ///
116    /// An `ArcRunnable<E>` that executes this runnable when `run()` is invoked.
117    fn into_arc(mut self) -> ArcRunnable<E>
118    where
119        Self: Sized + Send + 'static,
120    {
121        ArcRunnable::new(move || self.run())
122    }
123
124    /// Converts this runnable into a mutable closure.
125    ///
126    /// # Returns
127    ///
128    /// A closure implementing `FnMut() -> Result<(), E>`.
129    fn into_fn(mut self) -> impl FnMut() -> Result<(), E>
130    where
131        Self: Sized + 'static,
132    {
133        move || self.run()
134    }
135
136    /// Converts this runnable into a boxed runnable without consuming `self`.
137    ///
138    /// The method clones `self` and boxes the clone. Use this for cloneable
139    /// runnable values that need to be reused after boxing.
140    ///
141    /// # Returns
142    ///
143    /// A new `BoxRunnable<E>` built from a clone of this runnable.
144    fn to_box(&self) -> BoxRunnable<E>
145    where
146        Self: Clone + Sized + 'static,
147    {
148        self.clone().into_box()
149    }
150
151    /// Converts this runnable into a mutable closure without consuming `self`.
152    ///
153    /// The method clones `self` and returns a mutable closure that executes
154    /// the clone.
155    ///
156    /// # Returns
157    ///
158    /// A closure implementing `FnMut() -> Result<(), E>`.
159    fn to_fn(&self) -> impl FnMut() -> Result<(), E>
160    where
161        Self: Clone + Sized + 'static,
162    {
163        self.clone().into_fn()
164    }
165
166    /// Converts this runnable into a shared single-threaded runnable without
167    /// consuming `self`.
168    ///
169    /// The method clones `self` and wraps the clone.
170    ///
171    /// # Returns
172    ///
173    /// A new `RcRunnable<E>` built from a clone of this runnable.
174    fn to_rc(&self) -> RcRunnable<E>
175    where
176        Self: Clone + Sized + 'static,
177    {
178        self.clone().into_rc()
179    }
180
181    /// Converts this runnable into a shared thread-safe runnable without
182    /// consuming `self`.
183    ///
184    /// The method clones `self` and wraps the clone.
185    ///
186    /// # Returns
187    ///
188    /// A new `ArcRunnable<E>` built from a clone of this runnable.
189    fn to_arc(&self) -> ArcRunnable<E>
190    where
191        Self: Clone + Send + Sized + 'static,
192    {
193        self.clone().into_arc()
194    }
195
196    /// Converts this runnable into a callable returning unit.
197    ///
198    /// # Returns
199    ///
200    /// A `BoxCallable<(), E>` that executes this runnable and returns
201    /// `Ok(())` on success.
202    fn into_callable(self) -> BoxCallable<(), E>
203    where
204        Self: Sized + 'static,
205    {
206        let mut runnable = self;
207        BoxCallable::new(move || runnable.run())
208    }
209}
210
211// ============================================================================
212// BoxRunnable
213// ============================================================================
214
215/// Box-based reusable runnable.
216///
217/// `BoxRunnable<E>` stores a `Box<dyn FnMut() -> Result<(), E>>` and can be
218/// executed repeatedly. It is the boxed concrete implementation of
219/// [`Runnable`].
220///
221/// # Type Parameters
222///
223/// * `E` - The error value returned when the action fails.
224///
225/// # Examples
226///
227/// ```rust
228/// use qubit_function::{BoxRunnable, Runnable};
229///
230/// let mut task = BoxRunnable::new(|| Ok::<(), String>(()));
231/// assert_eq!(task.run(), Ok(()));
232/// ```
233///
234/// # Author
235///
236/// Haixing Hu
237pub struct BoxRunnable<E> {
238    /// The stateful closure executed by this runnable.
239    function: Box<dyn FnMut() -> Result<(), E>>,
240    /// The optional name of this runnable.
241    name: Option<String>,
242}
243
244impl<E> BoxRunnable<E> {
245    impl_common_new_methods!(
246        (FnMut() -> Result<(), E> + 'static),
247        |function| Box::new(function),
248        "runnable"
249    );
250
251    /// Creates a boxed runnable from a reusable supplier.
252    ///
253    /// This is an explicit bridge from `Supplier<Result<(), E>>` to
254    /// `Runnable<E>`.
255    ///
256    /// # Parameters
257    ///
258    /// * `supplier` - The supplier that produces the runnable result.
259    ///
260    /// # Returns
261    ///
262    /// A new `BoxRunnable<E>`.
263    #[inline]
264    pub fn from_supplier<S>(supplier: S) -> Self
265    where
266        S: Supplier<Result<(), E>> + 'static,
267    {
268        Self::new(move || supplier.get())
269    }
270
271    impl_common_name_methods!("runnable");
272
273    /// Chains another runnable after this runnable succeeds.
274    ///
275    /// The second runnable is not executed if this runnable returns `Err`.
276    ///
277    /// # Parameters
278    ///
279    /// * `next` - The runnable to execute after this runnable succeeds.
280    ///
281    /// # Returns
282    ///
283    /// A runnable executing both actions in sequence.
284    #[inline]
285    pub fn and_then<N>(self, next: N) -> BoxRunnable<E>
286    where
287        N: Runnable<E> + 'static,
288        E: 'static,
289    {
290        let name = self.name;
291        let mut function = self.function;
292        let mut next = next;
293        BoxRunnable::new_with_optional_name(
294            move || {
295                function()?;
296                next.run()
297            },
298            name,
299        )
300    }
301
302    /// Runs this runnable before a callable.
303    ///
304    /// The callable is not executed if this runnable returns `Err`.
305    ///
306    /// # Parameters
307    ///
308    /// * `callable` - The callable to execute after this runnable succeeds.
309    ///
310    /// # Returns
311    ///
312    /// A callable producing the second computation's result.
313    #[inline]
314    pub fn then_callable<R, C>(self, callable: C) -> BoxCallable<R, E>
315    where
316        C: crate::tasks::callable::Callable<R, E> + 'static,
317        R: 'static,
318        E: 'static,
319    {
320        let name = self.name;
321        let mut function = self.function;
322        let mut callable = callable;
323        BoxCallable::new_with_optional_name(
324            move || {
325                function()?;
326                callable.call()
327            },
328            name,
329        )
330    }
331}
332
333impl<E> Runnable<E> for BoxRunnable<E> {
334    /// Executes the boxed runnable.
335    #[inline]
336    fn run(&mut self) -> Result<(), E> {
337        (self.function)()
338    }
339
340    impl_box_conversions!(
341        BoxRunnable<E>,
342        RcRunnable,
343        FnMut() -> Result<(), E>
344    );
345
346    /// Converts this boxed runnable into a boxed callable while preserving its
347    /// name.
348    #[inline]
349    fn into_callable(self) -> BoxCallable<(), E>
350    where
351        Self: Sized + 'static,
352    {
353        let name = self.name;
354        let mut function = self.function;
355        BoxCallable::new_with_optional_name(
356            move || {
357                function()?;
358                Ok(())
359            },
360            name,
361        )
362    }
363}
364
365// ============================================================================
366// RcRunnable
367// ============================================================================
368
369/// Single-threaded shared runnable.
370///
371/// `RcRunnable<E>` stores a `Rc<RefCell<dyn FnMut() -> Result<(), E>>>` and can
372/// be called repeatedly through shared ownership.
373///
374/// # Type Parameters
375///
376/// * `E` - The error value returned when the action fails.
377///
378/// # Author
379///
380/// Haixing Hu
381pub struct RcRunnable<E> {
382    /// The stateful closure executed by this runnable.
383    function: Rc<RefCell<dyn FnMut() -> Result<(), E>>>,
384    /// The optional name of this runnable.
385    name: Option<String>,
386}
387
388impl<E> Clone for RcRunnable<E> {
389    #[inline]
390    fn clone(&self) -> Self {
391        Self {
392            function: Rc::clone(&self.function),
393            name: self.name.clone(),
394        }
395    }
396}
397
398impl<E> RcRunnable<E> {
399    impl_common_new_methods!(
400        (FnMut() -> Result<(), E> + 'static),
401        |function| Rc::new(RefCell::new(function)),
402        "runnable"
403    );
404
405    /// Creates a shared runnable from a reusable supplier.
406    ///
407    /// # Parameters
408    ///
409    /// * `supplier` - The supplier that produces the runnable result.
410    ///
411    /// # Returns
412    ///
413    /// A new `RcRunnable<E>`.
414    #[inline]
415    pub fn from_supplier<S>(supplier: S) -> Self
416    where
417        S: Supplier<Result<(), E>> + 'static,
418    {
419        Self::new(move || supplier.get())
420    }
421
422    impl_common_name_methods!("runnable");
423}
424
425impl<E> Runnable<E> for RcRunnable<E> {
426    /// Executes the shared runnable.
427    #[inline]
428    fn run(&mut self) -> Result<(), E> {
429        (self.function.borrow_mut())()
430    }
431
432    impl_rc_conversions!(
433        RcRunnable<E>,
434        BoxRunnable,
435        FnMut() -> Result<(), E>
436    );
437}
438
439// ============================================================================
440// ArcRunnable
441// ============================================================================
442
443/// Thread-safe runnable.
444///
445/// `ArcRunnable<E>` stores an `Arc<Mutex<dyn FnMut() -> Result<(), E> + Send>>`
446/// and can be called repeatedly across threads.
447///
448/// # Type Parameters
449///
450/// * `E` - The error value returned when the action fails.
451///
452/// # Author
453///
454/// Haixing Hu
455pub struct ArcRunnable<E> {
456    /// The stateful closure executed by this runnable.
457    function: Arc<Mutex<dyn FnMut() -> Result<(), E> + Send>>,
458    /// The optional name of this runnable.
459    name: Option<String>,
460}
461
462impl<E> Clone for ArcRunnable<E> {
463    #[inline]
464    fn clone(&self) -> Self {
465        Self {
466            function: Arc::clone(&self.function),
467            name: self.name.clone(),
468        }
469    }
470}
471
472impl<E> ArcRunnable<E> {
473    impl_common_new_methods!(
474        (FnMut() -> Result<(), E> + Send + 'static),
475        |function| Arc::new(Mutex::new(function)),
476        "runnable"
477    );
478
479    /// Creates a thread-safe runnable from a reusable supplier.
480    ///
481    /// # Parameters
482    ///
483    /// * `supplier` - The supplier that produces the runnable result.
484    ///
485    /// # Returns
486    ///
487    /// A new `ArcRunnable<E>`.
488    #[inline]
489    pub fn from_supplier<S>(supplier: S) -> Self
490    where
491        S: Supplier<Result<(), E>> + Send + 'static,
492    {
493        Self::new(move || supplier.get())
494    }
495
496    impl_common_name_methods!("runnable");
497}
498
499impl<E> Runnable<E> for ArcRunnable<E> {
500    /// Executes the thread-safe runnable.
501    #[inline]
502    fn run(&mut self) -> Result<(), E> {
503        (self.function.lock())()
504    }
505
506    impl_arc_conversions!(
507        ArcRunnable<E>,
508        BoxRunnable,
509        RcRunnable,
510        FnMut() -> Result<(), E>
511    );
512}
513
514impl<E> SupplierOnce<Result<(), E>> for BoxRunnable<E> {
515    /// Executes the boxed runnable as a one-time supplier of `Result<(), E>`.
516    #[inline]
517    fn get(mut self) -> Result<(), E> {
518        self.run()
519    }
520}
521
522impl_closure_trait!(
523    Runnable<E>,
524    run,
525    FnMut() -> Result<(), E>
526);
527
528impl_supplier_debug_display!(BoxRunnable<E>);