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}