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