qubit_function/tasks/callable_with.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # CallableWith Types
10//!
11//! Provides fallible, reusable computations that operate on a mutable input.
12//!
13//! A `CallableWith<T, R, E>` is equivalent to
14//! `FnMut(&mut T) -> Result<R, E>`, but uses task-oriented vocabulary. Use it
15//! when the operation needs access to protected or caller-provided state and
16//! returns a success value.
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 tasks::runnable_with::BoxRunnableWith,
42};
43
44/// A fallible, reusable computation that receives mutable input.
45///
46/// Conceptually this is `FnMut(&mut T) -> Result<R, E>` with task-oriented
47/// naming. It is useful for executor-style APIs that run a task with access to
48/// protected state, such as a value held under a lock.
49///
50/// # Type Parameters
51///
52/// * `T` - The mutable input type.
53/// * `R` - The success value returned by the computation.
54/// * `E` - The error value returned when the computation fails.
55///
56/// # Author
57///
58/// Haixing Hu
59pub trait CallableWith<T, R, E> {
60 /// Executes the computation with mutable input.
61 ///
62 /// # Parameters
63 ///
64 /// * `input` - The mutable input passed to this task.
65 ///
66 /// # Returns
67 ///
68 /// Returns `Ok(R)` when the computation succeeds, or `Err(E)` when it
69 /// fails. The exact error meaning is defined by the concrete callable.
70 fn call_with(&mut self, input: &mut T) -> Result<R, E>;
71
72 /// Converts this callable into a boxed callable.
73 ///
74 /// # Returns
75 ///
76 /// A `BoxCallableWith<T, R, E>`.
77 fn into_box(mut self) -> BoxCallableWith<T, R, E>
78 where
79 Self: Sized + 'static,
80 {
81 BoxCallableWith::new(move |input| self.call_with(input))
82 }
83
84 /// Converts this callable into an `Rc` callable.
85 ///
86 /// # Returns
87 ///
88 /// A `RcCallableWith<T, R, E>`.
89 fn into_rc(mut self) -> RcCallableWith<T, R, E>
90 where
91 Self: Sized + 'static,
92 {
93 RcCallableWith::new(move |input| self.call_with(input))
94 }
95
96 /// Converts this callable into an `Arc` callable.
97 ///
98 /// # Returns
99 ///
100 /// An `ArcCallableWith<T, R, E>`.
101 fn into_arc(mut self) -> ArcCallableWith<T, R, E>
102 where
103 Self: Sized + Send + 'static,
104 {
105 ArcCallableWith::new(move |input| self.call_with(input))
106 }
107
108 /// Converts this callable into a mutable closure.
109 ///
110 /// # Returns
111 ///
112 /// A closure implementing `FnMut(&mut T) -> Result<R, E>`.
113 fn into_fn(mut self) -> impl FnMut(&mut T) -> Result<R, E>
114 where
115 Self: Sized + 'static,
116 {
117 move |input| self.call_with(input)
118 }
119
120 /// Converts this callable into a boxed callable without consuming `self`.
121 ///
122 /// # Returns
123 ///
124 /// A `BoxCallableWith<T, R, E>` built from a clone of this callable.
125 fn to_box(&self) -> BoxCallableWith<T, R, E>
126 where
127 Self: Clone + Sized + 'static,
128 {
129 self.clone().into_box()
130 }
131
132 /// Converts this callable into an `Rc` callable without consuming `self`.
133 ///
134 /// # Returns
135 ///
136 /// A `RcCallableWith<T, R, E>` built from a clone of this callable.
137 fn to_rc(&self) -> RcCallableWith<T, R, E>
138 where
139 Self: Clone + Sized + 'static,
140 {
141 self.clone().into_rc()
142 }
143
144 /// Converts this callable into an `Arc` callable without consuming `self`.
145 ///
146 /// # Returns
147 ///
148 /// An `ArcCallableWith<T, R, E>` built from a clone of this callable.
149 fn to_arc(&self) -> ArcCallableWith<T, R, E>
150 where
151 Self: Clone + Send + Sized + 'static,
152 {
153 self.clone().into_arc()
154 }
155
156 /// Converts this callable into a mutable closure without consuming `self`.
157 ///
158 /// # Returns
159 ///
160 /// A closure implementing `FnMut(&mut T) -> Result<R, E>`.
161 fn to_fn(&self) -> impl FnMut(&mut T) -> Result<R, E>
162 where
163 Self: Clone + Sized + 'static,
164 {
165 self.clone().into_fn()
166 }
167
168 /// Converts this callable into a runnable by discarding the success value.
169 ///
170 /// # Returns
171 ///
172 /// A `BoxRunnableWith<T, E>` preserving errors and mapping success to unit.
173 fn into_runnable_with(mut self) -> BoxRunnableWith<T, E>
174 where
175 Self: Sized + 'static,
176 {
177 BoxRunnableWith::new(move |input| self.call_with(input).map(|_| ()))
178 }
179}
180
181/// Box-based callable with mutable input.
182///
183/// `BoxCallableWith<T, R, E>` stores a
184/// `Box<dyn FnMut(&mut T) -> Result<R, E>>` and can be called repeatedly.
185///
186/// # Author
187///
188/// Haixing Hu
189pub struct BoxCallableWith<T, R, E> {
190 /// The stateful closure executed by this callable.
191 function: Box<dyn FnMut(&mut T) -> Result<R, E>>,
192 /// The optional name of this callable.
193 name: Option<String>,
194}
195
196impl<T, R, E> BoxCallableWith<T, R, E> {
197 impl_common_new_methods!(
198 (FnMut(&mut T) -> Result<R, E> + 'static),
199 |function| Box::new(function),
200 "callable-with"
201 );
202
203 impl_common_name_methods!("callable-with");
204
205 /// Maps the success value of this callable.
206 ///
207 /// # Parameters
208 ///
209 /// * `mapper` - Function that transforms the success value.
210 ///
211 /// # Returns
212 ///
213 /// A new callable with mutable input that applies `mapper` on success.
214 #[inline]
215 pub fn map<U, M>(self, mut mapper: M) -> BoxCallableWith<T, U, E>
216 where
217 M: FnMut(R) -> U + 'static,
218 T: 'static,
219 R: 'static,
220 E: 'static,
221 {
222 let name = self.name;
223 let mut function = self.function;
224 BoxCallableWith::new_with_optional_name(move |input| function(input).map(&mut mapper), name)
225 }
226
227 /// Maps the error value of this callable.
228 ///
229 /// # Parameters
230 ///
231 /// * `mapper` - Function that transforms the error value.
232 ///
233 /// # Returns
234 ///
235 /// A new callable with mutable input that applies `mapper` on failure.
236 #[inline]
237 pub fn map_err<E2, M>(self, mut mapper: M) -> BoxCallableWith<T, R, E2>
238 where
239 M: FnMut(E) -> E2 + 'static,
240 T: 'static,
241 R: 'static,
242 E: 'static,
243 {
244 let name = self.name;
245 let mut function = self.function;
246 BoxCallableWith::new_with_optional_name(
247 move |input| function(input).map_err(&mut mapper),
248 name,
249 )
250 }
251
252 /// Chains another fallible computation after this callable succeeds.
253 ///
254 /// # Parameters
255 ///
256 /// * `next` - Function receiving the success value and mutable input.
257 ///
258 /// # Returns
259 ///
260 /// A new callable that runs `next` only when this callable succeeds.
261 #[inline]
262 pub fn and_then<U, N>(self, next: N) -> BoxCallableWith<T, U, E>
263 where
264 N: FnMut(R, &mut T) -> Result<U, E> + 'static,
265 T: 'static,
266 R: 'static,
267 E: 'static,
268 {
269 let name = self.name;
270 let mut function = self.function;
271 let mut next = next;
272 BoxCallableWith::new_with_optional_name(
273 move |input| {
274 let value = function(input)?;
275 next(value, input)
276 },
277 name,
278 )
279 }
280}
281
282impl<T, R, E> CallableWith<T, R, E> for BoxCallableWith<T, R, E> {
283 /// Executes the boxed callable with mutable input.
284 #[inline]
285 fn call_with(&mut self, input: &mut T) -> Result<R, E> {
286 (self.function)(input)
287 }
288
289 impl_box_conversions!(
290 BoxCallableWith<T, R, E>,
291 RcCallableWith,
292 FnMut(&mut T) -> Result<R, E>
293 );
294
295 /// Converts this boxed callable into a boxed runnable while preserving its
296 /// name.
297 #[inline]
298 fn into_runnable_with(self) -> BoxRunnableWith<T, E>
299 where
300 Self: Sized + 'static,
301 {
302 let name = self.name;
303 let mut function = self.function;
304 BoxRunnableWith::new_with_optional_name(move |input| function(input).map(|_| ()), name)
305 }
306}
307
308/// Single-threaded shared callable with mutable input.
309///
310/// `RcCallableWith<T, R, E>` stores a
311/// `Rc<RefCell<dyn FnMut(&mut T) -> Result<R, E>>>`.
312///
313/// # Author
314///
315/// Haixing Hu
316pub struct RcCallableWith<T, R, E> {
317 /// The stateful closure executed by this callable.
318 function: Rc<RefCell<dyn FnMut(&mut T) -> Result<R, E>>>,
319 /// The optional name of this callable.
320 name: Option<String>,
321}
322
323impl<T, R, E> Clone for RcCallableWith<T, R, E> {
324 #[inline]
325 fn clone(&self) -> Self {
326 Self {
327 function: Rc::clone(&self.function),
328 name: self.name.clone(),
329 }
330 }
331}
332
333impl<T, R, E> RcCallableWith<T, R, E> {
334 impl_common_new_methods!(
335 (FnMut(&mut T) -> Result<R, E> + 'static),
336 |function| Rc::new(RefCell::new(function)),
337 "callable-with"
338 );
339
340 impl_common_name_methods!("callable-with");
341}
342
343impl<T, R, E> CallableWith<T, R, E> for RcCallableWith<T, R, E> {
344 /// Executes the shared callable with mutable input.
345 #[inline]
346 fn call_with(&mut self, input: &mut T) -> Result<R, E> {
347 (self.function.borrow_mut())(input)
348 }
349
350 impl_rc_conversions!(
351 RcCallableWith<T, R, E>,
352 BoxCallableWith,
353 FnMut(input: &mut T) -> Result<R, E>
354 );
355
356 /// Converts this shared callable into a boxed runnable while preserving its
357 /// name.
358 #[inline]
359 fn into_runnable_with(self) -> BoxRunnableWith<T, E>
360 where
361 Self: Sized + 'static,
362 {
363 let name = self.name;
364 let function = self.function;
365 BoxRunnableWith::new_with_optional_name(
366 move |input| (function.borrow_mut())(input).map(|_| ()),
367 name,
368 )
369 }
370}
371
372/// Thread-safe shared callable with mutable input.
373///
374/// `ArcCallableWith<T, R, E>` stores an
375/// `Arc<Mutex<dyn FnMut(&mut T) -> Result<R, E> + Send>>`.
376///
377/// # Author
378///
379/// Haixing Hu
380pub struct ArcCallableWith<T, R, E> {
381 /// The stateful closure executed by this callable.
382 function: Arc<Mutex<dyn FnMut(&mut T) -> Result<R, E> + Send>>,
383 /// The optional name of this callable.
384 name: Option<String>,
385}
386
387impl<T, R, E> Clone for ArcCallableWith<T, R, E> {
388 #[inline]
389 fn clone(&self) -> Self {
390 Self {
391 function: Arc::clone(&self.function),
392 name: self.name.clone(),
393 }
394 }
395}
396
397impl<T, R, E> ArcCallableWith<T, R, E> {
398 impl_common_new_methods!(
399 (FnMut(&mut T) -> Result<R, E> + Send + 'static),
400 |function| Arc::new(Mutex::new(function)),
401 "callable-with"
402 );
403
404 impl_common_name_methods!("callable-with");
405}
406
407impl<T, R, E> CallableWith<T, R, E> for ArcCallableWith<T, R, E> {
408 /// Executes the thread-safe callable with mutable input.
409 #[inline]
410 fn call_with(&mut self, input: &mut T) -> Result<R, E> {
411 (self.function.lock())(input)
412 }
413
414 impl_arc_conversions!(
415 ArcCallableWith<T, R, E>,
416 BoxCallableWith,
417 RcCallableWith,
418 FnMut(input: &mut T) -> Result<R, E>
419 );
420
421 /// Converts this shared callable into a boxed runnable while preserving its
422 /// name.
423 #[inline]
424 fn into_runnable_with(self) -> BoxRunnableWith<T, E>
425 where
426 Self: Sized + 'static,
427 {
428 let name = self.name;
429 let function = self.function;
430 BoxRunnableWith::new_with_optional_name(
431 move |input| (function.lock())(input).map(|_| ()),
432 name,
433 )
434 }
435}
436
437impl_closure_trait!(
438 CallableWith<T, R, E>,
439 call_with,
440 FnMut(input: &mut T) -> Result<R, E>
441);
442
443impl_function_debug_display!(BoxCallableWith<T, R, E>);
444impl_function_debug_display!(RcCallableWith<T, R, E>);
445impl_function_debug_display!(ArcCallableWith<T, R, E>);