prism3_function/transformers/
bi_transformer_once.rs

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