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