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