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>);