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}