Skip to main content

qubit_function/tasks/callable/
arc_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// qubit-style: allow explicit-imports
11//! Defines the `ArcCallable` public type.
12
13use std::sync::Arc;
14
15use parking_lot::Mutex;
16
17use crate::{
18    functions::macros::impl_function_debug_display,
19    macros::{
20        impl_arc_conversions,
21        impl_closure_trait,
22        impl_common_name_methods,
23        impl_common_new_methods,
24    },
25    suppliers::supplier::Supplier,
26    tasks::{
27        callable::{
28            BoxCallable,
29            Callable,
30            RcCallable,
31        },
32        callable_once::{
33            BoxCallableOnce,
34            LocalBoxCallableOnce,
35        },
36        runnable::BoxRunnable,
37    },
38};
39
40// ============================================================================
41// ArcCallable
42// ============================================================================
43
44/// Thread-safe callable.
45///
46/// `ArcCallable<R, E>` stores a `Arc<Mutex<dyn FnMut() -> Result<R, E> + Send>>`
47/// and can be called repeatedly across threads.
48///
49/// # Type Parameters
50///
51/// * `R` - The success value returned by the computation.
52/// * `E` - The error value returned when the computation fails.
53///
54pub struct ArcCallable<R, E> {
55    /// The stateful closure executed by this callable.
56    pub(super) function: Arc<Mutex<dyn FnMut() -> Result<R, E> + Send>>,
57    /// The optional name of this callable.
58    pub(super) name: Option<String>,
59}
60
61impl<R, E> Clone for ArcCallable<R, E> {
62    #[inline]
63    fn clone(&self) -> Self {
64        Self {
65            function: Arc::clone(&self.function),
66            name: self.name.clone(),
67        }
68    }
69}
70
71impl<R, E> ArcCallable<R, E> {
72    impl_common_new_methods!(
73        (FnMut() -> Result<R, E> + Send + 'static),
74        |function| Arc::new(Mutex::new(function)),
75        "callable"
76    );
77
78    /// Creates an `ArcCallable` from a reusable supplier.
79    ///
80    /// # Parameters
81    ///
82    /// * `supplier` - The supplier that produces the callable result.
83    ///
84    /// # Returns
85    ///
86    /// A new `ArcCallable<R, E>`.
87    #[inline]
88    pub fn from_supplier<S>(supplier: S) -> Self
89    where
90        S: Supplier<Result<R, E>> + Send + 'static,
91    {
92        Self::new(move || supplier.get())
93    }
94
95    impl_common_name_methods!("callable");
96}
97
98impl<R, E> Callable<R, E> for ArcCallable<R, E> {
99    /// Executes the thread-safe callable.
100    #[inline]
101    fn call(&mut self) -> Result<R, E> {
102        (self.function.lock())()
103    }
104
105    impl_arc_conversions!(
106        ArcCallable<R, E>,
107        BoxCallable,
108        RcCallable,
109        BoxCallableOnce,
110        FnMut() -> Result<R, E>
111    );
112
113    /// Converts this shared callable into a local boxed one-time callable while
114    /// preserving its name.
115    #[inline]
116    fn into_local_once(self) -> LocalBoxCallableOnce<R, E>
117    where
118        Self: Sized + 'static,
119    {
120        let name = self.name;
121        let function = self.function;
122        LocalBoxCallableOnce::new_with_optional_name(move || (function.lock())(), name)
123    }
124
125    /// Converts this shared callable into a local boxed one-time callable
126    /// without consuming `self`.
127    #[inline]
128    fn to_local_once(&self) -> LocalBoxCallableOnce<R, E>
129    where
130        Self: Clone + Sized + 'static,
131    {
132        self.clone().into_local_once()
133    }
134
135    /// Converts this shared callable into a boxed runnable while preserving its
136    /// name.
137    #[inline]
138    fn into_runnable(self) -> BoxRunnable<E>
139    where
140        Self: Sized + 'static,
141    {
142        let name = self.name;
143        let function = self.function;
144        BoxRunnable::new_with_optional_name(move || (function.lock())().map(|_| ()), name)
145    }
146}
147
148impl_closure_trait!(
149    Callable<R, E>,
150    call,
151    FnMut() -> Result<R, E>
152);
153
154impl_function_debug_display!(BoxCallable<R, E>);
155impl_function_debug_display!(RcCallable<R, E>);
156impl_function_debug_display!(ArcCallable<R, E>);