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, 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, 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};
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 /// BoxFunction};
553 ///
554 /// let add = |x: &i32, y: &i32| *x + *y;
555 /// let to_string = BoxFunction::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 /// assert!(both_positive.test(&5, &3));
632 /// ```
633 fn when<P>(self, predicate: P) -> BoxConditionalBiFunction<T, U, R>
634 where
635 Self: 'static,
636 P: BiPredicate<T, U> + 'static,
637 T: 'static,
638 U: 'static,
639 R: 'static,
640 {
641 BoxBiFunction::new(self).when(predicate)
642 }
643}
644
645/// Blanket implementation of FnBiFunctionOps for all closures
646///
647/// Automatically implements `FnBiFunctionOps<T, U, R>` for any type that
648/// implements `Fn(&T, &U) -> R`.
649///
650/// # Author
651///
652/// Haixing Hu
653impl<T, U, R, F> FnBiFunctionOps<T, U, R> for F where F: Fn(&T, &U) -> R {}
654
655// ============================================================================
656// Type Aliases for BinaryOperator (BiFunction<T, T, R>)
657// ============================================================================
658
659/// Type alias for `BoxBiFunction<T, T, R>`
660///
661/// Represents a binary function that takes two values of type `T` and produces
662/// a value of type `R`, with single ownership semantics. Similar to Java's
663/// `BiFunction<T, T, R>` but with different type parameters.
664///
665/// # Examples
666///
667/// ```rust
668/// use qubit_function::{BoxBinaryFunction, BiFunction};
669///
670/// let add: BoxBinaryFunction<i32, i32> = BoxBinaryFunction::new(|x, y| *x + *y);
671/// assert_eq!(add.apply(&20, &22), 42);
672/// ```
673///
674/// # Author
675///
676/// Haixing Hu
677pub type BoxBinaryFunction<T, R> = BoxBiFunction<T, T, R>;
678
679/// Type alias for `ArcBiFunction<T, T, R>`
680///
681/// Represents a thread-safe binary function that takes two values of type `T`
682/// and produces a value of type `R`. Similar to Java's `BiFunction<T, T, R>`
683/// with shared, thread-safe ownership.
684///
685/// # Examples
686///
687/// ```rust
688/// use qubit_function::{ArcBinaryFunction, BiFunction};
689///
690/// let multiply: ArcBinaryFunction<i32, i32> = ArcBinaryFunction::new(|x, y| *x * *y);
691/// let multiply_clone = multiply.clone();
692/// assert_eq!(multiply.apply(&6, &7), 42);
693/// assert_eq!(multiply_clone.apply(&6, &7), 42);
694/// ```
695///
696/// # Author
697///
698/// Haixing Hu
699pub type ArcBinaryFunction<T, R> = ArcBiFunction<T, T, R>;
700
701/// Type alias for `RcBiFunction<T, T, R>`
702///
703/// Represents a single-threaded binary function that takes two values of type `T`
704/// and produces a value of type `R`. Similar to Java's `BiFunction<T, T, R>`
705/// with shared, single-threaded ownership.
706///
707/// # Examples
708///
709/// ```rust
710/// use qubit_function::{RcBinaryFunction, BiFunction};
711///
712/// let max: RcBinaryFunction<i32, i32> = RcBinaryFunction::new(|x, y| if x > y { *x } else { *y });
713/// let max_clone = max.clone();
714/// assert_eq!(max.apply(&30, &42), 42);
715/// assert_eq!(max_clone.apply(&30, &42), 42);
716/// ```
717///
718/// # Author
719///
720/// Haixing Hu
721pub type RcBinaryFunction<T, R> = RcBiFunction<T, T, R>;
722
723// ============================================================================
724// BoxConditionalBiFunction - Box-based Conditional BiFunction
725// ============================================================================
726
727/// BoxConditionalBiFunction struct
728///
729/// A conditional bi-function that only executes when a bi-predicate is
730/// satisfied. Uses `BoxBiFunction` and `BoxBiPredicate` for single
731/// ownership semantics.
732///
733/// This type is typically created by calling `BoxBiFunction::when()` and is
734/// designed to work with the `or_else()` method to create if-then-else logic.
735///
736/// # Features
737///
738/// - **Single Ownership**: Not cloneable, consumes `self` on use
739/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
740/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
741/// - **Implements BiFunction**: Can be used anywhere a `BiFunction` is expected
742///
743/// # Examples
744///
745/// ## With or_else Branch
746///
747/// ```rust
748/// use qubit_function::{BiFunction, BoxBiFunction};
749///
750/// let add = BoxBiFunction::new(|x: &i32, y: &i32| *x + *y);
751/// let multiply = BoxBiFunction::new(|x: &i32, y: &i32| *x * *y);
752/// let conditional = add.when(|x: &i32, y: &i32| *x > 0).or_else(multiply);
753///
754/// assert_eq!(conditional.apply(&5, &3), 8); // when branch executed
755/// assert_eq!(conditional.apply(&-5, &3), -15); // or_else branch executed
756/// ```
757///
758/// # Author
759///
760/// Haixing Hu
761pub struct BoxConditionalBiFunction<T, U, R> {
762 function: BoxBiFunction<T, U, R>,
763 predicate: BoxBiPredicate<T, U>,
764}
765
766// Implement BoxConditionalBiFunction
767impl_box_conditional_function!(
768 BoxConditionalBiFunction<T, U, R>,
769 BoxBiFunction,
770 BiFunction
771);
772
773// Use macro to generate Debug and Display implementations
774impl_conditional_function_debug_display!(BoxConditionalBiFunction<T, U, R>);
775
776// ============================================================================
777// RcConditionalBiFunction - Rc-based Conditional BiFunction
778// ============================================================================
779
780/// RcConditionalBiFunction struct
781///
782/// A single-threaded conditional bi-function that only executes when a
783/// bi-predicate is satisfied. Uses `RcBiFunction` and `RcBiPredicate` for
784/// shared ownership within a single thread.
785///
786/// This type is typically created by calling `RcBiFunction::when()` and is
787/// designed to work with the `or_else()` method to create if-then-else logic.
788///
789/// # Features
790///
791/// - **Shared Ownership**: Cloneable via `Rc`, multiple owners allowed
792/// - **Single-Threaded**: Not thread-safe, cannot be sent across threads
793/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
794/// - **No Lock Overhead**: More efficient than `ArcConditionalBiFunction`
795///
796/// # Examples
797///
798/// ```rust
799/// use qubit_function::{BiFunction, RcBiFunction};
800///
801/// let add = RcBiFunction::new(|x: &i32, y: &i32| *x + *y);
802/// let multiply = RcBiFunction::new(|x: &i32, y: &i32| *x * *y);
803/// let conditional = add.when(|x: &i32, y: &i32| *x > 0).or_else(multiply);
804///
805/// let conditional_clone = conditional.clone();
806///
807/// assert_eq!(conditional.apply(&5, &3), 8);
808/// assert_eq!(conditional_clone.apply(&-5, &3), -15);
809/// ```
810///
811/// # Author
812///
813/// Haixing Hu
814pub struct RcConditionalBiFunction<T, U, R> {
815 function: RcBiFunction<T, U, R>,
816 predicate: RcBiPredicate<T, U>,
817}
818
819// Implement RcConditionalBiFunction
820impl_shared_conditional_function!(
821 RcConditionalBiFunction<T, U, R>,
822 RcBiFunction,
823 BiFunction,
824 into_rc,
825 'static
826);
827
828// Use macro to generate Debug and Display implementations
829impl_conditional_function_debug_display!(RcConditionalBiFunction<T, U, R>);
830
831// Implement Clone for RcConditionalBiFunction
832impl_conditional_function_clone!(RcConditionalBiFunction<T, U, R>);
833
834// ============================================================================
835// ArcConditionalBiFunction - Arc-based Conditional BiFunction
836// ============================================================================
837
838/// ArcConditionalBiFunction struct
839///
840/// A thread-safe conditional bi-function that only executes when a
841/// bi-predicate is satisfied. Uses `ArcBiFunction` and `ArcBiPredicate` for
842/// shared ownership across threads.
843///
844/// This type is typically created by calling `ArcBiFunction::when()` and is
845/// designed to work with the `or_else()` method to create if-then-else logic.
846///
847/// # Features
848///
849/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
850/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
851/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
852/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
853///
854/// # Examples
855///
856/// ```rust
857/// use qubit_function::{BiFunction, ArcBiFunction};
858///
859/// let add = ArcBiFunction::new(|x: &i32, y: &i32| *x + *y);
860/// let multiply = ArcBiFunction::new(|x: &i32, y: &i32| *x * *y);
861/// let conditional = add.when(|x: &i32, y: &i32| *x > 0).or_else(multiply);
862///
863/// let conditional_clone = conditional.clone();
864///
865/// assert_eq!(conditional.apply(&5, &3), 8);
866/// assert_eq!(conditional_clone.apply(&-5, &3), -15);
867/// ```
868///
869/// # Author
870///
871/// Haixing Hu
872pub struct ArcConditionalBiFunction<T, U, R> {
873 function: ArcBiFunction<T, U, R>,
874 predicate: ArcBiPredicate<T, U>,
875}
876
877// Implement ArcConditionalBiFunction
878impl_shared_conditional_function!(
879 ArcConditionalBiFunction<T, U, R>,
880 ArcBiFunction,
881 BiFunction,
882 into_arc,
883 Send + Sync + 'static
884);
885
886// Implement Debug and Display for ArcConditionalBiFunction
887impl_conditional_function_debug_display!(ArcConditionalBiFunction<T, U, R>);
888
889// Implement Clone for ArcConditionalBiFunction
890impl_conditional_function_clone!(ArcConditionalBiFunction<T, U, R>);