Skip to main content

qubit_function/transformers/transformer/
fn_transformer_ops.rs

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