Skip to main content

qubit_function/tasks/callable_with/
box_callable_with.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 `BoxCallableWith` public type.
12
13#![allow(unused_imports)]
14
15use super::*;
16
17/// Box-based callable with mutable input.
18///
19/// `BoxCallableWith<T, R, E>` stores a
20/// `Box<dyn FnMut(&mut T) -> Result<R, E>>` and can be called repeatedly.
21///
22pub struct BoxCallableWith<T, R, E> {
23    /// The stateful closure executed by this callable.
24    pub(super) function: Box<dyn FnMut(&mut T) -> Result<R, E>>,
25    /// The optional name of this callable.
26    pub(super) name: Option<String>,
27}
28
29impl<T, R, E> BoxCallableWith<T, R, E> {
30    impl_common_new_methods!(
31        (FnMut(&mut T) -> Result<R, E> + 'static),
32        |function| Box::new(function),
33        "callable-with"
34    );
35
36    impl_common_name_methods!("callable-with");
37
38    /// Maps the success value of this callable.
39    ///
40    /// # Parameters
41    ///
42    /// * `mapper` - Function that transforms the success value.
43    ///
44    /// # Returns
45    ///
46    /// A new callable with mutable input that applies `mapper` on success.
47    #[inline]
48    pub fn map<U, M>(self, mut mapper: M) -> BoxCallableWith<T, U, E>
49    where
50        M: FnMut(R) -> U + 'static,
51        T: 'static,
52        R: 'static,
53        E: 'static,
54    {
55        let name = self.name;
56        let mut function = self.function;
57        BoxCallableWith::new_with_optional_name(move |input| function(input).map(&mut mapper), name)
58    }
59
60    /// Maps the error value of this callable.
61    ///
62    /// # Parameters
63    ///
64    /// * `mapper` - Function that transforms the error value.
65    ///
66    /// # Returns
67    ///
68    /// A new callable with mutable input that applies `mapper` on failure.
69    #[inline]
70    pub fn map_err<E2, M>(self, mut mapper: M) -> BoxCallableWith<T, R, E2>
71    where
72        M: FnMut(E) -> E2 + 'static,
73        T: 'static,
74        R: 'static,
75        E: 'static,
76    {
77        let name = self.name;
78        let mut function = self.function;
79        BoxCallableWith::new_with_optional_name(
80            move |input| function(input).map_err(&mut mapper),
81            name,
82        )
83    }
84
85    /// Chains another fallible computation after this callable succeeds.
86    ///
87    /// # Parameters
88    ///
89    /// * `next` - Function receiving the success value and mutable input.
90    ///
91    /// # Returns
92    ///
93    /// A new callable that runs `next` only when this callable succeeds.
94    #[inline]
95    pub fn and_then<U, N>(self, next: N) -> BoxCallableWith<T, U, E>
96    where
97        N: FnMut(R, &mut T) -> Result<U, E> + 'static,
98        T: 'static,
99        R: 'static,
100        E: 'static,
101    {
102        let name = self.name;
103        let mut function = self.function;
104        let mut next = next;
105        BoxCallableWith::new_with_optional_name(
106            move |input| {
107                let value = function(input)?;
108                next(value, input)
109            },
110            name,
111        )
112    }
113}
114
115impl<T, R, E> CallableWith<T, R, E> for BoxCallableWith<T, R, E> {
116    /// Executes the boxed callable with mutable input.
117    #[inline]
118    fn call_with(&mut self, input: &mut T) -> Result<R, E> {
119        (self.function)(input)
120    }
121
122    impl_box_conversions!(
123        BoxCallableWith<T, R, E>,
124        RcCallableWith,
125        FnMut(&mut T) -> Result<R, E>
126    );
127
128    /// Converts this boxed callable into a boxed runnable while preserving its
129    /// name.
130    #[inline]
131    fn into_runnable_with(self) -> BoxRunnableWith<T, E>
132    where
133        Self: Sized + 'static,
134    {
135        let name = self.name;
136        let mut function = self.function;
137        BoxRunnableWith::new_with_optional_name(move |input| function(input).map(|_| ()), name)
138    }
139}