qubit_function/tasks/callable.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//! # Callable Types
11//!
12//! Provides fallible, reusable, zero-argument computations.
13//!
14//! A `Callable<R, E>` is equivalent to `FnMut() -> Result<R, E>`, but uses
15//! task-oriented vocabulary. Use it when the operation is a computation or task
16//! whose success value matters. Use `Runnable<E>` when the operation only needs
17//! to report success or failure.
18//!
19//! The trait itself does not require `Send`; concurrent executors should add
20//! `+ Send + 'static` at their API boundary.
21//!
22
23use crate::{
24 tasks::callable_once::{
25 BoxCallableOnce,
26 LocalBoxCallableOnce,
27 },
28 tasks::runnable::BoxRunnable,
29};
30
31mod box_callable;
32pub use box_callable::BoxCallable;
33mod rc_callable;
34pub use rc_callable::RcCallable;
35mod arc_callable;
36pub use arc_callable::ArcCallable;
37
38// ============================================================================
39// Callable Trait
40// ============================================================================
41
42/// A fallible, reusable zero-argument computation.
43///
44/// Conceptually this is the same shape as `FnMut() -> Result<R, E>`: `call` takes
45/// `&mut self` and returns `Result<R, E>`, but the API uses task-oriented naming
46/// and helpers. In this crate it aligns with
47/// [`Supplier`](crate::suppliers::Supplier) of `Result<R, E>`—a fallible
48/// supplier—while emphasizing executable work rather than plain value production.
49///
50/// Choose **`Callable`** when callers need the success value `R`. When only
51/// success or failure matters, use [`Runnable`](crate::tasks::Runnable), whose
52/// success type is `()`.
53///
54/// # Type Parameters
55///
56/// * `R` - The success value returned by the computation.
57/// * `E` - The error value returned when the computation fails.
58///
59/// # Examples
60///
61/// ```rust
62/// use qubit_function::Callable;
63///
64/// let mut task = || Ok::<i32, String>(21 * 2);
65/// assert_eq!(task.call().expect("call should succeed"), 42);
66/// ```
67///
68pub trait Callable<R, E> {
69 /// Executes the computation, borrowing `self` mutably.
70 ///
71 /// # Returns
72 ///
73 /// Returns `Ok(R)` when the computation succeeds, or `Err(E)` when it
74 /// fails. The exact error meaning is defined by the concrete callable.
75 fn call(&mut self) -> Result<R, E>;
76
77 /// Converts this callable into a boxed callable.
78 ///
79 /// # Returns
80 ///
81 /// A `BoxCallable<R, E>` that executes this callable when `call()` is
82 /// invoked.
83 fn into_box(mut self) -> BoxCallable<R, E>
84 where
85 Self: Sized + 'static,
86 {
87 BoxCallable::new(move || self.call())
88 }
89
90 /// Converts this callable into an `Rc` callable.
91 ///
92 /// # Returns
93 ///
94 /// A `RcCallable<R, E>`.
95 fn into_rc(mut self) -> RcCallable<R, E>
96 where
97 Self: Sized + 'static,
98 {
99 RcCallable::new(move || self.call())
100 }
101
102 /// Converts this callable into an `Arc` callable.
103 ///
104 /// # Returns
105 ///
106 /// An `ArcCallable<R, E>`.
107 fn into_arc(mut self) -> ArcCallable<R, E>
108 where
109 Self: Sized + Send + 'static,
110 {
111 ArcCallable::new(move || self.call())
112 }
113
114 /// Converts this callable into a mutable closure.
115 ///
116 /// # Returns
117 ///
118 /// A closure implementing `FnMut() -> Result<R, E>`.
119 fn into_fn(mut self) -> impl FnMut() -> Result<R, E>
120 where
121 Self: Sized + 'static,
122 {
123 move || self.call()
124 }
125
126 /// Converts this callable into a boxed callable without consuming `self`.
127 ///
128 /// The method clones `self` and boxes the clone. Use this for cloneable
129 /// callable values that need to be reused after boxing.
130 ///
131 /// # Returns
132 ///
133 /// A new `BoxCallable<R, E>` built from a clone of this callable.
134 fn to_box(&self) -> BoxCallable<R, E>
135 where
136 Self: Clone + Sized + 'static,
137 {
138 self.clone().into_box()
139 }
140
141 /// Converts this callable into an `Rc` callable without consuming `self`.
142 ///
143 /// The method clones `self` and wraps the clone.
144 ///
145 /// # Returns
146 ///
147 /// A `RcCallable<R, E>`.
148 fn to_rc(&self) -> RcCallable<R, E>
149 where
150 Self: Clone + Sized + 'static,
151 {
152 self.clone().into_rc()
153 }
154
155 /// Converts this callable into an `Arc` callable without consuming `self`.
156 ///
157 /// The method clones `self` and wraps the clone.
158 ///
159 /// # Returns
160 ///
161 /// An `ArcCallable<R, E>`.
162 fn to_arc(&self) -> ArcCallable<R, E>
163 where
164 Self: Clone + Send + Sized + 'static,
165 {
166 self.clone().into_arc()
167 }
168
169 /// Converts this callable into a mutable closure without consuming `self`.
170 ///
171 /// The method clones `self` and returns a closure that executes the clone
172 /// on each call.
173 ///
174 /// # Returns
175 ///
176 /// A closure implementing `FnMut() -> Result<R, E>`.
177 fn to_fn(&self) -> impl FnMut() -> Result<R, E>
178 where
179 Self: Clone + Sized + 'static,
180 {
181 self.clone().into_fn()
182 }
183
184 /// Converts this callable into a one-time callable.
185 ///
186 /// The returned callable consumes itself on each invocation.
187 ///
188 /// # Returns
189 ///
190 /// A `BoxCallableOnce<R, E>`.
191 fn into_once(mut self) -> BoxCallableOnce<R, E>
192 where
193 Self: Sized + Send + 'static,
194 {
195 BoxCallableOnce::new(move || self.call())
196 }
197
198 /// Converts this callable into a local one-time callable.
199 ///
200 /// The returned callable consumes itself on each invocation and may hold
201 /// non-`Send` captures.
202 ///
203 /// # Returns
204 ///
205 /// A `LocalBoxCallableOnce<R, E>`.
206 fn into_local_once(mut self) -> LocalBoxCallableOnce<R, E>
207 where
208 Self: Sized + 'static,
209 {
210 LocalBoxCallableOnce::new(move || self.call())
211 }
212
213 /// Converts this callable into a one-time callable without consuming
214 /// `self`.
215 ///
216 /// The method clones `self` and returns a one-time callable.
217 ///
218 /// # Returns
219 ///
220 /// A `BoxCallableOnce<R, E>`.
221 fn to_once(&self) -> BoxCallableOnce<R, E>
222 where
223 Self: Clone + Send + Sized + 'static,
224 {
225 self.clone().into_once()
226 }
227
228 /// Converts this callable into a local one-time callable without consuming
229 /// `self`.
230 ///
231 /// The method clones `self` and returns a local one-time callable.
232 ///
233 /// # Returns
234 ///
235 /// A `LocalBoxCallableOnce<R, E>`.
236 fn to_local_once(&self) -> LocalBoxCallableOnce<R, E>
237 where
238 Self: Clone + Sized + 'static,
239 {
240 self.clone().into_local_once()
241 }
242
243 /// Converts this callable into a runnable by discarding the success value.
244 ///
245 /// The returned runnable preserves errors and maps any `Ok(R)` to
246 /// `Ok(())`.
247 ///
248 /// # Returns
249 ///
250 /// A `BoxRunnable<E>` that executes this callable and discards its success
251 /// value.
252 fn into_runnable(mut self) -> BoxRunnable<E>
253 where
254 Self: Sized + 'static,
255 {
256 BoxRunnable::new(move || self.call().map(|_| ()))
257 }
258}