Skip to main content

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