prism3_function/
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//! Hu Haixing
23
24use crate::bi_predicate::{BiPredicate, BoxBiPredicate};
25
26// ============================================================================
27// Core Trait
28// ============================================================================
29
30/// BiTransformerOnce trait - consuming bi-transformation that takes ownership
31///
32/// Defines the behavior of a consuming bi-transformer: converting two values of
33/// types `T` and `U` to a value of type `R` by taking ownership of self and
34/// both inputs. This trait is analogous to `FnOnce(T, U) -> R`.
35///
36/// # Type Parameters
37///
38/// * `T` - The type of the first input value (consumed)
39/// * `U` - The type of the second input value (consumed)
40/// * `R` - The type of the output value
41///
42/// # Author
43///
44/// Hu Haixing
45pub trait BiTransformerOnce<T, U, R> {
46    /// Transforms two input values, consuming self and both inputs
47    ///
48    /// # Parameters
49    ///
50    /// * `first` - The first input value (consumed)
51    /// * `second` - The second input value (consumed)
52    ///
53    /// # Returns
54    ///
55    /// The transformed output value
56    fn apply_once(self, first: T, second: U) -> R;
57
58    /// Converts to BoxBiTransformerOnce
59    ///
60    /// **⚠️ Consumes `self`**: The original bi-transformer becomes unavailable
61    /// after calling this method.
62    ///
63    /// # Returns
64    ///
65    /// Returns `BoxBiTransformerOnce<T, U, R>`
66    fn into_box_once(self) -> BoxBiTransformerOnce<T, U, R>
67    where
68        Self: Sized + 'static,
69        T: 'static,
70        U: 'static,
71        R: 'static,
72    {
73        BoxBiTransformerOnce::new(move |t: T, u: U| self.apply_once(t, u))
74    }
75
76    /// Converts bi-transformer to a closure
77    ///
78    /// **⚠️ Consumes `self`**: The original bi-transformer becomes unavailable
79    /// after calling this method.
80    ///
81    /// # Returns
82    ///
83    /// Returns a closure that implements `FnOnce(T, U) -> R`
84    fn into_fn_once(self) -> impl FnOnce(T, U) -> R
85    where
86        Self: Sized + 'static,
87        T: 'static,
88        U: 'static,
89        R: 'static,
90    {
91        move |t: T, u: U| self.apply_once(t, u)
92    }
93
94    /// Converts bi-transformer to a boxed function pointer
95    ///
96    /// **📌 Borrows `&self`**: The original bi-transformer remains usable
97    /// after calling this method.
98    ///
99    /// # Returns
100    ///
101    /// Returns a boxed function pointer that implements `FnOnce(T, U) -> R`
102    ///
103    /// # Examples
104    ///
105    /// ```rust
106    /// use prism3_function::BiTransformerOnce;
107    ///
108    /// let add = |x: i32, y: i32| x + y;
109    /// let func = add.to_fn_once();
110    /// assert_eq!(func(20, 22), 42);
111    /// ```
112    fn to_box_once(&self) -> BoxBiTransformerOnce<T, U, R>
113    where
114        Self: Clone + 'static,
115        T: 'static,
116        U: 'static,
117        R: 'static,
118    {
119        self.clone().into_box_once()
120    }
121
122    /// Converts bi-transformer to a closure
123    ///
124    /// **📌 Borrows `&self`**: The original bi-transformer remains usable
125    /// after calling this method.
126    ///
127    /// # Returns
128    ///
129    /// Returns a closure that implements `FnOnce(T, U) -> R`
130    ///
131    /// # Examples
132    ///
133    /// ```rust
134    /// use prism3_function::BiTransformerOnce;
135    ///
136    /// let add = |x: i32, y: i32| x + y;
137    /// let func = add.to_fn_once();
138    /// assert_eq!(func(20, 22), 42);
139    /// ```
140    fn to_fn_once(&self) -> impl FnOnce(T, U) -> R
141    where
142        Self: Clone + 'static,
143        T: 'static,
144        U: 'static,
145        R: 'static,
146    {
147        self.clone().into_fn_once()
148    }
149}
150
151// ============================================================================
152// BoxBiTransformerOnce - Box<dyn FnOnce(T, U) -> R>
153// ============================================================================
154
155/// BoxBiTransformerOnce - consuming bi-transformer wrapper based on
156/// `Box<dyn FnOnce>`
157///
158/// A bi-transformer wrapper that provides single ownership with one-time use
159/// semantics. Consumes self and both input values.
160///
161/// # Features
162///
163/// - **Based on**: `Box<dyn FnOnce(T, U) -> R>`
164/// - **Ownership**: Single ownership, cannot be cloned
165/// - **Reusability**: Can only be called once (consumes self and inputs)
166/// - **Thread Safety**: Not thread-safe (no `Send + Sync` requirement)
167///
168/// # Author
169///
170/// Hu Haixing
171pub struct BoxBiTransformerOnce<T, U, R> {
172    function: Box<dyn FnOnce(T, U) -> R>,
173}
174
175impl<T, U, R> BoxBiTransformerOnce<T, U, R>
176where
177    T: 'static,
178    U: 'static,
179    R: 'static,
180{
181    /// Creates a new BoxBiTransformerOnce
182    ///
183    /// # Parameters
184    ///
185    /// * `f` - The closure or function to wrap
186    ///
187    /// # Examples
188    ///
189    /// ```rust
190    /// use prism3_function::{BoxBiTransformerOnce, BiTransformerOnce};
191    ///
192    /// let add = BoxBiTransformerOnce::new(|x: i32, y: i32| x + y);
193    /// assert_eq!(add.apply_once(20, 22), 42);
194    /// ```
195    pub fn new<F>(f: F) -> Self
196    where
197        F: FnOnce(T, U) -> R + 'static,
198    {
199        BoxBiTransformerOnce {
200            function: Box::new(f),
201        }
202    }
203
204    /// Chain composition - applies self first, then after
205    ///
206    /// Creates a new bi-transformer that applies this bi-transformer first,
207    /// then applies the after transformer to the result. Consumes self and
208    /// returns a new `BoxBiTransformerOnce`.
209    ///
210    /// # Type Parameters
211    ///
212    /// * `S` - The output type of the after transformer
213    /// * `F` - The type of the after transformer (must implement TransformerOnce<R, S>)
214    ///
215    /// # Parameters
216    ///
217    /// * `after` - The transformer to apply after self. **Note: This parameter
218    ///   is passed by value and will transfer ownership.** Since
219    ///   `BoxBiTransformerOnce` cannot be cloned, the parameter will be consumed.
220    ///   Can be:
221    ///   - A closure: `|x: R| -> S`
222    ///   - A function pointer: `fn(R) -> S`
223    ///   - A `BoxTransformerOnce<R, S>`
224    ///   - Any type implementing `TransformerOnce<R, S>`
225    ///
226    /// # Returns
227    ///
228    /// A new `BoxBiTransformerOnce<T, U, S>` representing the composition
229    ///
230    /// # Examples
231    ///
232    /// ```rust
233    /// use prism3_function::{BiTransformerOnce, BoxBiTransformerOnce};
234    ///
235    /// let add = BoxBiTransformerOnce::new(|x: i32, y: i32| x + y);
236    /// let double = |x: i32| x * 2;
237    ///
238    /// // Both add and double are moved and consumed
239    /// let composed = add.and_then(double);
240    /// assert_eq!(composed.apply_once(3, 5), 16); // (3 + 5) * 2
241    /// // add.apply_once(1, 2); // Would not compile - moved
242    /// // double(10); // Would not compile - moved
243    /// ```
244    pub fn and_then<S, F>(self, after: F) -> BoxBiTransformerOnce<T, U, S>
245    where
246        S: 'static,
247        F: crate::transformer_once::TransformerOnce<R, S> + 'static,
248    {
249        let self_fn = self.function;
250        BoxBiTransformerOnce::new(move |t: T, u: U| after.apply_once(self_fn(t, u)))
251    }
252
253    /// Creates a conditional bi-transformer
254    ///
255    /// Returns a bi-transformer that only executes when a bi-predicate is
256    /// satisfied. You must call `or_else()` to provide an alternative
257    /// bi-transformer.
258    ///
259    /// # Parameters
260    ///
261    /// * `predicate` - The condition to check. **Note: This parameter is passed
262    ///   by value and will transfer ownership.** If you need to preserve the
263    ///   original bi-predicate, clone it first (if it implements `Clone`).
264    ///   Can be:
265    ///   - A closure: `|x: &T, y: &U| -> bool`
266    ///   - A function pointer: `fn(&T, &U) -> bool`
267    ///   - A `BoxBiPredicate<T, U>`
268    ///   - An `RcBiPredicate<T, U>`
269    ///   - An `ArcBiPredicate<T, U>`
270    ///   - Any type implementing `BiPredicate<T, U>`
271    ///
272    /// # Returns
273    ///
274    /// Returns `BoxConditionalBiTransformerOnce<T, U, R>`
275    ///
276    /// # Examples
277    ///
278    /// ## Basic usage with or_else
279    ///
280    /// ```rust
281    /// use prism3_function::{BiTransformerOnce, BoxBiTransformerOnce};
282    ///
283    /// let add = BoxBiTransformerOnce::new(|x: i32, y: i32| x + y);
284    /// let multiply = BoxBiTransformerOnce::new(|x: i32, y: i32| x * y);
285    /// let conditional = add.when(|x: &i32, y: &i32| *x > 0 && *y > 0)
286    ///     .or_else(multiply);
287    /// assert_eq!(conditional.apply_once(5, 3), 8);
288    ///
289    /// let add2 = BoxBiTransformerOnce::new(|x: i32, y: i32| x + y);
290    /// let multiply2 = BoxBiTransformerOnce::new(|x: i32, y: i32| x * y);
291    /// let conditional2 = add2.when(|x: &i32, y: &i32| *x > 0 && *y > 0)
292    ///     .or_else(multiply2);
293    /// assert_eq!(conditional2.apply_once(-5, 3), -15);
294    /// ```
295    ///
296    /// ## Preserving bi-predicate with clone
297    ///
298    /// ```rust
299    /// use prism3_function::{BiTransformerOnce, BoxBiTransformerOnce, RcBiPredicate};
300    ///
301    /// let add = BoxBiTransformerOnce::new(|x: i32, y: i32| x + y);
302    /// let both_positive = RcBiPredicate::new(|x: &i32, y: &i32|
303    ///     *x > 0 && *y > 0);
304    ///
305    /// // Clone to preserve original bi-predicate
306    /// let conditional = add.when(both_positive.clone())
307    ///     .or_else(BoxBiTransformerOnce::new(|x, y| x * y));
308    ///
309    /// assert_eq!(conditional.apply_once(5, 3), 8);
310    ///
311    /// // Original bi-predicate still usable
312    /// assert!(both_positive.test(&5, &3));
313    /// ```
314    pub fn when<P>(self, predicate: P) -> BoxConditionalBiTransformerOnce<T, U, R>
315    where
316        P: BiPredicate<T, U> + 'static,
317    {
318        BoxConditionalBiTransformerOnce {
319            transformer: self,
320            predicate: predicate.into_box(),
321        }
322    }
323}
324
325impl<T, U, R> BoxBiTransformerOnce<T, U, R>
326where
327    T: 'static,
328    U: 'static,
329    R: Clone + 'static,
330{
331    /// Creates a constant bi-transformer
332    ///
333    /// # Examples
334    ///
335    /// ```rust
336    /// use prism3_function::{BoxBiTransformerOnce, BiTransformerOnce};
337    ///
338    /// let constant = BoxBiTransformerOnce::constant("hello");
339    /// assert_eq!(constant.apply_once(123, 456), "hello");
340    /// ```
341    pub fn constant(value: R) -> BoxBiTransformerOnce<T, U, R> {
342        BoxBiTransformerOnce::new(move |_, _| value.clone())
343    }
344}
345
346impl<T, U, R> BiTransformerOnce<T, U, R> for BoxBiTransformerOnce<T, U, R> {
347    fn apply_once(self, first: T, second: U) -> R {
348        (self.function)(first, second)
349    }
350
351    fn into_box_once(self) -> BoxBiTransformerOnce<T, U, R>
352    where
353        T: 'static,
354        U: 'static,
355        R: 'static,
356    {
357        // Zero-cost: directly return itself
358        self
359    }
360
361    fn into_fn_once(self) -> impl FnOnce(T, U) -> R
362    where
363        T: 'static,
364        U: 'static,
365        R: 'static,
366    {
367        move |t: T, u: U| self.apply_once(t, u)
368    }
369
370    //  do NOT override BoxBiTransformerOnce::to_xxxx() because BoxBiTransformerOnce is not Clone
371    //  and calling BoxBiTransformerOnce::to_xxxx() will cause a compile error
372}
373
374// ============================================================================
375// BoxConditionalBiTransformerOnce - Box-based Conditional BiTransformer
376// ============================================================================
377
378/// BoxConditionalBiTransformerOnce struct
379///
380/// A conditional consuming bi-transformer that only executes when a bi-predicate
381/// is satisfied. Uses `BoxBiTransformerOnce` and `BoxBiPredicate` for single
382/// ownership semantics.
383///
384/// This type is typically created by calling `BoxBiTransformerOnce::when()` and
385/// is designed to work with the `or_else()` method to create if-then-else logic.
386///
387/// # Features
388///
389/// - **Single Ownership**: Not cloneable, consumes `self` on use
390/// - **One-time Use**: Can only be called once
391/// - **Conditional Execution**: Only transforms when bi-predicate returns `true`
392/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
393///
394/// # Examples
395///
396/// ## With or_else Branch
397///
398/// ```rust
399/// use prism3_function::{BiTransformerOnce, BoxBiTransformerOnce};
400///
401/// let add = BoxBiTransformerOnce::new(|x: i32, y: i32| x + y);
402/// let multiply = BoxBiTransformerOnce::new(|x: i32, y: i32| x * y);
403/// let conditional = add.when(|x: &i32, y: &i32| *x > 0 && *y > 0).or_else(multiply);
404/// assert_eq!(conditional.apply_once(5, 3), 8); // when branch executed
405///
406/// let add2 = BoxBiTransformerOnce::new(|x: i32, y: i32| x + y);
407/// let multiply2 = BoxBiTransformerOnce::new(|x: i32, y: i32| x * y);
408/// let conditional2 = add2.when(|x: &i32, y: &i32| *x > 0 && *y > 0).or_else(multiply2);
409/// assert_eq!(conditional2.apply_once(-5, 3), -15); // or_else branch executed
410/// ```
411///
412/// # Author
413///
414/// Haixing Hu
415pub struct BoxConditionalBiTransformerOnce<T, U, R> {
416    transformer: BoxBiTransformerOnce<T, U, R>,
417    predicate: BoxBiPredicate<T, U>,
418}
419
420impl<T, U, R> BoxConditionalBiTransformerOnce<T, U, R>
421where
422    T: 'static,
423    U: 'static,
424    R: 'static,
425{
426    /// Adds an else branch
427    ///
428    /// Executes the original bi-transformer when the condition is satisfied,
429    /// otherwise executes else_transformer.
430    ///
431    /// # Parameters
432    ///
433    /// * `else_transformer` - The bi-transformer for the else branch, can be:
434    ///   - Closure: `|x: T, y: U| -> R`
435    ///   - `BoxBiTransformerOnce<T, U, R>`
436    ///   - Any type implementing `BiTransformerOnce<T, U, R>`
437    ///
438    /// # Returns
439    ///
440    /// Returns the composed `BoxBiTransformerOnce<T, U, R>`
441    ///
442    /// # Examples
443    ///
444    /// ## Using a closure (recommended)
445    ///
446    /// ```rust
447    /// use prism3_function::{BiTransformerOnce, BoxBiTransformerOnce};
448    ///
449    /// let add = BoxBiTransformerOnce::new(|x: i32, y: i32| x + y);
450    /// let conditional = add.when(|x: &i32, y: &i32| *x > 0 && *y > 0).or_else(|x: i32, y: i32| x * y);
451    /// assert_eq!(conditional.apply_once(5, 3), 8); // Condition satisfied, execute add
452    ///
453    /// let add2 = BoxBiTransformerOnce::new(|x: i32, y: i32| x + y);
454    /// let conditional2 = add2.when(|x: &i32, y: &i32| *x > 0 && *y > 0).or_else(|x: i32, y: i32| x * y);
455    /// assert_eq!(conditional2.apply_once(-5, 3), -15); // Condition not satisfied, execute multiply
456    /// ```
457    pub fn or_else<F>(self, else_transformer: F) -> BoxBiTransformerOnce<T, U, R>
458    where
459        F: BiTransformerOnce<T, U, R> + 'static,
460    {
461        let pred = self.predicate;
462        let then_trans = self.transformer;
463        BoxBiTransformerOnce::new(move |t, u| {
464            if pred.test(&t, &u) {
465                then_trans.apply_once(t, u)
466            } else {
467                else_transformer.apply_once(t, u)
468            }
469        })
470    }
471}
472
473// ============================================================================
474// Blanket implementation for standard FnOnce trait
475// ============================================================================
476
477/// Implement BiTransformerOnce<T, U, R> for any type that implements
478/// FnOnce(T, U) -> R
479///
480/// This allows once-callable closures and function pointers to be used
481/// directly with our BiTransformerOnce trait without wrapping.
482///
483/// # Examples
484///
485/// ```rust
486/// use prism3_function::BiTransformerOnce;
487///
488/// fn add(x: i32, y: i32) -> i32 {
489///     x + y
490/// }
491///
492/// assert_eq!(add.apply_once(20, 22), 42);
493///
494/// let owned_x = String::from("hello");
495/// let owned_y = String::from("world");
496/// let concat = |x: String, y: String| {
497///     format!("{} {}", x, y)
498/// };
499/// assert_eq!(concat.apply_once(owned_x, owned_y), "hello world");
500/// ```
501///
502/// # Author
503///
504/// Hu Haixing
505impl<F, T, U, R> BiTransformerOnce<T, U, R> for F
506where
507    F: FnOnce(T, U) -> R,
508    T: 'static,
509    U: 'static,
510    R: 'static,
511{
512    fn apply_once(self, first: T, second: U) -> R {
513        self(first, second)
514    }
515
516    fn into_box_once(self) -> BoxBiTransformerOnce<T, U, R>
517    where
518        Self: Sized + 'static,
519    {
520        BoxBiTransformerOnce::new(self)
521    }
522
523    fn into_fn_once(self) -> impl FnOnce(T, U) -> R
524    where
525        Self: Sized + 'static,
526    {
527        move |first: T, second: U| -> R { self(first, second) }
528    }
529
530    fn to_box_once(&self) -> BoxBiTransformerOnce<T, U, R>
531    where
532        Self: Clone + 'static,
533        T: 'static,
534        U: 'static,
535        R: 'static,
536    {
537        BoxBiTransformerOnce::new(self.clone())
538    }
539
540    fn to_fn_once(&self) -> impl FnOnce(T, U) -> R
541    where
542        Self: Clone + 'static,
543        T: 'static,
544        U: 'static,
545        R: 'static,
546    {
547        self.clone()
548    }
549}
550
551// ============================================================================
552// FnBiTransformerOnceOps - Extension trait for FnOnce(T, U) -> R bi-transformers
553// ============================================================================
554
555/// Extension trait for closures implementing `FnOnce(T, U) -> R`
556///
557/// Provides composition methods (`and_then`, `when`) for one-time use
558/// bi-transformer closures and function pointers without requiring explicit
559/// wrapping in `BoxBiTransformerOnce`.
560///
561/// This trait is automatically implemented for all closures and function
562/// pointers that implement `FnOnce(T, U) -> R`.
563///
564/// # Design Rationale
565///
566/// While closures automatically implement `BiTransformerOnce<T, U, R>` through
567/// blanket implementation, they don't have access to instance methods like
568/// `and_then` and `when`. This extension trait provides those methods,
569/// returning `BoxBiTransformerOnce` for maximum flexibility.
570///
571/// # Examples
572///
573/// ## Chain composition with and_then
574///
575/// ```rust
576/// use prism3_function::{BiTransformerOnce, FnBiTransformerOnceOps};
577///
578/// let add = |x: i32, y: i32| x + y;
579/// let double = |x: i32| x * 2;
580///
581/// let composed = add.and_then(double);
582/// assert_eq!(composed.apply_once(3, 5), 16); // (3 + 5) * 2
583/// ```
584///
585/// ## Conditional execution with when
586///
587/// ```rust
588/// use prism3_function::{BiTransformerOnce, FnBiTransformerOnceOps};
589///
590/// let add = |x: i32, y: i32| x + y;
591/// let multiply = |x: i32, y: i32| x * y;
592///
593/// let conditional = add.when(|x: &i32, y: &i32| *x > 0 && *y > 0).or_else(multiply);
594/// assert_eq!(conditional.apply_once(5, 3), 8); // add
595/// ```
596///
597/// # Author
598///
599/// Hu Haixing
600pub trait FnBiTransformerOnceOps<T, U, R>: FnOnce(T, U) -> R + Sized + 'static {
601    /// Chain composition - applies self first, then after
602    ///
603    /// Creates a new bi-transformer that applies this bi-transformer first,
604    /// then applies the after transformer to the result. Consumes self and
605    /// returns a `BoxBiTransformerOnce`.
606    ///
607    /// # Type Parameters
608    ///
609    /// * `S` - The output type of the after transformer
610    /// * `F` - The type of the after transformer (must implement TransformerOnce<R, S>)
611    ///
612    /// # Parameters
613    ///
614    /// * `after` - The transformer to apply after self. **Note: This parameter
615    ///   is passed by value and will transfer ownership.** Since this is a
616    ///   `FnOnce` bi-transformer, the parameter will be consumed. Can be:
617    ///   - A closure: `|x: R| -> S`
618    ///   - A function pointer: `fn(R) -> S`
619    ///   - A `BoxTransformerOnce<R, S>`
620    ///   - Any type implementing `TransformerOnce<R, S>`
621    ///
622    /// # Returns
623    ///
624    /// A new `BoxBiTransformerOnce<T, U, S>` representing the composition
625    ///
626    /// # Examples
627    ///
628    /// ```rust
629    /// use prism3_function::{BiTransformerOnce, FnBiTransformerOnceOps,
630    ///     BoxTransformerOnce};
631    ///
632    /// let add = |x: i32, y: i32| x + y;
633    /// let to_string = BoxTransformerOnce::new(|x: i32| x.to_string());
634    ///
635    /// // to_string is moved and consumed
636    /// let composed = add.and_then(to_string);
637    /// assert_eq!(composed.apply_once(20, 22), "42");
638    /// // to_string.apply_once(10); // Would not compile - moved
639    /// ```
640    fn and_then<S, F>(self, after: F) -> BoxBiTransformerOnce<T, U, S>
641    where
642        S: 'static,
643        F: crate::transformer_once::TransformerOnce<R, S> + 'static,
644        T: 'static,
645        U: 'static,
646        R: 'static,
647    {
648        BoxBiTransformerOnce::new(move |t: T, u: U| after.apply_once(self(t, u)))
649    }
650
651    /// Creates a conditional bi-transformer
652    ///
653    /// Returns a bi-transformer that only executes when a bi-predicate is
654    /// satisfied. You must call `or_else()` to provide an alternative
655    /// bi-transformer for when the condition is not satisfied.
656    ///
657    /// # Parameters
658    ///
659    /// * `predicate` - The condition to check. **Note: This parameter is passed
660    ///   by value and will transfer ownership.** If you need to preserve the
661    ///   original bi-predicate, clone it first (if it implements `Clone`).
662    ///   Can be:
663    ///   - A closure: `|x: &T, y: &U| -> bool`
664    ///   - A function pointer: `fn(&T, &U) -> bool`
665    ///   - A `BoxBiPredicate<T, U>`
666    ///   - An `RcBiPredicate<T, U>`
667    ///   - An `ArcBiPredicate<T, U>`
668    ///   - Any type implementing `BiPredicate<T, U>`
669    ///
670    /// # Returns
671    ///
672    /// Returns `BoxConditionalBiTransformerOnce<T, U, R>`
673    ///
674    /// # Examples
675    ///
676    /// ## Basic usage with or_else
677    ///
678    /// ```rust
679    /// use prism3_function::{BiTransformerOnce, FnBiTransformerOnceOps};
680    ///
681    /// let add = |x: i32, y: i32| x + y;
682    /// let multiply = |x: i32, y: i32| x * y;
683    /// let conditional = add.when(|x: &i32, y: &i32| *x > 0)
684    ///     .or_else(multiply);
685    ///
686    /// assert_eq!(conditional.apply_once(5, 3), 8);
687    /// ```
688    ///
689    /// ## Preserving bi-predicate with clone
690    ///
691    /// ```rust
692    /// use prism3_function::{BiTransformerOnce, FnBiTransformerOnceOps,
693    ///     RcBiPredicate};
694    ///
695    /// let add = |x: i32, y: i32| x + y;
696    /// let both_positive = RcBiPredicate::new(|x: &i32, y: &i32|
697    ///     *x > 0 && *y > 0);
698    ///
699    /// // Clone to preserve original bi-predicate
700    /// let conditional = add.when(both_positive.clone())
701    ///     .or_else(|x: i32, y: i32| x * y);
702    ///
703    /// assert_eq!(conditional.apply_once(5, 3), 8);
704    ///
705    /// // Original bi-predicate still usable
706    /// assert!(both_positive.test(&5, &3));
707    /// ```
708    fn when<P>(self, predicate: P) -> BoxConditionalBiTransformerOnce<T, U, R>
709    where
710        P: BiPredicate<T, U> + 'static,
711        T: 'static,
712        U: 'static,
713        R: 'static,
714    {
715        BoxBiTransformerOnce::new(self).when(predicate)
716    }
717}
718
719/// Blanket implementation of FnBiTransformerOnceOps for all closures
720///
721/// Automatically implements `FnBiTransformerOnceOps<T, U, R>` for any type that
722/// implements `FnOnce(T, U) -> R`.
723///
724/// # Author
725///
726/// Hu Haixing
727impl<T, U, R, F> FnBiTransformerOnceOps<T, U, R> for F where F: FnOnce(T, U) -> R + 'static {}
728
729// ============================================================================
730// BinaryOperatorOnce Trait - Marker trait for BiTransformerOnce<T, T, T>
731// ============================================================================
732
733/// BinaryOperatorOnce trait - marker trait for one-time use binary operators
734///
735/// A one-time use binary operator takes two values of type `T` and produces a
736/// value of the same type `T`, consuming self in the process. This trait
737/// extends `BiTransformerOnce<T, T, T>` to provide semantic clarity for
738/// same-type binary operations with consuming semantics. Equivalent to Java's
739/// `BinaryOperator<T>` but with FnOnce semantics.
740///
741/// # Automatic Implementation
742///
743/// This trait is automatically implemented for all types that implement
744/// `BiTransformerOnce<T, T, T>`, so you don't need to implement it manually.
745///
746/// # Type Parameters
747///
748/// * `T` - The type of both input values and the output value
749///
750/// # Examples
751///
752/// ## Using in generic constraints
753///
754/// ```rust
755/// use prism3_function::{BinaryOperatorOnce, BiTransformerOnce};
756///
757/// fn combine<T, O>(a: T, b: T, op: O) -> T
758/// where
759///     O: BinaryOperatorOnce<T>,
760/// {
761///     op.apply_once(a, b)
762/// }
763///
764/// let multiply = |x: i32, y: i32| x * y;
765/// assert_eq!(combine(6, 7, multiply), 42);
766/// ```
767///
768/// # Author
769///
770/// Hu Haixing
771pub trait BinaryOperatorOnce<T>: BiTransformerOnce<T, T, T> {}
772
773/// Blanket implementation of BinaryOperatorOnce for all BiTransformerOnce<T, T, T>
774///
775/// This automatically implements `BinaryOperatorOnce<T>` for any type that
776/// implements `BiTransformerOnce<T, T, T>`.
777///
778/// # Author
779///
780/// Hu Haixing
781impl<F, T> BinaryOperatorOnce<T> for F
782where
783    F: BiTransformerOnce<T, T, T>,
784    T: 'static,
785{
786    // empty
787}
788
789// ============================================================================
790// Type Aliases for BinaryOperatorOnce (BiTransformerOnce<T, T, T>)
791// ============================================================================
792
793/// Type alias for `BoxBiTransformerOnce<T, T, T>`
794///
795/// Represents a one-time use binary operator that takes two values of type `T`
796/// and produces a value of the same type `T`. Equivalent to Java's
797/// `BinaryOperator<T>` with consuming semantics (FnOnce).
798///
799/// # Examples
800///
801/// ```rust
802/// use prism3_function::{BoxBinaryOperatorOnce, BiTransformerOnce};
803///
804/// let add: BoxBinaryOperatorOnce<i32> = BoxBinaryOperatorOnce::new(|x, y| x + y);
805/// assert_eq!(add.apply_once(20, 22), 42);
806/// ```
807///
808/// # Author
809///
810/// Hu Haixing
811pub type BoxBinaryOperatorOnce<T> = BoxBiTransformerOnce<T, T, T>;