Skip to main content

qubit_function/transformers/transformer/
fn_transformer_ops.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 `FnTransformerOps` public type.
12
13#![allow(unused_imports)]
14
15use super::*;
16
17// ============================================================================
18// FnTransformerOps - Extension trait for closure transformers
19// ============================================================================
20
21/// Extension trait for closures implementing `Fn(T) -> R`
22///
23/// Provides composition methods (`and_then`, `compose`, `when`) for closures
24/// and function pointers without requiring explicit wrapping in
25/// `BoxTransformer`, `RcTransformer`, or `ArcTransformer`.
26///
27/// This trait is automatically implemented for all closures and function
28/// pointers that implement `Fn(T) -> R`.
29///
30/// # Design Rationale
31///
32/// While closures automatically implement `Transformer<T, R>` through blanket
33/// implementation, they don't have access to instance methods like `and_then`,
34/// `compose`, and `when`. This extension trait provides those methods,
35/// returning `BoxTransformer` for maximum flexibility.
36///
37/// # Examples
38///
39/// ## Chain composition with and_then
40///
41/// ```rust
42/// use qubit_function::{Transformer, FnTransformerOps};
43///
44/// let double = |x: i32| x * 2;
45/// let to_string = |x: i32| x.to_string();
46///
47/// let composed = double.and_then(to_string);
48/// assert_eq!(composed.apply(21), "42");
49/// ```
50///
51/// ## Reverse composition with compose
52///
53/// ```rust
54/// use qubit_function::{Transformer, FnTransformerOps};
55///
56/// let double = |x: i32| x * 2;
57/// let add_one = |x: i32| x + 1;
58///
59/// let composed = double.compose(add_one);
60/// assert_eq!(composed.apply(5), 12); // (5 + 1) * 2
61/// ```
62///
63/// ## Conditional transformation with when
64///
65/// ```rust
66/// use qubit_function::{Transformer, FnTransformerOps};
67///
68/// let double = |x: i32| x * 2;
69/// let conditional = double.when(|x: &i32| *x > 0).or_else(|x: i32| -x);
70///
71/// assert_eq!(conditional.apply(5), 10);
72/// assert_eq!(conditional.apply(-5), 5);
73/// ```
74///
75pub trait FnTransformerOps<T, R>: Fn(T) -> R + Sized {
76    /// Chain composition - applies self first, then after
77    ///
78    /// Creates a new transformer that applies this transformer first, then
79    /// applies the after transformer to the result. Consumes self and returns
80    /// a `BoxTransformer`.
81    ///
82    /// # Type Parameters
83    ///
84    /// * `S` - The output type of the after transformer
85    /// * `F` - The type of the after transformer (must implement Transformer<R, S>)
86    ///
87    /// # Parameters
88    ///
89    /// * `after` - The transformer to apply after self. **Note: This parameter
90    ///   is passed by value and will transfer ownership.** If you need to
91    ///   preserve the original transformer, clone it first (if it implements
92    ///   `Clone`). Can be:
93    ///   - A closure: `|x: R| -> S`
94    ///   - A function pointer: `fn(R) -> S`
95    ///   - A `BoxTransformer<R, S>`
96    ///   - An `RcTransformer<R, S>`
97    ///   - An `ArcTransformer<R, S>`
98    ///   - Any type implementing `Transformer<R, S>`
99    ///
100    /// # Returns
101    ///
102    /// A new `BoxTransformer<T, S>` representing the composition
103    ///
104    /// # Examples
105    ///
106    /// ## Direct value passing (ownership transfer)
107    ///
108    /// ```rust
109    /// use qubit_function::{Transformer, FnTransformerOps, BoxTransformer};
110    ///
111    /// let double = |x: i32| x * 2;
112    /// let to_string = BoxTransformer::new(|x: i32| x.to_string());
113    ///
114    /// // to_string is moved here
115    /// let composed = double.and_then(to_string);
116    /// assert_eq!(composed.apply(21), "42");
117    /// // to_string.apply(5); // Would not compile - moved
118    /// ```
119    ///
120    /// ## Preserving original with separate closures
121    ///
122    /// ```rust
123    /// use qubit_function::{Transformer, FnTransformerOps};
124    ///
125    /// let double = |x: i32| x * 2;
126    /// let to_string = |x: i32| x.to_string();
127    /// let to_string_for_validation = |x: i32| x.to_string();
128    ///
129    /// let composed = double.and_then(to_string);
130    /// assert_eq!(composed.apply(21), "42");
131    ///
132    /// // Original still usable
133    /// assert_eq!(to_string_for_validation(5), "5");
134    /// ```
135    fn and_then<S, F>(self, after: F) -> BoxTransformer<T, S>
136    where
137        Self: 'static,
138        S: 'static,
139        F: Transformer<R, S> + 'static,
140        T: 'static,
141        R: 'static,
142    {
143        BoxTransformer::new(move |x: T| after.apply(self(x)))
144    }
145
146    /// Reverse composition - applies before first, then self
147    ///
148    /// Creates a new transformer that applies the before transformer first,
149    /// then applies this transformer to the result. Consumes self and returns
150    /// a `BoxTransformer`.
151    ///
152    /// # Type Parameters
153    ///
154    /// * `S` - The input type of the before transformer
155    /// * `F` - The type of the before transformer (must implement Transformer<S, T>)
156    ///
157    /// # Parameters
158    ///
159    /// * `before` - The transformer to apply before self. **Note: This parameter
160    ///   is passed by value and will transfer ownership.** If you need to
161    ///   preserve the original transformer, clone it first (if it implements
162    ///   `Clone`). Can be:
163    ///   - A closure: `|x: S| -> T`
164    ///   - A function pointer: `fn(S) -> T`
165    ///   - A `BoxTransformer<S, T>`
166    ///   - An `RcTransformer<S, T>`
167    ///   - An `ArcTransformer<S, T>`
168    ///   - Any type implementing `Transformer<S, T>`
169    ///
170    /// # Returns
171    ///
172    /// A new `BoxTransformer<S, R>` representing the composition
173    ///
174    /// # Examples
175    ///
176    /// ## Direct value passing (ownership transfer)
177    ///
178    /// ```rust
179    /// use qubit_function::{Transformer, FnTransformerOps, BoxTransformer};
180    ///
181    /// let double = |x: i32| x * 2;
182    /// let add_one = BoxTransformer::new(|x: i32| x + 1);
183    ///
184    /// // add_one is moved here
185    /// let composed = double.compose(add_one);
186    /// assert_eq!(composed.apply(5), 12); // (5 + 1) * 2
187    /// // add_one.apply(3); // Would not compile - moved
188    /// ```
189    ///
190    /// ## Preserving original with separate closures
191    ///
192    /// ```rust
193    /// use qubit_function::{Transformer, FnTransformerOps};
194    ///
195    /// let double = |x: i32| x * 2;
196    /// let add_one = |x: i32| x + 1;
197    /// let add_one_for_validation = |x: i32| x + 1;
198    ///
199    /// let composed = double.compose(add_one);
200    /// assert_eq!(composed.apply(5), 12); // (5 + 1) * 2
201    ///
202    /// // Original still usable
203    /// assert_eq!(add_one_for_validation(3), 4);
204    /// ```
205    fn compose<S, F>(self, before: F) -> BoxTransformer<S, R>
206    where
207        Self: 'static,
208        S: 'static,
209        F: Transformer<S, T> + 'static,
210        T: 'static,
211        R: 'static,
212    {
213        BoxTransformer::new(move |x: S| self(before.apply(x)))
214    }
215
216    /// Creates a conditional transformer
217    ///
218    /// Returns a transformer that only executes when a predicate is satisfied.
219    /// You must call `or_else()` to provide an alternative transformer for when
220    /// the condition is not satisfied.
221    ///
222    /// # Parameters
223    ///
224    /// * `predicate` - The condition to check. **Note: This parameter is passed
225    ///   by value and will transfer ownership.** If you need to preserve the
226    ///   original predicate, clone it first (if it implements `Clone`). Can be:
227    ///   - A closure: `|x: &T| -> bool`
228    ///   - A function pointer: `fn(&T) -> bool`
229    ///   - A `BoxPredicate<T>`
230    ///   - An `RcPredicate<T>`
231    ///   - An `ArcPredicate<T>`
232    ///   - Any type implementing `Predicate<T>`
233    ///
234    /// # Returns
235    ///
236    /// Returns `BoxConditionalTransformer<T, R>`
237    ///
238    /// # Examples
239    ///
240    /// ## Basic usage with or_else
241    ///
242    /// ```rust
243    /// use qubit_function::{Transformer, FnTransformerOps};
244    ///
245    /// let double = |x: i32| x * 2;
246    /// let conditional = double.when(|x: &i32| *x > 0).or_else(|x: i32| -x);
247    ///
248    /// assert_eq!(conditional.apply(5), 10);
249    /// assert_eq!(conditional.apply(-5), 5);
250    /// ```
251    ///
252    /// ## Preserving original with separate predicates
253    ///
254    /// ```rust
255    /// use qubit_function::{Transformer, FnTransformerOps};
256    ///
257    /// let double = |x: i32| x * 2;
258    /// let is_positive = |x: &i32| *x > 0;
259    /// let is_positive_for_validation = |x: &i32| *x > 0;
260    /// let conditional = double.when(is_positive)
261    ///     .or_else(|x: i32| -x);
262    ///
263    /// assert_eq!(conditional.apply(5), 10);
264    ///
265    /// // Original predicate still usable
266    /// assert!(is_positive_for_validation(&3));
267    /// ```
268    fn when<P>(self, predicate: P) -> BoxConditionalTransformer<T, R>
269    where
270        Self: 'static,
271        P: Predicate<T> + 'static,
272        T: 'static,
273        R: 'static,
274    {
275        BoxTransformer::new(self).when(predicate)
276    }
277}
278
279/// Blanket implementation of FnTransformerOps for all closures
280///
281/// Automatically implements `FnTransformerOps<T, R>` for any type that
282/// implements `Fn(T) -> R`.
283///
284impl<T, R, F> FnTransformerOps<T, R> for F where F: Fn(T) -> R {}