Skip to main content

qubit_function/tasks/
runnable_once.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # Runnable Once Types
10//!
11//! Provides fallible, one-time, zero-argument actions.
12//!
13//! A `RunnableOnce<E>` is equivalent to `FnOnce() -> Result<(), E>`, but uses
14//! task-oriented vocabulary. Use it when the operation's side effect matters
15//! and only success or failure should be reported.
16//!
17//! The trait itself does not require `Send`; concurrent executors should add
18//! `+ Send + 'static` at their API boundary.
19//!
20//! # Author
21//!
22//! Haixing Hu
23
24use crate::{
25    macros::{
26        impl_box_once_conversions,
27        impl_closure_once_trait,
28        impl_common_name_methods,
29        impl_common_new_methods,
30    },
31    suppliers::macros::impl_supplier_debug_display,
32    suppliers::supplier_once::SupplierOnce,
33    tasks::callable_once::{
34        BoxCallableOnce,
35        CallableOnce,
36    },
37};
38
39mod box_runnable_once;
40pub use box_runnable_once::BoxRunnableOnce;
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///
70/// # Author
71///
72/// Haixing Hu
73pub trait RunnableOnce<E> {
74    /// Executes the action, consuming `self`.
75    ///
76    /// # Returns
77    ///
78    /// Returns `Ok(())` when the action succeeds, or `Err(E)` when it fails.
79    /// The exact error meaning is defined by the concrete runnable.
80    fn run(self) -> Result<(), E>;
81
82    /// Converts this runnable into a boxed runnable.
83    ///
84    /// # Returns
85    ///
86    /// A `BoxRunnableOnce<E>` that executes this runnable when `run()` is
87    /// invoked.
88    fn into_box(self) -> BoxRunnableOnce<E>
89    where
90        Self: Sized + 'static,
91    {
92        BoxRunnableOnce::new(move || self.run())
93    }
94
95    /// Converts this runnable into a closure.
96    ///
97    /// # Returns
98    ///
99    /// A closure implementing `FnOnce() -> Result<(), E>`.
100    fn into_fn(self) -> impl FnOnce() -> Result<(), E>
101    where
102        Self: Sized + 'static,
103    {
104        move || self.run()
105    }
106
107    /// Converts this runnable into a boxed runnable without consuming `self`.
108    ///
109    /// The method clones `self` and boxes the clone. Use this for cloneable
110    /// runnable values that need to be reused after boxing.
111    ///
112    /// # Returns
113    ///
114    /// A new `BoxRunnableOnce<E>` built from a clone of this runnable.
115    fn to_box(&self) -> BoxRunnableOnce<E>
116    where
117        Self: Clone + Sized + 'static,
118    {
119        self.clone().into_box()
120    }
121
122    /// Converts this runnable into a closure without consuming `self`.
123    ///
124    /// The method clones `self` and returns a one-time closure that executes
125    /// the clone.
126    ///
127    /// # Returns
128    ///
129    /// A closure implementing `FnOnce() -> Result<(), E>`.
130    fn to_fn(&self) -> impl FnOnce() -> Result<(), E>
131    where
132        Self: Clone + Sized + 'static,
133    {
134        self.clone().into_fn()
135    }
136
137    /// Converts this runnable into a callable returning unit.
138    ///
139    /// # Returns
140    ///
141    /// A `BoxCallableOnce<(), E>` that executes this runnable and returns
142    /// `Ok(())` on success.
143    fn into_callable(self) -> BoxCallableOnce<(), E>
144    where
145        Self: Sized + 'static,
146    {
147        BoxCallableOnce::new(move || self.run())
148    }
149}