Skip to main content

qubit_function/transformers/
bi_transformer_once.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # BiTransformerOnce Types
10//!
11//! Provides Rust implementations of consuming bi-transformer traits similar to
12//! Rust's `FnOnce` trait, but with value-oriented semantics for functional
13//! programming patterns with two inputs.
14//!
15//! This module provides the `BiTransformerOnce<T, U, R>` trait and one-time use
16//! implementations:
17//!
18//! - [`BoxBiTransformerOnce`]: Single ownership, one-time use
19//!
20//! # Author
21//!
22//! Haixing Hu
23use crate::macros::{
24    impl_box_once_conversions,
25    impl_closure_once_trait,
26};
27use crate::predicates::bi_predicate::{
28    BiPredicate,
29    BoxBiPredicate,
30};
31use crate::transformers::{
32    macros::{
33        impl_box_conditional_transformer,
34        impl_box_transformer_methods,
35        impl_conditional_transformer_debug_display,
36        impl_transformer_common_methods,
37        impl_transformer_constant_method,
38        impl_transformer_debug_display,
39    },
40    transformer_once::TransformerOnce,
41};
42
43// ============================================================================
44// Core Trait
45// ============================================================================
46
47/// BiTransformerOnce trait - consuming bi-transformation that takes ownership
48///
49/// Defines the behavior of a consuming bi-transformer: converting two values of
50/// types `T` and `U` to a value of type `R` by taking ownership of self and
51/// both inputs. This trait is analogous to `FnOnce(T, U) -> R`.
52///
53/// # Type Parameters
54///
55/// * `T` - The type of the first input value (consumed)
56/// * `U` - The type of the second input value (consumed)
57/// * `R` - The type of the output value
58///
59/// # Author
60///
61/// Haixing Hu
62pub trait BiTransformerOnce<T, U, R> {
63    /// Transforms two input values, consuming self and both inputs
64    ///
65    /// # Parameters
66    ///
67    /// * `first` - The first input value (consumed)
68    /// * `second` - The second input value (consumed)
69    ///
70    /// # Returns
71    ///
72    /// The transformed output value
73    fn apply(self, first: T, second: U) -> R;
74
75    /// Converts to BoxBiTransformerOnce
76    ///
77    /// **⚠️ Consumes `self`**: The original bi-transformer becomes unavailable
78    /// after calling this method.
79    ///
80    /// # Returns
81    ///
82    /// Returns `BoxBiTransformerOnce<T, U, R>`
83    fn into_box(self) -> BoxBiTransformerOnce<T, U, R>
84    where
85        Self: Sized + 'static,
86        T: 'static,
87        U: 'static,
88        R: 'static,
89    {
90        BoxBiTransformerOnce::new(move |t: T, u: U| self.apply(t, u))
91    }
92
93    /// Converts bi-transformer to a closure
94    ///
95    /// **⚠️ Consumes `self`**: The original bi-transformer becomes unavailable
96    /// after calling this method.
97    ///
98    /// # Returns
99    ///
100    /// Returns a closure that implements `FnOnce(T, U) -> R`
101    fn into_fn(self) -> impl FnOnce(T, U) -> R
102    where
103        Self: Sized + 'static,
104    {
105        move |t: T, u: U| self.apply(t, u)
106    }
107
108    /// Converts bi-transformer to a boxed function pointer
109    ///
110    /// **📌 Borrows `&self`**: The original bi-transformer remains usable
111    /// after calling this method.
112    ///
113    /// # Returns
114    ///
115    /// Returns a boxed function pointer that implements `FnOnce(T, U) -> R`
116    ///
117    /// # Examples
118    ///
119    /// ```rust
120    /// use qubit_function::BiTransformerOnce;
121    ///
122    /// let add = |x: i32, y: i32| x + y;
123    /// let func = add.to_fn();
124    /// assert_eq!(func(20, 22), 42);
125    /// ```
126    fn to_box(&self) -> BoxBiTransformerOnce<T, U, R>
127    where
128        Self: Clone + 'static,
129        T: 'static,
130        U: 'static,
131        R: 'static,
132    {
133        self.clone().into_box()
134    }
135
136    /// Converts bi-transformer to a closure
137    ///
138    /// **📌 Borrows `&self`**: The original bi-transformer remains usable
139    /// after calling this method.
140    ///
141    /// # Returns
142    ///
143    /// Returns a closure that implements `FnOnce(T, U) -> R`
144    ///
145    /// # Examples
146    ///
147    /// ```rust
148    /// use qubit_function::BiTransformerOnce;
149    ///
150    /// let add = |x: i32, y: i32| x + y;
151    /// let func = add.to_fn();
152    /// assert_eq!(func(20, 22), 42);
153    /// ```
154    fn to_fn(&self) -> impl FnOnce(T, U) -> R
155    where
156        Self: Clone + 'static,
157    {
158        self.clone().into_fn()
159    }
160}
161
162// ============================================================================
163// BoxBiTransformerOnce - Box<dyn FnOnce(T, U) -> R>
164// ============================================================================
165
166/// BoxBiTransformerOnce - consuming bi-transformer wrapper based on
167/// `Box<dyn FnOnce>`
168///
169/// A bi-transformer wrapper that provides single ownership with one-time use
170/// semantics. Consumes self and both input values.
171///
172/// # Features
173///
174/// - **Based on**: `Box<dyn FnOnce(T, U) -> R>`
175/// - **Ownership**: Single ownership, cannot be cloned
176/// - **Reusability**: Can only be called once (consumes self and inputs)
177/// - **Thread Safety**: Not thread-safe (no `Send + Sync` requirement)
178///
179/// # Author
180///
181/// Haixing Hu
182pub struct BoxBiTransformerOnce<T, U, R> {
183    function: Box<dyn FnOnce(T, U) -> R>,
184    name: Option<String>,
185}
186
187// Implement BoxBiTransformerOnce
188impl<T, U, R> BoxBiTransformerOnce<T, U, R> {
189    impl_transformer_common_methods!(
190        BoxBiTransformerOnce<T, U, R>,
191        (FnOnce(T, U) -> R + 'static),
192        |f| Box::new(f)
193    );
194
195    impl_box_transformer_methods!(
196        BoxBiTransformerOnce<T, U, R>,
197        BoxConditionalBiTransformerOnce,
198        TransformerOnce
199    );
200}
201
202// Implement BiTransformerOnce trait for BoxBiTransformerOnce
203impl<T, U, R> BiTransformerOnce<T, U, R> for BoxBiTransformerOnce<T, U, R> {
204    fn apply(self, first: T, second: U) -> R {
205        (self.function)(first, second)
206    }
207
208    impl_box_once_conversions!(
209        BoxBiTransformerOnce<T, U, R>,
210        BiTransformerOnce,
211        FnOnce(T, U) -> R
212    );
213}
214
215// Implement constant method for BoxBiTransformerOnce
216impl_transformer_constant_method!(BoxBiTransformerOnce<T, U, R>);
217
218// Use macro to generate Debug and Display implementations
219impl_transformer_debug_display!(BoxBiTransformerOnce<T, U, R>);
220
221// ============================================================================
222// Blanket implementation for standard FnOnce trait
223// ============================================================================
224
225// Implement BiTransformerOnce for all FnOnce(T, U) -> R using macro
226impl_closure_once_trait!(
227    BiTransformerOnce<T, U, R>,
228    apply,
229    BoxBiTransformerOnce,
230    FnOnce(first: T, second: U) -> R
231);
232
233// ============================================================================
234// FnBiTransformerOnceOps - Extension trait for FnOnce(T, U) -> R bi-transformers
235// ============================================================================
236
237/// Extension trait for closures implementing `FnOnce(T, U) -> R`
238///
239/// Provides composition methods (`and_then`, `when`) for one-time use
240/// bi-transformer closures and function pointers without requiring explicit
241/// wrapping in `BoxBiTransformerOnce`.
242///
243/// This trait is automatically implemented for all closures and function
244/// pointers that implement `FnOnce(T, U) -> R`.
245///
246/// # Design Rationale
247///
248/// While closures automatically implement `BiTransformerOnce<T, U, R>` through
249/// blanket implementation, they don't have access to instance methods like
250/// `and_then` and `when`. This extension trait provides those methods,
251/// returning `BoxBiTransformerOnce` for maximum flexibility.
252///
253/// # Examples
254///
255/// ## Chain composition with and_then
256///
257/// ```rust
258/// use qubit_function::{BiTransformerOnce, FnBiTransformerOnceOps};
259///
260/// let add = |x: i32, y: i32| x + y;
261/// let double = |x: i32| x * 2;
262///
263/// let composed = add.and_then(double);
264/// assert_eq!(composed.apply(3, 5), 16); // (3 + 5) * 2
265/// ```
266///
267/// ## Conditional execution with when
268///
269/// ```rust
270/// use qubit_function::{BiTransformerOnce, FnBiTransformerOnceOps};
271///
272/// let add = |x: i32, y: i32| x + y;
273/// let multiply = |x: i32, y: i32| x * y;
274///
275/// let conditional = add.when(|x: &i32, y: &i32| *x > 0 && *y > 0).or_else(multiply);
276/// assert_eq!(conditional.apply(5, 3), 8); // add
277/// ```
278///
279/// # Author
280///
281/// Haixing Hu
282pub trait FnBiTransformerOnceOps<T, U, R>: FnOnce(T, U) -> R + Sized {
283    /// Chain composition - applies self first, then after
284    ///
285    /// Creates a new bi-transformer that applies this bi-transformer first,
286    /// then applies the after transformer to the result. Consumes self and
287    /// returns a `BoxBiTransformerOnce`.
288    ///
289    /// # Type Parameters
290    ///
291    /// * `S` - The output type of the after transformer
292    /// * `F` - The type of the after transformer (must implement TransformerOnce<R, S>)
293    ///
294    /// # Parameters
295    ///
296    /// * `after` - The transformer to apply after self. **Note: This parameter
297    ///   is passed by value and will transfer ownership.** Since this is a
298    ///   `FnOnce` bi-transformer, the parameter will be consumed. Can be:
299    ///   - A closure: `|x: R| -> S`
300    ///   - A function pointer: `fn(R) -> S`
301    ///   - A `BoxTransformerOnce<R, S>`
302    ///   - Any type implementing `TransformerOnce<R, S>`
303    ///
304    /// # Returns
305    ///
306    /// A new `BoxBiTransformerOnce<T, U, S>` representing the composition
307    ///
308    /// # Examples
309    ///
310    /// ```rust
311    /// use qubit_function::{BiTransformerOnce, FnBiTransformerOnceOps,
312    ///     BoxTransformerOnce};
313    ///
314    /// let add = |x: i32, y: i32| x + y;
315    /// let to_string = BoxTransformerOnce::new(|x: i32| x.to_string());
316    ///
317    /// // to_string is moved and consumed
318    /// let composed = add.and_then(to_string);
319    /// assert_eq!(composed.apply(20, 22), "42");
320    /// // to_string.apply(10); // Would not compile - moved
321    /// ```
322    fn and_then<S, F>(self, after: F) -> BoxBiTransformerOnce<T, U, S>
323    where
324        Self: 'static,
325        S: 'static,
326        F: crate::transformers::transformer_once::TransformerOnce<R, S> + 'static,
327        T: 'static,
328        U: 'static,
329        R: 'static,
330    {
331        BoxBiTransformerOnce::new(move |t: T, u: U| after.apply(self(t, u)))
332    }
333
334    /// Creates a conditional bi-transformer
335    ///
336    /// Returns a bi-transformer that only executes when a bi-predicate is
337    /// satisfied. You must call `or_else()` to provide an alternative
338    /// bi-transformer for when the condition is not satisfied.
339    ///
340    /// # Parameters
341    ///
342    /// * `predicate` - The condition to check. **Note: This parameter is passed
343    ///   by value and will transfer ownership.** If you need to preserve the
344    ///   original bi-predicate, clone it first (if it implements `Clone`).
345    ///   Can be:
346    ///   - A closure: `|x: &T, y: &U| -> bool`
347    ///   - A function pointer: `fn(&T, &U) -> bool`
348    ///   - A `BoxBiPredicate<T, U>`
349    ///   - An `RcBiPredicate<T, U>`
350    ///   - An `ArcBiPredicate<T, U>`
351    ///   - Any type implementing `BiPredicate<T, U>`
352    ///
353    /// # Returns
354    ///
355    /// Returns `BoxConditionalBiTransformerOnce<T, U, R>`
356    ///
357    /// # Examples
358    ///
359    /// ## Basic usage with or_else
360    ///
361    /// ```rust
362    /// use qubit_function::{BiTransformerOnce, FnBiTransformerOnceOps};
363    ///
364    /// let add = |x: i32, y: i32| x + y;
365    /// let multiply = |x: i32, y: i32| x * y;
366    /// let conditional = add.when(|x: &i32, y: &i32| *x > 0)
367    ///     .or_else(multiply);
368    ///
369    /// assert_eq!(conditional.apply(5, 3), 8);
370    /// ```
371    ///
372    /// ## Preserving bi-predicate with clone
373    ///
374    /// ```rust
375    /// use qubit_function::{BiTransformerOnce, FnBiTransformerOnceOps,
376    ///     RcBiPredicate};
377    ///
378    /// let add = |x: i32, y: i32| x + y;
379    /// let both_positive = RcBiPredicate::new(|x: &i32, y: &i32|
380    ///     *x > 0 && *y > 0);
381    ///
382    /// // Clone to preserve original bi-predicate
383    /// let conditional = add.when(both_positive.clone())
384    ///     .or_else(|x: i32, y: i32| x * y);
385    ///
386    /// assert_eq!(conditional.apply(5, 3), 8);
387    ///
388    /// // Original bi-predicate still usable
389    /// assert!(both_positive.test(&5, &3));
390    /// ```
391    fn when<P>(self, predicate: P) -> BoxConditionalBiTransformerOnce<T, U, R>
392    where
393        Self: 'static,
394        P: BiPredicate<T, U> + 'static,
395        T: 'static,
396        U: 'static,
397        R: 'static,
398    {
399        BoxBiTransformerOnce::new(self).when(predicate)
400    }
401}
402
403/// Blanket implementation of FnBiTransformerOnceOps for all closures
404///
405/// Automatically implements `FnBiTransformerOnceOps<T, U, R>` for any type that
406/// implements `FnOnce(T, U) -> R`.
407///
408/// # Author
409///
410/// Haixing Hu
411impl<T, U, R, F> FnBiTransformerOnceOps<T, U, R> for F where F: FnOnce(T, U) -> R {}
412
413// ============================================================================
414// BinaryOperatorOnce Trait - Marker trait for BiTransformerOnce<T, T, T>
415// ============================================================================
416
417/// BinaryOperatorOnce trait - marker trait for one-time use binary operators
418///
419/// A one-time use binary operator takes two values of type `T` and produces a
420/// value of the same type `T`, consuming self in the process. This trait
421/// extends `BiTransformerOnce<T, T, T>` to provide semantic clarity for
422/// same-type binary operations with consuming semantics. Equivalent to Java's
423/// `BinaryOperator<T>` but with FnOnce semantics.
424///
425/// # Automatic Implementation
426///
427/// This trait is automatically implemented for all types that implement
428/// `BiTransformerOnce<T, T, T>`, so you don't need to implement it manually.
429///
430/// # Type Parameters
431///
432/// * `T` - The type of both input values and the output value
433///
434/// # Examples
435///
436/// ## Using in generic constraints
437///
438/// ```rust
439/// use qubit_function::{BinaryOperatorOnce, BiTransformerOnce};
440///
441/// fn combine<T, O>(a: T, b: T, op: O) -> T
442/// where
443///     O: BinaryOperatorOnce<T>,
444/// {
445///     op.apply(a, b)
446/// }
447///
448/// let multiply = |x: i32, y: i32| x * y;
449/// assert_eq!(combine(6, 7, multiply), 42);
450/// ```
451///
452/// # Author
453///
454/// Haixing Hu
455pub trait BinaryOperatorOnce<T>: BiTransformerOnce<T, T, T> {}
456
457/// Blanket implementation of BinaryOperatorOnce for all BiTransformerOnce<T, T, T>
458///
459/// This automatically implements `BinaryOperatorOnce<T>` for any type that
460/// implements `BiTransformerOnce<T, T, T>`.
461///
462/// # Author
463///
464/// Haixing Hu
465impl<F, T> BinaryOperatorOnce<T> for F
466where
467    F: BiTransformerOnce<T, T, T>,
468{
469    // empty
470}
471
472// ============================================================================
473// Type Aliases for BinaryOperatorOnce (BiTransformerOnce<T, T, T>)
474// ============================================================================
475
476/// Type alias for `BoxBiTransformerOnce<T, T, T>`
477///
478/// Represents a one-time use binary operator that takes two values of type `T`
479/// and produces a value of the same type `T`. Equivalent to Java's
480/// `BinaryOperator<T>` with consuming semantics (FnOnce).
481///
482/// # Examples
483///
484/// ```rust
485/// use qubit_function::{BoxBinaryOperatorOnce, BiTransformerOnce};
486///
487/// let add: BoxBinaryOperatorOnce<i32> = BoxBinaryOperatorOnce::new(|x, y| x + y);
488/// assert_eq!(add.apply(20, 22), 42);
489/// ```
490///
491/// # Author
492///
493/// Haixing Hu
494pub type BoxBinaryOperatorOnce<T> = BoxBiTransformerOnce<T, T, T>;
495
496// ============================================================================
497// BoxConditionalBiTransformerOnce - Box-based Conditional BiTransformer
498// ============================================================================
499
500/// BoxConditionalBiTransformerOnce struct
501///
502/// A conditional consuming bi-transformer that only executes when a bi-predicate
503/// is satisfied. Uses `BoxBiTransformerOnce` and `BoxBiPredicate` for single
504/// ownership semantics.
505///
506/// This type is typically created by calling `BoxBiTransformerOnce::when()` and
507/// is designed to work with the `or_else()` method to create if-then-else logic.
508///
509/// # Features
510///
511/// - **Single Ownership**: Not cloneable, consumes `self` on use
512/// - **One-time Use**: Can only be called once
513/// - **Conditional Execution**: Only transforms when bi-predicate returns `true`
514/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
515///
516/// # Examples
517///
518/// ## With or_else Branch
519///
520/// ```rust
521/// use qubit_function::{BiTransformerOnce, BoxBiTransformerOnce};
522///
523/// let add = BoxBiTransformerOnce::new(|x: i32, y: i32| x + y);
524/// let multiply = BoxBiTransformerOnce::new(|x: i32, y: i32| x * y);
525/// let conditional = add.when(|x: &i32, y: &i32| *x > 0 && *y > 0).or_else(multiply);
526/// assert_eq!(conditional.apply(5, 3), 8); // when branch executed
527///
528/// let add2 = BoxBiTransformerOnce::new(|x: i32, y: i32| x + y);
529/// let multiply2 = BoxBiTransformerOnce::new(|x: i32, y: i32| x * y);
530/// let conditional2 = add2.when(|x: &i32, y: &i32| *x > 0 && *y > 0).or_else(multiply2);
531/// assert_eq!(conditional2.apply(-5, 3), -15); // or_else branch executed
532/// ```
533///
534/// # Author
535///
536/// Haixing Hu
537pub struct BoxConditionalBiTransformerOnce<T, U, R> {
538    transformer: BoxBiTransformerOnce<T, U, R>,
539    predicate: BoxBiPredicate<T, U>,
540}
541
542// Implement BoxConditionalTransformerOnce
543impl_box_conditional_transformer!(
544    BoxConditionalBiTransformerOnce<T, U, R>,
545    BoxBiTransformerOnce,
546    BiTransformerOnce
547);
548
549// Use macro to generate Debug and Display implementations
550impl_conditional_transformer_debug_display!(BoxConditionalBiTransformerOnce<T, U, R>);