qubit_function/tasks/callable.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # Callable Types
10//!
11//! Provides fallible, reusable, zero-argument computations.
12//!
13//! A `Callable<R, E>` is equivalent to `FnMut() -> Result<R, E>`, but uses
14//! task-oriented vocabulary. Use it when the operation is a computation or task
15//! whose success value matters. Use `Runnable<E>` when the operation only needs
16//! to report success or failure.
17//!
18//! The trait itself does not require `Send`; concurrent executors should add
19//! `+ Send + 'static` at their API boundary.
20//!
21//! # Author
22//!
23//! Haixing Hu
24
25use std::cell::RefCell;
26use std::rc::Rc;
27use std::sync::Arc;
28
29use parking_lot::Mutex;
30
31use crate::{
32 functions::macros::impl_function_debug_display,
33 macros::{
34 impl_arc_conversions,
35 impl_box_conversions,
36 impl_closure_trait,
37 impl_common_name_methods,
38 impl_common_new_methods,
39 impl_rc_conversions,
40 },
41 suppliers::supplier::Supplier,
42 tasks::callable_once::BoxCallableOnce,
43 tasks::runnable::BoxRunnable,
44};
45
46// ============================================================================
47// Callable Trait
48// ============================================================================
49
50/// A fallible, reusable zero-argument computation.
51///
52/// Conceptually this is the same shape as `FnMut() -> Result<R, E>`: `call` takes
53/// `&mut self` and returns `Result<R, E>`, but the API uses task-oriented naming
54/// and helpers. In this crate it aligns with [`Supplier`] of `Result<R, E>`—a
55/// fallible supplier—while emphasizing executable work rather than plain value
56/// production.
57///
58/// Choose **`Callable`** when callers need the success value `R`. When only
59/// success or failure matters, use [`Runnable`](crate::tasks::Runnable), whose
60/// success type is `()`.
61///
62/// # Type Parameters
63///
64/// * `R` - The success value returned by the computation.
65/// * `E` - The error value returned when the computation fails.
66///
67/// # Examples
68///
69/// ```rust
70/// use qubit_function::Callable;
71///
72/// let mut task = || Ok::<i32, String>(21 * 2);
73/// assert_eq!(task.call().expect("call should succeed"), 42);
74/// ```
75///
76/// # Author
77///
78/// Haixing Hu
79pub trait Callable<R, E> {
80 /// Executes the computation, borrowing `self` mutably.
81 ///
82 /// # Returns
83 ///
84 /// Returns `Ok(R)` when the computation succeeds, or `Err(E)` when it
85 /// fails. The exact error meaning is defined by the concrete callable.
86 fn call(&mut self) -> Result<R, E>;
87
88 /// Converts this callable into a boxed callable.
89 ///
90 /// # Returns
91 ///
92 /// A `BoxCallable<R, E>` that executes this callable when `call()` is
93 /// invoked.
94 fn into_box(mut self) -> BoxCallable<R, E>
95 where
96 Self: Sized + 'static,
97 {
98 BoxCallable::new(move || self.call())
99 }
100
101 /// Converts this callable into an `Rc` callable.
102 ///
103 /// # Returns
104 ///
105 /// A `RcCallable<R, E>`.
106 fn into_rc(mut self) -> RcCallable<R, E>
107 where
108 Self: Sized + 'static,
109 {
110 RcCallable::new(move || self.call())
111 }
112
113 /// Converts this callable into an `Arc` callable.
114 ///
115 /// # Returns
116 ///
117 /// An `ArcCallable<R, E>`.
118 fn into_arc(mut self) -> ArcCallable<R, E>
119 where
120 Self: Sized + Send + 'static,
121 {
122 ArcCallable::new(move || self.call())
123 }
124
125 /// Converts this callable into a mutable closure.
126 ///
127 /// # Returns
128 ///
129 /// A closure implementing `FnMut() -> Result<R, E>`.
130 fn into_fn(mut self) -> impl FnMut() -> Result<R, E>
131 where
132 Self: Sized + 'static,
133 {
134 move || self.call()
135 }
136
137 /// Converts this callable into a boxed callable without consuming `self`.
138 ///
139 /// The method clones `self` and boxes the clone. Use this for cloneable
140 /// callable values that need to be reused after boxing.
141 ///
142 /// # Returns
143 ///
144 /// A new `BoxCallable<R, E>` built from a clone of this callable.
145 fn to_box(&self) -> BoxCallable<R, E>
146 where
147 Self: Clone + Sized + 'static,
148 {
149 self.clone().into_box()
150 }
151
152 /// Converts this callable into an `Rc` callable without consuming `self`.
153 ///
154 /// The method clones `self` and wraps the clone.
155 ///
156 /// # Returns
157 ///
158 /// A `RcCallable<R, E>`.
159 fn to_rc(&self) -> RcCallable<R, E>
160 where
161 Self: Clone + Sized + 'static,
162 {
163 self.clone().into_rc()
164 }
165
166 /// Converts this callable into an `Arc` callable without consuming `self`.
167 ///
168 /// The method clones `self` and wraps the clone.
169 ///
170 /// # Returns
171 ///
172 /// An `ArcCallable<R, E>`.
173 fn to_arc(&self) -> ArcCallable<R, E>
174 where
175 Self: Clone + Send + Sized + 'static,
176 {
177 self.clone().into_arc()
178 }
179
180 /// Converts this callable into a mutable closure without consuming `self`.
181 ///
182 /// The method clones `self` and returns a closure that executes the clone
183 /// on each call.
184 ///
185 /// # Returns
186 ///
187 /// A closure implementing `FnMut() -> Result<R, E>`.
188 fn to_fn(&self) -> impl FnMut() -> Result<R, E>
189 where
190 Self: Clone + Sized + 'static,
191 {
192 self.clone().into_fn()
193 }
194
195 /// Converts this callable into a one-time callable.
196 ///
197 /// The returned callable consumes itself on each invocation.
198 ///
199 /// # Returns
200 ///
201 /// A `BoxCallableOnce<R, E>`.
202 fn into_once(mut self) -> BoxCallableOnce<R, E>
203 where
204 Self: Sized + 'static,
205 {
206 BoxCallableOnce::new(move || self.call())
207 }
208
209 /// Converts this callable into a one-time callable without consuming
210 /// `self`.
211 ///
212 /// The method clones `self` and returns a one-time callable.
213 ///
214 /// # Returns
215 ///
216 /// A `BoxCallableOnce<R, E>`.
217 fn to_once(&self) -> BoxCallableOnce<R, E>
218 where
219 Self: Clone + Sized + 'static,
220 {
221 self.clone().into_once()
222 }
223
224 /// Converts this callable into a runnable by discarding the success value.
225 ///
226 /// The returned runnable preserves errors and maps any `Ok(R)` to
227 /// `Ok(())`.
228 ///
229 /// # Returns
230 ///
231 /// A `BoxRunnable<E>` that executes this callable and discards its success
232 /// value.
233 fn into_runnable(mut self) -> BoxRunnable<E>
234 where
235 Self: Sized + 'static,
236 {
237 BoxRunnable::new(move || self.call().map(|_| ()))
238 }
239}
240
241// ============================================================================
242// BoxCallable
243// ============================================================================
244
245/// Box-based callable.
246///
247/// `BoxCallable<R, E>` stores a `Box<dyn FnMut() -> Result<R, E>>` and can be
248/// called repeatedly. It is the boxed concrete implementation of
249/// [`Callable`].
250///
251/// # Type Parameters
252///
253/// * `R` - The success value returned by the computation.
254/// * `E` - The error value returned when the computation fails.
255///
256/// # Example
257///
258/// ```rust
259/// use qubit_function::{BoxCallable, Callable};
260///
261/// let mut task = BoxCallable::new(|| Ok::<i32, String>(42));
262/// assert_eq!(task.call().expect("call should succeed"), 42);
263/// ```
264///
265/// # Author
266///
267/// Haixing Hu
268pub struct BoxCallable<R, E> {
269 /// The stateful closure executed by this callable.
270 function: Box<dyn FnMut() -> Result<R, E>>,
271 /// The optional name of this callable.
272 name: Option<String>,
273}
274
275impl<R, E> BoxCallable<R, E> {
276 impl_common_new_methods!(
277 (FnMut() -> Result<R, E> + 'static),
278 |function| Box::new(function),
279 "callable"
280 );
281
282 /// Creates a boxed callable from a reusable supplier.
283 ///
284 /// This is an explicit bridge from `Supplier<Result<R, E>>` to
285 /// `Callable<R, E>`.
286 ///
287 /// # Parameters
288 ///
289 /// * `supplier` - The supplier that produces the callable result.
290 ///
291 /// # Returns
292 ///
293 /// A new `BoxCallable<R, E>`.
294 #[inline]
295 pub fn from_supplier<S>(supplier: S) -> Self
296 where
297 S: Supplier<Result<R, E>> + 'static,
298 {
299 Self::new(move || supplier.get())
300 }
301
302 impl_common_name_methods!("callable");
303
304 /// Maps the success value of this callable.
305 ///
306 /// # Parameters
307 ///
308 /// * `mapper` - Function that transforms the success value.
309 ///
310 /// # Returns
311 ///
312 /// A new callable that applies `mapper` when this callable succeeds.
313 #[inline]
314 pub fn map<U, M>(self, mut mapper: M) -> BoxCallable<U, E>
315 where
316 M: FnMut(R) -> U + 'static,
317 R: 'static,
318 E: 'static,
319 {
320 let name = self.name;
321 let mut function = self.function;
322 BoxCallable::new_with_optional_name(move || function().map(&mut mapper), name)
323 }
324
325 /// Maps the error value of this callable.
326 ///
327 /// # Parameters
328 ///
329 /// * `mapper` - Function that transforms the error value.
330 ///
331 /// # Returns
332 ///
333 /// A new callable that applies `mapper` when this callable fails.
334 #[inline]
335 pub fn map_err<E2, M>(self, mut mapper: M) -> BoxCallable<R, E2>
336 where
337 M: FnMut(E) -> E2 + 'static,
338 R: 'static,
339 E: 'static,
340 {
341 let name = self.name;
342 let mut function = self.function;
343 BoxCallable::new_with_optional_name(move || function().map_err(&mut mapper), name)
344 }
345
346 /// Chains another fallible computation after this callable succeeds.
347 ///
348 /// # Parameters
349 ///
350 /// * `next` - Function that receives the success value and returns the next
351 /// result.
352 ///
353 /// # Returns
354 ///
355 /// A new callable that runs `next` only when this callable succeeds.
356 #[inline]
357 pub fn and_then<U, N>(self, next: N) -> BoxCallable<U, E>
358 where
359 N: FnMut(R) -> Result<U, E> + 'static,
360 R: 'static,
361 E: 'static,
362 {
363 let name = self.name;
364 let mut function = self.function;
365 let mut next = next;
366 BoxCallable::new_with_optional_name(
367 move || {
368 let value = function()?;
369 next(value)
370 },
371 name,
372 )
373 }
374}
375
376impl<R, E> Callable<R, E> for BoxCallable<R, E> {
377 /// Executes the boxed callable.
378 #[inline]
379 fn call(&mut self) -> Result<R, E> {
380 (self.function)()
381 }
382
383 impl_box_conversions!(
384 BoxCallable<R, E>,
385 RcCallable,
386 FnMut() -> Result<R, E>,
387 BoxCallableOnce
388 );
389
390 /// Converts this boxed callable into a boxed runnable while preserving its
391 /// name.
392 #[inline]
393 fn into_runnable(self) -> BoxRunnable<E>
394 where
395 Self: Sized + 'static,
396 {
397 let name = self.name;
398 let mut function = self.function;
399 BoxRunnable::new_with_optional_name(move || function().map(|_| ()), name)
400 }
401}
402
403// ============================================================================
404// RcCallable
405// ============================================================================
406
407/// Single-threaded shared callable.
408///
409/// `RcCallable<R, E>` stores a `Rc<RefCell<dyn FnMut() -> Result<R, E>>>` and
410/// can be called repeatedly through shared ownership.
411///
412/// # Type Parameters
413///
414/// * `R` - The success value returned by the computation.
415/// * `E` - The error value returned when the computation fails.
416///
417/// # Author
418///
419/// Haixing Hu
420pub struct RcCallable<R, E> {
421 /// The stateful closure executed by this callable.
422 function: Rc<RefCell<dyn FnMut() -> Result<R, E>>>,
423 /// The optional name of this callable.
424 name: Option<String>,
425}
426
427impl<R, E> Clone for RcCallable<R, E> {
428 #[inline]
429 fn clone(&self) -> Self {
430 Self {
431 function: Rc::clone(&self.function),
432 name: self.name.clone(),
433 }
434 }
435}
436
437impl<R, E> RcCallable<R, E> {
438 impl_common_new_methods!(
439 (FnMut() -> Result<R, E> + 'static),
440 |function| Rc::new(RefCell::new(function)),
441 "callable"
442 );
443
444 /// Creates an `RcCallable` from a reusable supplier.
445 ///
446 /// # Parameters
447 ///
448 /// * `supplier` - The supplier that produces the callable result.
449 ///
450 /// # Returns
451 ///
452 /// A new `RcCallable<R, E>`.
453 #[inline]
454 pub fn from_supplier<S>(supplier: S) -> Self
455 where
456 S: Supplier<Result<R, E>> + 'static,
457 {
458 Self::new(move || supplier.get())
459 }
460
461 impl_common_name_methods!("callable");
462}
463
464impl<R, E> Callable<R, E> for RcCallable<R, E> {
465 /// Executes the shared callable.
466 #[inline]
467 fn call(&mut self) -> Result<R, E> {
468 (self.function.borrow_mut())()
469 }
470
471 impl_rc_conversions!(
472 RcCallable<R, E>,
473 BoxCallable,
474 BoxCallableOnce,
475 FnMut() -> Result<R, E>
476 );
477
478 /// Converts this shared callable into a boxed runnable while preserving its
479 /// name.
480 #[inline]
481 fn into_runnable(self) -> BoxRunnable<E>
482 where
483 Self: Sized + 'static,
484 {
485 let name = self.name;
486 let function = self.function;
487 BoxRunnable::new_with_optional_name(move || (function.borrow_mut())().map(|_| ()), name)
488 }
489}
490
491// ============================================================================
492// ArcCallable
493// ============================================================================
494
495/// Thread-safe callable.
496///
497/// `ArcCallable<R, E>` stores a `Arc<Mutex<dyn FnMut() -> Result<R, E> + Send>>`
498/// and can be called repeatedly across threads.
499///
500/// # Type Parameters
501///
502/// * `R` - The success value returned by the computation.
503/// * `E` - The error value returned when the computation fails.
504///
505/// # Author
506///
507/// Haixing Hu
508pub struct ArcCallable<R, E> {
509 /// The stateful closure executed by this callable.
510 function: Arc<Mutex<dyn FnMut() -> Result<R, E> + Send>>,
511 /// The optional name of this callable.
512 name: Option<String>,
513}
514
515impl<R, E> Clone for ArcCallable<R, E> {
516 #[inline]
517 fn clone(&self) -> Self {
518 Self {
519 function: Arc::clone(&self.function),
520 name: self.name.clone(),
521 }
522 }
523}
524
525impl<R, E> ArcCallable<R, E> {
526 impl_common_new_methods!(
527 (FnMut() -> Result<R, E> + Send + 'static),
528 |function| Arc::new(Mutex::new(function)),
529 "callable"
530 );
531
532 /// Creates an `ArcCallable` from a reusable supplier.
533 ///
534 /// # Parameters
535 ///
536 /// * `supplier` - The supplier that produces the callable result.
537 ///
538 /// # Returns
539 ///
540 /// A new `ArcCallable<R, E>`.
541 #[inline]
542 pub fn from_supplier<S>(supplier: S) -> Self
543 where
544 S: Supplier<Result<R, E>> + Send + 'static,
545 {
546 Self::new(move || supplier.get())
547 }
548
549 impl_common_name_methods!("callable");
550}
551
552impl<R, E> Callable<R, E> for ArcCallable<R, E> {
553 /// Executes the thread-safe callable.
554 #[inline]
555 fn call(&mut self) -> Result<R, E> {
556 (self.function.lock())()
557 }
558
559 impl_arc_conversions!(
560 ArcCallable<R, E>,
561 BoxCallable,
562 RcCallable,
563 BoxCallableOnce,
564 FnMut() -> Result<R, E>
565 );
566
567 /// Converts this shared callable into a boxed runnable while preserving its
568 /// name.
569 #[inline]
570 fn into_runnable(self) -> BoxRunnable<E>
571 where
572 Self: Sized + 'static,
573 {
574 let name = self.name;
575 let function = self.function;
576 BoxRunnable::new_with_optional_name(move || (function.lock())().map(|_| ()), name)
577 }
578}
579
580impl_closure_trait!(
581 Callable<R, E>,
582 call,
583 BoxCallableOnce,
584 FnMut() -> Result<R, E>
585);
586
587impl_function_debug_display!(BoxCallable<R, E>);
588impl_function_debug_display!(RcCallable<R, E>);
589impl_function_debug_display!(ArcCallable<R, E>);