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