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