Skip to main content

qubit_function/tasks/
runnable_once.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 Once Types
11//!
12//! Provides fallible, one-time, zero-argument actions.
13//!
14//! A `RunnableOnce<E>` is equivalent to `FnOnce() -> 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::{
24        impl_box_once_conversions,
25        impl_common_name_methods,
26        impl_common_new_methods,
27    },
28    suppliers::macros::impl_supplier_debug_display,
29    suppliers::supplier_once::SupplierOnce,
30    tasks::callable_once::{
31        BoxCallableOnce,
32        CallableOnce,
33        LocalBoxCallableOnce,
34    },
35};
36
37mod box_runnable_once;
38pub use box_runnable_once::BoxRunnableOnce;
39mod local_box_runnable_once;
40pub use local_box_runnable_once::LocalBoxRunnableOnce;
41
42// ============================================================================
43// RunnableOnce Trait
44// ============================================================================
45
46/// A fallible one-time action.
47///
48/// Conceptually this matches `FnOnce() -> Result<(), E>`: `run` consumes `self`
49/// and returns `Result<(), E>`, but the surface uses task-oriented naming and
50/// helpers instead of closure types. It is a semantic specialization of
51/// `SupplierOnce<Result<(), E>>` for executable actions and deferred side effects.
52///
53/// Choose **`RunnableOnce`** when only success or failure matters; the success
54/// type is `()`. When callers need the success value `R`, use
55/// [`CallableOnce`].
56///
57/// # Type Parameters
58///
59/// * `E` - The error value returned when the action fails.
60///
61/// # Examples
62///
63/// ```rust
64/// use qubit_function::{RunnableOnce, BoxRunnableOnce};
65///
66/// let task = || Ok::<(), String>(());
67/// assert_eq!(task.run(), Ok(()));
68/// ```
69///
70pub trait RunnableOnce<E> {
71    /// Executes the action, consuming `self`.
72    ///
73    /// # Returns
74    ///
75    /// Returns `Ok(())` when the action succeeds, or `Err(E)` when it fails.
76    /// The exact error meaning is defined by the concrete runnable.
77    fn run(self) -> Result<(), E>;
78
79    /// Converts this runnable into a boxed runnable.
80    ///
81    /// # Returns
82    ///
83    /// A `BoxRunnableOnce<E>` that executes this runnable when `run()` is
84    /// invoked.
85    fn into_box(self) -> BoxRunnableOnce<E>
86    where
87        Self: Sized + Send + 'static,
88    {
89        BoxRunnableOnce::new(move || self.run())
90    }
91
92    /// Converts this runnable into a local boxed runnable.
93    ///
94    /// # Returns
95    ///
96    /// A `LocalBoxRunnableOnce<E>` that may hold non-`Send` captures and must
97    /// be executed on the local thread.
98    fn into_local_box(self) -> LocalBoxRunnableOnce<E>
99    where
100        Self: Sized + 'static,
101    {
102        LocalBoxRunnableOnce::new(move || self.run())
103    }
104
105    /// Converts this runnable into a closure.
106    ///
107    /// # Returns
108    ///
109    /// A closure implementing `FnOnce() -> Result<(), E>`.
110    fn into_fn(self) -> impl FnOnce() -> Result<(), E>
111    where
112        Self: Sized + 'static,
113    {
114        move || self.run()
115    }
116
117    /// Converts this runnable into a boxed runnable without consuming `self`.
118    ///
119    /// The method clones `self` and boxes the clone. Use this for cloneable
120    /// runnable values that need to be reused after boxing.
121    ///
122    /// # Returns
123    ///
124    /// A new `BoxRunnableOnce<E>` built from a clone of this runnable.
125    fn to_box(&self) -> BoxRunnableOnce<E>
126    where
127        Self: Clone + Send + Sized + 'static,
128    {
129        self.clone().into_box()
130    }
131
132    /// Converts this runnable into a local boxed runnable without consuming
133    /// `self`.
134    ///
135    /// The method clones `self` and boxes the clone without requiring `Send`.
136    ///
137    /// # Returns
138    ///
139    /// A new `LocalBoxRunnableOnce<E>` built from a clone of this runnable.
140    fn to_local_box(&self) -> LocalBoxRunnableOnce<E>
141    where
142        Self: Clone + Sized + 'static,
143    {
144        self.clone().into_local_box()
145    }
146
147    /// Converts this runnable into a closure without consuming `self`.
148    ///
149    /// The method clones `self` and returns a one-time closure that executes
150    /// the clone.
151    ///
152    /// # Returns
153    ///
154    /// A closure implementing `FnOnce() -> Result<(), E>`.
155    fn to_fn(&self) -> impl FnOnce() -> Result<(), E>
156    where
157        Self: Clone + Sized + 'static,
158    {
159        self.clone().into_fn()
160    }
161
162    /// Converts this runnable into a callable returning unit.
163    ///
164    /// # Returns
165    ///
166    /// A `BoxCallableOnce<(), E>` that executes this runnable and returns
167    /// `Ok(())` on success.
168    fn into_callable(self) -> BoxCallableOnce<(), E>
169    where
170        Self: Sized + Send + 'static,
171    {
172        BoxCallableOnce::new(move || self.run())
173    }
174
175    /// Converts this runnable into a local callable returning unit.
176    ///
177    /// # Returns
178    ///
179    /// A `LocalBoxCallableOnce<(), E>` that may hold non-`Send` captures and
180    /// returns `Ok(())` on success.
181    fn into_local_callable(self) -> LocalBoxCallableOnce<(), E>
182    where
183        Self: Sized + 'static,
184    {
185        LocalBoxCallableOnce::new(move || self.run())
186    }
187}