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_closure_once_trait,
26 impl_common_name_methods,
27 impl_common_new_methods,
28 },
29 suppliers::macros::impl_supplier_debug_display,
30 suppliers::supplier_once::SupplierOnce,
31 tasks::callable_once::{
32 BoxCallableOnce,
33 CallableOnce,
34 },
35};
36
37mod box_runnable_once;
38pub use box_runnable_once::BoxRunnableOnce;
39
40// ============================================================================
41// RunnableOnce Trait
42// ============================================================================
43
44/// A fallible one-time action.
45///
46/// Conceptually this matches `FnOnce() -> Result<(), E>`: `run` consumes `self`
47/// and returns `Result<(), E>`, but the surface uses task-oriented naming and
48/// helpers instead of closure types. It is a semantic specialization of
49/// `SupplierOnce<Result<(), E>>` for executable actions and deferred side effects.
50///
51/// Choose **`RunnableOnce`** when only success or failure matters; the success
52/// type is `()`. When callers need the success value `R`, use
53/// [`CallableOnce`].
54///
55/// # Type Parameters
56///
57/// * `E` - The error value returned when the action fails.
58///
59/// # Examples
60///
61/// ```rust
62/// use qubit_function::{RunnableOnce, BoxRunnableOnce};
63///
64/// let task = || Ok::<(), String>(());
65/// assert_eq!(task.run(), Ok(()));
66/// ```
67///
68pub trait RunnableOnce<E> {
69 /// Executes the action, consuming `self`.
70 ///
71 /// # Returns
72 ///
73 /// Returns `Ok(())` when the action succeeds, or `Err(E)` when it fails.
74 /// The exact error meaning is defined by the concrete runnable.
75 fn run(self) -> Result<(), E>;
76
77 /// Converts this runnable into a boxed runnable.
78 ///
79 /// # Returns
80 ///
81 /// A `BoxRunnableOnce<E>` that executes this runnable when `run()` is
82 /// invoked.
83 fn into_box(self) -> BoxRunnableOnce<E>
84 where
85 Self: Sized + 'static,
86 {
87 BoxRunnableOnce::new(move || self.run())
88 }
89
90 /// Converts this runnable into a closure.
91 ///
92 /// # Returns
93 ///
94 /// A closure implementing `FnOnce() -> Result<(), E>`.
95 fn into_fn(self) -> impl FnOnce() -> Result<(), E>
96 where
97 Self: Sized + 'static,
98 {
99 move || self.run()
100 }
101
102 /// Converts this runnable into a boxed runnable without consuming `self`.
103 ///
104 /// The method clones `self` and boxes the clone. Use this for cloneable
105 /// runnable values that need to be reused after boxing.
106 ///
107 /// # Returns
108 ///
109 /// A new `BoxRunnableOnce<E>` built from a clone of this runnable.
110 fn to_box(&self) -> BoxRunnableOnce<E>
111 where
112 Self: Clone + Sized + 'static,
113 {
114 self.clone().into_box()
115 }
116
117 /// Converts this runnable into a closure without consuming `self`.
118 ///
119 /// The method clones `self` and returns a one-time closure that executes
120 /// the clone.
121 ///
122 /// # Returns
123 ///
124 /// A closure implementing `FnOnce() -> Result<(), E>`.
125 fn to_fn(&self) -> impl FnOnce() -> Result<(), E>
126 where
127 Self: Clone + Sized + 'static,
128 {
129 self.clone().into_fn()
130 }
131
132 /// Converts this runnable into a callable returning unit.
133 ///
134 /// # Returns
135 ///
136 /// A `BoxCallableOnce<(), E>` that executes this runnable and returns
137 /// `Ok(())` on success.
138 fn into_callable(self) -> BoxCallableOnce<(), E>
139 where
140 Self: Sized + 'static,
141 {
142 BoxCallableOnce::new(move || self.run())
143 }
144}