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