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}