Skip to main content

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