prism3_function/functions/bi_function.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025.
4 * 3-Prism Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9
10//! # BiFunction Types
11//!
12//! Provides Rust implementations of bi-function traits for computing output values
13//! from two input references. BiFunctions borrow input values (not consuming them)
14//! and produce output values.
15//!
16//! It is similar to the `Fn(&T, &U) -> R` trait in the standard library.
17//!
18//! This module provides the `BiFunction<T, U, R>` trait and three
19//! implementations:
20//!
21//! - [`BoxBiFunction`]: Single ownership, not cloneable
22//! - [`ArcBiFunction`]: Thread-safe shared ownership, cloneable
23//! - [`RcBiFunction`]: Single-threaded shared ownership, cloneable
24//!
25//! # Author
26//!
27//! Haixing Hu
28use std::rc::Rc;
29use std::sync::Arc;
30
31use crate::functions::{
32 bi_function_once::BoxBiFunctionOnce,
33 function::Function,
34 macros::{
35 impl_box_conditional_function,
36 impl_box_function_methods,
37 impl_conditional_function_clone,
38 impl_conditional_function_debug_display,
39 impl_function_clone,
40 impl_function_common_methods,
41 impl_function_constant_method,
42 impl_function_debug_display,
43 impl_shared_conditional_function,
44 impl_shared_function_methods,
45 },
46};
47use crate::macros::{
48 impl_arc_conversions,
49 impl_box_conversions,
50 impl_closure_trait,
51 impl_rc_conversions,
52};
53use crate::predicates::bi_predicate::{
54 ArcBiPredicate,
55 BiPredicate,
56 BoxBiPredicate,
57 RcBiPredicate,
58};
59
60// ============================================================================
61// Core Trait
62// ============================================================================
63
64/// BiFunction trait - computes output from two input references
65///
66/// Defines the behavior of a bi-function: computing a value of type `R`
67/// from references to types `T` and `U` without consuming the inputs. This is analogous to
68/// `Fn(&T, &U) -> R` in Rust's standard library, similar to Java's `BiFunction<T, U, R>`.
69///
70/// # Type Parameters
71///
72/// * `T` - The type of the first input value (borrowed)
73/// * `U` - The type of the second input value (borrowed)
74/// * `R` - The type of the output value
75///
76/// # Author
77///
78/// Haixing Hu
79pub trait BiFunction<T, U, R> {
80 /// Applies the bi-function to two input references to produce an output value
81 ///
82 /// # Parameters
83 ///
84 /// * `first` - Reference to the first input value
85 /// * `second` - Reference to the second input value
86 ///
87 /// # Returns
88 ///
89 /// The computed output value
90 fn apply(&self, first: &T, second: &U) -> R;
91
92 /// Converts to BoxBiFunction
93 ///
94 /// **⚠️ Consumes `self`**: The original bi-function becomes
95 /// unavailable after calling this method.
96 ///
97 /// # Default Implementation
98 ///
99 /// The default implementation wraps `self` in a `Box` and creates a
100 /// `BoxBiFunction`. Types can override this method to provide more
101 /// efficient conversions.
102 ///
103 /// # Returns
104 ///
105 /// Returns `BoxBiFunction<T, U, R>`
106 fn into_box(self) -> BoxBiFunction<T, U, R>
107 where
108 Self: Sized + 'static,
109 T: 'static,
110 U: 'static,
111 R: 'static,
112 {
113 BoxBiFunction::new(move |t, u| self.apply(t, u))
114 }
115
116 /// Converts to RcBiFunction
117 ///
118 /// **⚠️ Consumes `self`**: The original bi-function becomes
119 /// unavailable after calling this method.
120 ///
121 /// # Default Implementation
122 ///
123 /// The default implementation wraps `self` in an `Rc` and creates an
124 /// `RcBiFunction`. Types can override this method to provide more
125 /// efficient conversions.
126 ///
127 /// # Returns
128 ///
129 /// Returns `RcBiFunction<T, U, R>`
130 fn into_rc(self) -> RcBiFunction<T, U, R>
131 where
132 Self: Sized + 'static,
133 T: 'static,
134 U: 'static,
135 R: 'static,
136 {
137 RcBiFunction::new(move |t, u| self.apply(t, u))
138 }
139
140 /// Converts to ArcBiFunction
141 ///
142 /// **⚠️ Consumes `self`**: The original bi-function becomes
143 /// unavailable after calling this method.
144 ///
145 /// # Default Implementation
146 ///
147 /// The default implementation wraps `self` in an `Arc` and creates
148 /// an `ArcBiFunction`. Types can override this method to provide
149 /// more efficient conversions.
150 ///
151 /// # Returns
152 ///
153 /// Returns `ArcBiFunction<T, U, R>`
154 fn into_arc(self) -> ArcBiFunction<T, U, R>
155 where
156 Self: Sized + Send + Sync + 'static,
157 T: Send + Sync + 'static,
158 U: Send + Sync + 'static,
159 R: Send + Sync + 'static,
160 {
161 ArcBiFunction::new(move |t, u| self.apply(t, u))
162 }
163
164 /// Converts bi-function to a closure
165 ///
166 /// **⚠️ Consumes `self`**: The original bi-function becomes
167 /// unavailable after calling this method.
168 ///
169 /// # Default Implementation
170 ///
171 /// The default implementation creates a closure that captures `self`
172 /// and calls its `apply` method. Types can override this method
173 /// to provide more efficient conversions.
174 ///
175 /// # Returns
176 ///
177 /// Returns a closure that implements `Fn(&T, &U) -> R`
178 fn into_fn(self) -> impl Fn(&T, &U) -> R
179 where
180 Self: Sized + 'static,
181 T: 'static,
182 U: 'static,
183 R: 'static,
184 {
185 move |t, u| self.apply(t, u)
186 }
187
188 /// Converts to BiFunctionOnce
189 ///
190 /// **⚠️ Consumes `self`**: The original bi-function becomes unavailable after calling this method.
191 ///
192 /// Converts a reusable bi-function to a one-time bi-function that consumes itself on use.
193 /// This enables passing `BiFunction` to functions that require `BiFunctionOnce`.
194 ///
195 /// # Returns
196 ///
197 /// Returns a `BoxBiFunctionOnce<T, U, R>`
198 fn into_once(self) -> BoxBiFunctionOnce<T, U, R>
199 where
200 Self: Sized + 'static,
201 T: 'static,
202 U: 'static,
203 R: 'static,
204 {
205 BoxBiFunctionOnce::new(move |t, u| self.apply(t, u))
206 }
207
208 /// Non-consuming conversion to `BoxBiFunction` using `&self`.
209 ///
210 /// Default implementation clones `self` and delegates to `into_box`.
211 fn to_box(&self) -> BoxBiFunction<T, U, R>
212 where
213 Self: Sized + Clone + 'static,
214 T: 'static,
215 U: 'static,
216 R: 'static,
217 {
218 self.clone().into_box()
219 }
220
221 /// Non-consuming conversion to `RcBiFunction` using `&self`.
222 ///
223 /// Default implementation clones `self` and delegates to `into_rc`.
224 fn to_rc(&self) -> RcBiFunction<T, U, R>
225 where
226 Self: Sized + Clone + 'static,
227 T: 'static,
228 U: 'static,
229 R: 'static,
230 {
231 self.clone().into_rc()
232 }
233
234 /// Non-consuming conversion to `ArcBiFunction` using `&self`.
235 ///
236 /// Default implementation clones `self` and delegates to `into_arc`.
237 fn to_arc(&self) -> ArcBiFunction<T, U, R>
238 where
239 Self: Sized + Clone + Send + Sync + 'static,
240 T: Send + Sync + 'static,
241 U: Send + Sync + 'static,
242 R: Send + Sync + 'static,
243 {
244 self.clone().into_arc()
245 }
246
247 /// Non-consuming conversion to a boxed function using `&self`.
248 ///
249 /// Returns a `Box<dyn Fn(&T, &U) -> R>` that clones `self` and calls
250 /// `apply` inside the boxed closure.
251 fn to_fn(&self) -> impl Fn(&T, &U) -> R
252 where
253 Self: Sized + Clone + 'static,
254 T: 'static,
255 U: 'static,
256 R: 'static,
257 {
258 self.clone().into_fn()
259 }
260
261 /// Convert to BiFunctionOnce without consuming self
262 ///
263 /// **⚠️ Requires Clone**: This method requires `Self` to implement `Clone`.
264 /// Clones the current bi-function and converts the clone to a one-time bi-function.
265 ///
266 /// # Returns
267 ///
268 /// Returns a `BoxBiFunctionOnce<T, U, R>`
269 fn to_once(&self) -> BoxBiFunctionOnce<T, U, R>
270 where
271 Self: Clone + 'static,
272 T: 'static,
273 U: 'static,
274 R: 'static,
275 {
276 self.clone().into_once()
277 }
278}
279
280// ============================================================================
281// BoxBiFunction - Box<dyn Fn(&T, &U) -> R>
282// ============================================================================
283
284/// BoxBiFunction - bi-function wrapper based on `Box<dyn Fn>`
285///
286/// A bi-function wrapper that provides single ownership with reusable
287/// computation. Borrows both inputs and can be called multiple times.
288///
289/// # Features
290///
291/// - **Based on**: `Box<dyn Fn(&T, &U) -> R>`
292/// - **Ownership**: Single ownership, cannot be cloned
293/// - **Reusability**: Can be called multiple times (borrows inputs each time)
294/// - **Thread Safety**: Not thread-safe (no `Send + Sync` requirement)
295///
296/// # Author
297///
298/// Haixing Hu
299pub struct BoxBiFunction<T, U, R> {
300 function: Box<dyn Fn(&T, &U) -> R>,
301 name: Option<String>,
302}
303
304// Implement BoxBiFunction
305impl<T, U, R> BoxBiFunction<T, U, R>
306where
307 T: 'static,
308 U: 'static,
309 R: 'static,
310{
311 impl_function_common_methods!(
312 BoxBiFunction<T, U, R>,
313 (Fn(&T, &U) -> R + 'static),
314 |f| Box::new(f)
315 );
316
317 impl_box_function_methods!(
318 BoxBiFunction<T, U, R>,
319 BoxConditionalBiFunction,
320 Function
321 );
322}
323
324// Implement BiFunction trait for BoxBiFunction
325impl<T, U, R> BiFunction<T, U, R> for BoxBiFunction<T, U, R> {
326 fn apply(&self, first: &T, second: &U) -> R {
327 (self.function)(first, second)
328 }
329
330 // Generates: into_box(), into_rc(), into_fn(), into_once()
331 impl_box_conversions!(
332 BoxBiFunction<T, U, R>,
333 RcBiFunction,
334 Fn(&T, &U) -> R,
335 BoxBiFunctionOnce
336 );
337}
338
339// Implement constant method for BoxBiFunction
340impl_function_constant_method!(BoxBiFunction<T, U, R>);
341
342// Implement Debug and Display for BoxBiFunction
343impl_function_debug_display!(BoxBiFunction<T, U, R>);
344
345// ============================================================================
346// RcBiFunction - Rc<dyn Fn(&T, &U) -> R>
347// ============================================================================
348
349/// RcBiFunction - single-threaded bi-function wrapper
350///
351/// A single-threaded, clonable bi-function wrapper optimized for scenarios
352/// that require sharing without thread-safety overhead.
353///
354/// # Features
355///
356/// - **Based on**: `Rc<dyn Fn(&T, &U) -> R>`
357/// - **Ownership**: Shared ownership via reference counting (non-atomic)
358/// - **Reusability**: Can be called multiple times (borrows inputs each time)
359/// - **Thread Safety**: Not thread-safe (no `Send + Sync`)
360/// - **Clonable**: Cheap cloning via `Rc::clone`
361///
362/// # Author
363///
364/// Haixing Hu
365pub struct RcBiFunction<T, U, R> {
366 function: Rc<dyn Fn(&T, &U) -> R>,
367 name: Option<String>,
368}
369
370impl<T, U, R> RcBiFunction<T, U, R>
371where
372 T: 'static,
373 U: 'static,
374 R: 'static,
375{
376 impl_function_common_methods!(
377 RcBiFunction<T, U, R>,
378 (Fn(&T, &U) -> R + 'static),
379 |f| Rc::new(f)
380 );
381
382 impl_shared_function_methods!(
383 RcBiFunction<T, U, R>,
384 RcConditionalBiFunction,
385 into_rc,
386 Function,
387 'static
388 );
389}
390
391// Implement BiFunction trait for RcBiFunction
392impl<T, U, R> BiFunction<T, U, R> for RcBiFunction<T, U, R> {
393 fn apply(&self, first: &T, second: &U) -> R {
394 (self.function)(first, second)
395 }
396
397 // Generate into_box(), into_rc(), into_fn(), into_once(), to_box(), to_rc(), to_fn(), to_once()
398 impl_rc_conversions!(
399 RcBiFunction<T, U, R>,
400 BoxBiFunction,
401 BoxBiFunctionOnce,
402 Fn(first: &T, second: &U) -> R
403 );
404}
405
406// Implement constant method for RcBiFunction
407impl_function_constant_method!(RcBiFunction<T, U, R>);
408
409// Implement Debug and Display for RcBiFunction
410impl_function_debug_display!(RcBiFunction<T, U, R>);
411
412// Implement Clone for RcBiFunction
413impl_function_clone!(RcBiFunction<T, U, R>);
414
415// ============================================================================
416// ArcBiFunction - Arc<dyn Fn(&T, &U) -> R + Send + Sync>
417// ============================================================================
418
419/// ArcBiFunction - thread-safe bi-function wrapper
420///
421/// A thread-safe, clonable bi-function wrapper suitable for multi-threaded
422/// scenarios. Can be called multiple times and shared across threads.
423///
424/// # Features
425///
426/// - **Based on**: `Arc<dyn Fn(&T, &U) -> R + Send + Sync>`
427/// - **Ownership**: Shared ownership via reference counting
428/// - **Reusability**: Can be called multiple times (borrows inputs each time)
429/// - **Thread Safety**: Thread-safe (`Send + Sync` required)
430/// - **Clonable**: Cheap cloning via `Arc::clone`
431///
432/// # Author
433///
434/// Haixing Hu
435pub struct ArcBiFunction<T, U, R> {
436 function: Arc<dyn Fn(&T, &U) -> R + Send + Sync>,
437 name: Option<String>,
438}
439
440impl<T, U, R> ArcBiFunction<T, U, R>
441where
442 T: 'static,
443 U: 'static,
444 R: 'static,
445{
446 impl_function_common_methods!(
447 ArcBiFunction<T, U, R>,
448 (Fn(&T, &U) -> R + Send + Sync + 'static),
449 |f| Arc::new(f)
450 );
451
452 impl_shared_function_methods!(
453 ArcBiFunction<T, U, R>,
454 ArcConditionalBiFunction,
455 into_arc,
456 Function,
457 Send + Sync + 'static
458 );
459}
460
461// Implement constant method for ArcBiFunction
462impl_function_constant_method!(ArcBiFunction<T, U, R>, Send + Sync + 'static);
463
464// Implement Debug and Display for ArcBiFunction
465impl_function_debug_display!(ArcBiFunction<T, U, R>);
466
467// Implement Clone for ArcBiFunction
468impl_function_clone!(ArcBiFunction<T, U, R>);
469
470// Implement BiFunction trait for ArcBiFunction
471impl<T, U, R> BiFunction<T, U, R> for ArcBiFunction<T, U, R> {
472 fn apply(&self, first: &T, second: &U) -> R {
473 (self.function)(first, second)
474 }
475
476 // Use macro to implement conversion methods
477 impl_arc_conversions!(
478 ArcBiFunction<T, U, R>,
479 BoxBiFunction,
480 RcBiFunction,
481 BoxBiFunctionOnce,
482 Fn(t: &T, u: &U) -> R
483 );
484}
485
486// ============================================================================
487// Blanket implementation for standard Fn trait
488// ============================================================================
489
490// Implement BiFunction<T, U, R> for any type that implements Fn(&T, &U) -> R
491impl_closure_trait!(
492 BiFunction<T, U, R>,
493 apply,
494 BoxBiFunctionOnce,
495 Fn(first: &T, second: &U) -> R
496);
497
498// ============================================================================
499// FnBiFunctionOps - Extension trait for Fn(&T, &U) -> R bi-functions
500// ============================================================================
501
502/// Extension trait for closures implementing `Fn(&T, &U) -> R`
503///
504/// Provides composition methods (`and_then`, `when`) for bi-function
505/// closures and function pointers without requiring explicit wrapping in
506/// `BoxBiFunction`.
507///
508/// This trait is automatically implemented for all closures and function
509/// pointers that implement `Fn(&T, &U) -> R`.
510///
511/// # Design Rationale
512///
513/// While closures automatically implement `BiFunction<T, U, R>` through
514/// blanket implementation, they don't have access to instance methods like
515/// `and_then` and `when`. This extension trait provides those methods,
516/// returning `BoxBiFunction` for maximum flexibility.
517///
518/// # Examples
519///
520/// ## Chain composition with and_then
521///
522/// ```rust
523/// use prism3_function::{BiFunction, FnBiFunctionOps};
524///
525/// let add = |x: &i32, y: &i32| *x + *y;
526/// let double = |x: i32| x * 2;
527///
528/// let composed = add.and_then(double);
529/// assert_eq!(composed.apply(&3, &5), 16); // (3 + 5) * 2
530/// ```
531///
532/// ## Conditional execution with when
533///
534/// ```rust
535/// use prism3_function::{BiFunction, FnBiFunctionOps};
536///
537/// let add = |x: &i32, y: &i32| *x + *y;
538/// let multiply = |x: &i32, y: &i32| *x * *y;
539///
540/// let conditional = add.when(|x: &i32, y: &i32| *x > 0 && *y > 0).or_else(multiply);
541///
542/// assert_eq!(conditional.apply(&5, &3), 8); // add
543/// assert_eq!(conditional.apply(&-5, &3), -15); // multiply
544/// ```
545///
546/// # Author
547///
548/// Haixing Hu
549pub trait FnBiFunctionOps<T, U, R>: Fn(&T, &U) -> R + Sized + 'static {
550 /// Chain composition - applies self first, then after
551 ///
552 /// Creates a new bi-function that applies this bi-function first,
553 /// then applies the after function to the result. Consumes self and
554 /// returns a `BoxBiFunction`.
555 ///
556 /// # Type Parameters
557 ///
558 /// * `S` - The output type of the after function
559 /// * `F` - The type of the after function (must implement Function<R, S>)
560 ///
561 /// # Parameters
562 ///
563 /// * `after` - The function to apply after self. **Note: This parameter
564 /// is passed by value and will transfer ownership.** If you need to
565 /// preserve the original function, clone it first (if it implements
566 /// `Clone`). Can be:
567 /// - A closure: `|x: R| -> S`
568 /// - A function pointer: `fn(R) -> S`
569 /// - A `BoxFunction<R, S>`
570 /// - An `RcFunction<R, S>`
571 /// - An `ArcFunction<R, S>`
572 /// - Any type implementing `Function<R, S>`
573 ///
574 /// # Returns
575 ///
576 /// A new `BoxBiFunction<T, U, S>` representing the composition
577 ///
578 /// # Examples
579 ///
580 /// ## Direct value passing (ownership transfer)
581 ///
582 /// ```rust
583 /// use prism3_function::{BiFunction, FnBiFunctionOps,
584 /// BoxFunction};
585 ///
586 /// let add = |x: &i32, y: &i32| *x + *y;
587 /// let to_string = BoxFunction::new(|x: i32| x.to_string());
588 ///
589 /// // to_string is moved here
590 /// let composed = add.and_then(to_string);
591 /// assert_eq!(composed.apply(&20, &22), "42");
592 /// // to_string.apply(10); // Would not compile - moved
593 /// ```
594 ///
595 /// ## Preserving original with clone
596 ///
597 /// ```rust
598 /// use prism3_function::{BiFunction, FnBiFunctionOps,
599 /// BoxFunction};
600 ///
601 /// let add = |x: &i32, y: &i32| *x + *y;
602 /// let to_string = BoxFunction::new(|x: i32| x.to_string());
603 ///
604 /// // Clone to preserve original
605 /// let composed = add.and_then(to_string.clone());
606 /// assert_eq!(composed.apply(&20, &22), "42");
607 ///
608 /// // Original still usable
609 /// assert_eq!(to_string.apply(&10), "10");
610 /// ```
611 fn and_then<S, F>(self, after: F) -> BoxBiFunction<T, U, S>
612 where
613 S: 'static,
614 F: crate::functions::function::Function<R, S> + 'static,
615 T: 'static,
616 U: 'static,
617 R: 'static,
618 {
619 BoxBiFunction::new(move |t: &T, u: &U| after.apply(&self(t, u)))
620 }
621
622 /// Creates a conditional bi-function
623 ///
624 /// Returns a bi-function that only executes when a bi-predicate is
625 /// satisfied. You must call `or_else()` to provide an alternative
626 /// bi-function for when the condition is not satisfied.
627 ///
628 /// # Parameters
629 ///
630 /// * `predicate` - The condition to check. **Note: This parameter is passed
631 /// by value and will transfer ownership.** If you need to preserve the
632 /// original bi-predicate, clone it first (if it implements `Clone`).
633 /// Can be:
634 /// - A closure: `|x: &T, y: &U| -> bool`
635 /// - A function pointer: `fn(&T, &U) -> bool`
636 /// - A `BoxBiPredicate<T, U>`
637 /// - An `RcBiPredicate<T, U>`
638 /// - An `ArcBiPredicate<T, U>`
639 /// - Any type implementing `BiPredicate<T, U>`
640 ///
641 /// # Returns
642 ///
643 /// Returns `BoxConditionalBiFunction<T, U, R>`
644 ///
645 /// # Examples
646 ///
647 /// ## Basic usage with or_else
648 ///
649 /// ```rust
650 /// use prism3_function::{BiFunction, FnBiFunctionOps};
651 ///
652 /// let add = |x: &i32, y: &i32| *x + *y;
653 /// let conditional = add.when(|x: &i32, y: &i32| *x > 0)
654 /// .or_else(|x: &i32, y: &i32| *x * *y);
655 ///
656 /// assert_eq!(conditional.apply(&5, &3), 8);
657 /// assert_eq!(conditional.apply(&-5, &3), -15);
658 /// ```
659 ///
660 /// ## Preserving bi-predicate with clone
661 ///
662 /// ```rust
663 /// use prism3_function::{BiFunction, FnBiFunctionOps,
664 /// RcBiPredicate};
665 ///
666 /// let add = |x: &i32, y: &i32| *x + *y;
667 /// let both_positive = RcBiPredicate::new(|x: &i32, y: &i32|
668 /// *x > 0 && *y > 0);
669 ///
670 /// // Clone to preserve original bi-predicate
671 /// let conditional = add.when(both_positive.clone())
672 /// .or_else(|x: &i32, y: &i32| *x * *y);
673 ///
674 /// assert_eq!(conditional.apply(&5, &3), 8);
675 ///
676 /// // Original bi-predicate still usable
677 /// assert!(both_positive.test(&5, &3));
678 /// ```
679 fn when<P>(self, predicate: P) -> BoxConditionalBiFunction<T, U, R>
680 where
681 P: BiPredicate<T, U> + 'static,
682 T: 'static,
683 U: 'static,
684 R: 'static,
685 {
686 BoxBiFunction::new(self).when(predicate)
687 }
688}
689
690/// Blanket implementation of FnBiFunctionOps for all closures
691///
692/// Automatically implements `FnBiFunctionOps<T, U, R>` for any type that
693/// implements `Fn(&T, &U) -> R`.
694///
695/// # Author
696///
697/// Haixing Hu
698impl<T, U, R, F> FnBiFunctionOps<T, U, R> for F where F: Fn(&T, &U) -> R + 'static {}
699
700// ============================================================================
701// Type Aliases for BinaryOperator (BiFunction<T, T, R>)
702// ============================================================================
703
704/// Type alias for `BoxBiFunction<T, T, R>`
705///
706/// Represents a binary function that takes two values of type `T` and produces
707/// a value of type `R`, with single ownership semantics. Similar to Java's
708/// `BiFunction<T, T, R>` but with different type parameters.
709///
710/// # Examples
711///
712/// ```rust
713/// use prism3_function::{BoxBinaryFunction, BiFunction};
714///
715/// let add: BoxBinaryFunction<i32, i32> = BoxBinaryFunction::new(|x, y| *x + *y);
716/// assert_eq!(add.apply(&20, &22), 42);
717/// ```
718///
719/// # Author
720///
721/// Haixing Hu
722pub type BoxBinaryFunction<T, R> = BoxBiFunction<T, T, R>;
723
724/// Type alias for `ArcBiFunction<T, T, R>`
725///
726/// Represents a thread-safe binary function that takes two values of type `T`
727/// and produces a value of type `R`. Similar to Java's `BiFunction<T, T, R>`
728/// with shared, thread-safe ownership.
729///
730/// # Examples
731///
732/// ```rust
733/// use prism3_function::{ArcBinaryFunction, BiFunction};
734///
735/// let multiply: ArcBinaryFunction<i32, i32> = ArcBinaryFunction::new(|x, y| *x * *y);
736/// let multiply_clone = multiply.clone();
737/// assert_eq!(multiply.apply(&6, &7), 42);
738/// assert_eq!(multiply_clone.apply(&6, &7), 42);
739/// ```
740///
741/// # Author
742///
743/// Haixing Hu
744pub type ArcBinaryFunction<T, R> = ArcBiFunction<T, T, R>;
745
746/// Type alias for `RcBiFunction<T, T, R>`
747///
748/// Represents a single-threaded binary function that takes two values of type `T`
749/// and produces a value of type `R`. Similar to Java's `BiFunction<T, T, R>`
750/// with shared, single-threaded ownership.
751///
752/// # Examples
753///
754/// ```rust
755/// use prism3_function::{RcBinaryFunction, BiFunction};
756///
757/// let max: RcBinaryFunction<i32, i32> = RcBinaryFunction::new(|x, y| if x > y { *x } else { *y });
758/// let max_clone = max.clone();
759/// assert_eq!(max.apply(&30, &42), 42);
760/// assert_eq!(max_clone.apply(&30, &42), 42);
761/// ```
762///
763/// # Author
764///
765/// Haixing Hu
766pub type RcBinaryFunction<T, R> = RcBiFunction<T, T, R>;
767
768// ============================================================================
769// BoxConditionalBiFunction - Box-based Conditional BiFunction
770// ============================================================================
771
772/// BoxConditionalBiFunction struct
773///
774/// A conditional bi-function that only executes when a bi-predicate is
775/// satisfied. Uses `BoxBiFunction` and `BoxBiPredicate` for single
776/// ownership semantics.
777///
778/// This type is typically created by calling `BoxBiFunction::when()` and is
779/// designed to work with the `or_else()` method to create if-then-else logic.
780///
781/// # Features
782///
783/// - **Single Ownership**: Not cloneable, consumes `self` on use
784/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
785/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
786/// - **Implements BiFunction**: Can be used anywhere a `BiFunction` is expected
787///
788/// # Examples
789///
790/// ## With or_else Branch
791///
792/// ```rust
793/// use prism3_function::{BiFunction, BoxBiFunction};
794///
795/// let add = BoxBiFunction::new(|x: &i32, y: &i32| *x + *y);
796/// let multiply = BoxBiFunction::new(|x: &i32, y: &i32| *x * *y);
797/// let conditional = add.when(|x: &i32, y: &i32| *x > 0).or_else(multiply);
798///
799/// assert_eq!(conditional.apply(&5, &3), 8); // when branch executed
800/// assert_eq!(conditional.apply(&-5, &3), -15); // or_else branch executed
801/// ```
802///
803/// # Author
804///
805/// Haixing Hu
806pub struct BoxConditionalBiFunction<T, U, R> {
807 function: BoxBiFunction<T, U, R>,
808 predicate: BoxBiPredicate<T, U>,
809}
810
811// Implement BoxConditionalBiFunction
812impl_box_conditional_function!(
813 BoxConditionalBiFunction<T, U, R>,
814 BoxBiFunction,
815 BiFunction
816);
817
818// Use macro to generate Debug and Display implementations
819impl_conditional_function_debug_display!(BoxConditionalBiFunction<T, U, R>);
820
821// ============================================================================
822// RcConditionalBiFunction - Rc-based Conditional BiFunction
823// ============================================================================
824
825/// RcConditionalBiFunction struct
826///
827/// A single-threaded conditional bi-function that only executes when a
828/// bi-predicate is satisfied. Uses `RcBiFunction` and `RcBiPredicate` for
829/// shared ownership within a single thread.
830///
831/// This type is typically created by calling `RcBiFunction::when()` and is
832/// designed to work with the `or_else()` method to create if-then-else logic.
833///
834/// # Features
835///
836/// - **Shared Ownership**: Cloneable via `Rc`, multiple owners allowed
837/// - **Single-Threaded**: Not thread-safe, cannot be sent across threads
838/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
839/// - **No Lock Overhead**: More efficient than `ArcConditionalBiFunction`
840///
841/// # Examples
842///
843/// ```rust
844/// use prism3_function::{BiFunction, RcBiFunction};
845///
846/// let add = RcBiFunction::new(|x: &i32, y: &i32| *x + *y);
847/// let multiply = RcBiFunction::new(|x: &i32, y: &i32| *x * *y);
848/// let conditional = add.when(|x: &i32, y: &i32| *x > 0).or_else(multiply);
849///
850/// let conditional_clone = conditional.clone();
851///
852/// assert_eq!(conditional.apply(&5, &3), 8);
853/// assert_eq!(conditional_clone.apply(&-5, &3), -15);
854/// ```
855///
856/// # Author
857///
858/// Haixing Hu
859pub struct RcConditionalBiFunction<T, U, R> {
860 function: RcBiFunction<T, U, R>,
861 predicate: RcBiPredicate<T, U>,
862}
863
864// Implement RcConditionalBiFunction
865impl_shared_conditional_function!(
866 RcConditionalBiFunction<T, U, R>,
867 RcBiFunction,
868 BiFunction,
869 into_rc,
870 'static
871);
872
873// Use macro to generate Debug and Display implementations
874impl_conditional_function_debug_display!(RcConditionalBiFunction<T, U, R>);
875
876// Implement Clone for RcConditionalBiFunction
877impl_conditional_function_clone!(RcConditionalBiFunction<T, U, R>);
878
879// ============================================================================
880// ArcConditionalBiFunction - Arc-based Conditional BiFunction
881// ============================================================================
882
883/// ArcConditionalBiFunction struct
884///
885/// A thread-safe conditional bi-function that only executes when a
886/// bi-predicate is satisfied. Uses `ArcBiFunction` and `ArcBiPredicate` for
887/// shared ownership across threads.
888///
889/// This type is typically created by calling `ArcBiFunction::when()` and is
890/// designed to work with the `or_else()` method to create if-then-else logic.
891///
892/// # Features
893///
894/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
895/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
896/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
897/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
898///
899/// # Examples
900///
901/// ```rust
902/// use prism3_function::{BiFunction, ArcBiFunction};
903///
904/// let add = ArcBiFunction::new(|x: &i32, y: &i32| *x + *y);
905/// let multiply = ArcBiFunction::new(|x: &i32, y: &i32| *x * *y);
906/// let conditional = add.when(|x: &i32, y: &i32| *x > 0).or_else(multiply);
907///
908/// let conditional_clone = conditional.clone();
909///
910/// assert_eq!(conditional.apply(&5, &3), 8);
911/// assert_eq!(conditional_clone.apply(&-5, &3), -15);
912/// ```
913///
914/// # Author
915///
916/// Haixing Hu
917pub struct ArcConditionalBiFunction<T, U, R> {
918 function: ArcBiFunction<T, U, R>,
919 predicate: ArcBiPredicate<T, U>,
920}
921
922// Implement ArcConditionalBiFunction
923impl_shared_conditional_function!(
924 ArcConditionalBiFunction<T, U, R>,
925 ArcBiFunction,
926 BiFunction,
927 into_arc,
928 Send + Sync + 'static
929);
930
931// Implement Debug and Display for ArcConditionalBiFunction
932impl_conditional_function_debug_display!(ArcConditionalBiFunction<T, U, R>);
933
934// Implement Clone for ArcConditionalBiFunction
935impl_conditional_function_clone!(ArcConditionalBiFunction<T, U, R>);