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