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