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}