prism3_function/bi_predicate.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025.
4 * 3-Prism Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # BiPredicate Abstraction
10//!
11//! Provides a Rust implementation similar to Java's `BiPredicate`
12//! interface for testing whether two values satisfy a condition.
13//!
14//! ## Core Semantics
15//!
16//! A **BiPredicate** is fundamentally a pure judgment operation that
17//! tests whether two values satisfy a specific condition. It should
18//! be:
19//!
20//! - **Read-only**: Does not modify the tested values
21//! - **Side-effect free**: Does not change external state (from the
22//! user's perspective)
23//! - **Repeatable**: Same inputs should produce the same result
24//! - **Deterministic**: Judgment logic should be predictable
25//!
26//! ## Design Philosophy
27//!
28//! This module follows the same principles as the `Predicate` module:
29//!
30//! 1. **Single Trait**: Only one `BiPredicate<T, U>` trait with
31//! `&self`, keeping the API simple and semantically clear
32//! 2. **No BiPredicateMut**: All stateful scenarios use interior
33//! mutability (`RefCell`, `Cell`, `Mutex`) instead of `&mut self`
34//! 3. **No BiPredicateOnce**: Violates bi-predicate semantics -
35//! judgments should be repeatable
36//! 4. **Three Implementations**: `BoxBiPredicate`, `RcBiPredicate`,
37//! and `ArcBiPredicate` cover all ownership scenarios
38//!
39//! ## Type Selection Guide
40//!
41//! | Scenario | Recommended Type | Reason |
42//! |----------|------------------|--------|
43//! | One-time use | `BoxBiPredicate` | Single ownership, no overhead |
44//! | Multi-threaded | `ArcBiPredicate` | Thread-safe, clonable |
45//! | Single-threaded reuse | `RcBiPredicate` | Better performance |
46//! | Stateful predicate | Any type + `RefCell`/`Cell`/`Mutex` | Interior mutability |
47//!
48//! ## Examples
49//!
50//! ### Basic Usage with Closures
51//!
52//! ```rust
53//! use prism3_function::bi_predicate::BiPredicate;
54//!
55//! let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
56//! assert!(is_sum_positive.test(&5, &3));
57//! assert!(!is_sum_positive.test(&-3, &-7));
58//! ```
59//!
60//! ### BoxBiPredicate - Single Ownership
61//!
62//! ```rust
63//! use prism3_function::bi_predicate::{BiPredicate, BoxBiPredicate};
64//!
65//! let pred = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0)
66//! .and(BoxBiPredicate::new(|x, y| x > y));
67//! assert!(pred.test(&10, &5));
68//! ```
69//!
70//! ### Closure Composition with Extension Methods
71//!
72//! Closures automatically gain `and`, `or`, `not` methods through the
73//! `FnBiPredicateOps` extension trait, returning `BoxBiPredicate`:
74//!
75//! ```rust
76//! use prism3_function::bi_predicate::{BiPredicate,
77//! FnBiPredicateOps};
78//!
79//! // Compose closures directly - result is BoxBiPredicate
80//! let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
81//! let first_larger = |x: &i32, y: &i32| x > y;
82//!
83//! let combined = is_sum_positive.and(first_larger);
84//! assert!(combined.test(&10, &5));
85//! assert!(!combined.test(&3, &8));
86//!
87//! // Use `or` for disjunction
88//! let negative_sum = |x: &i32, y: &i32| x + y < 0;
89//! let both_large = |x: &i32, y: &i32| *x > 100 && *y > 100;
90//! let either = negative_sum.or(both_large);
91//! assert!(either.test(&-10, &5));
92//! assert!(either.test(&200, &150));
93//! ```
94//!
95//! ### RcBiPredicate - Single-threaded Reuse
96//!
97//! ```rust
98//! use prism3_function::bi_predicate::{BiPredicate, RcBiPredicate};
99//!
100//! let pred = RcBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
101//! let combined1 = pred.and(RcBiPredicate::new(|x, y| x > y));
102//! let combined2 = pred.or(RcBiPredicate::new(|x, y| *x > 100));
103//!
104//! // Original predicate is still usable
105//! assert!(pred.test(&5, &3));
106//! ```
107//!
108//! ### ArcBiPredicate - Thread-safe Sharing
109//!
110//! ```rust
111//! use prism3_function::bi_predicate::{BiPredicate, ArcBiPredicate};
112//! use std::thread;
113//!
114//! let pred = ArcBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
115//! let pred_clone = pred.clone();
116//!
117//! let handle = thread::spawn(move || {
118//! pred_clone.test(&10, &5)
119//! });
120//!
121//! assert!(handle.join().unwrap());
122//! assert!(pred.test(&3, &7)); // Original still usable
123//! ```
124//!
125//! ### Stateful BiPredicates with Interior Mutability
126//!
127//! ```rust
128//! use prism3_function::bi_predicate::{BiPredicate, BoxBiPredicate};
129//! use std::cell::Cell;
130//!
131//! let count = Cell::new(0);
132//! let pred = BoxBiPredicate::new(move |x: &i32, y: &i32| {
133//! count.set(count.get() + 1);
134//! x + y > 0
135//! });
136//!
137//! // No need for `mut` - interior mutability handles state
138//! assert!(pred.test(&5, &3));
139//! assert!(!pred.test(&-8, &-3));
140//! ```
141//!
142//! ## Author
143//!
144//! Haixing Hu
145
146use std::fmt::{Debug, Display};
147use std::rc::Rc;
148use std::sync::Arc;
149
150/// Type alias for bi-predicate function to simplify complex types.
151///
152/// This type alias represents a function that takes two references and returns a boolean.
153/// It is used to reduce type complexity in struct definitions.
154type BiPredicateFn<T, U> = dyn Fn(&T, &U) -> bool;
155
156/// Type alias for thread-safe bi-predicate function to simplify complex types.
157///
158/// This type alias represents a function that takes two references and returns a boolean,
159/// with Send + Sync bounds for thread-safe usage. It is used to reduce type complexity
160/// in Arc-based struct definitions.
161type SendSyncBiPredicateFn<T, U> = dyn Fn(&T, &U) -> bool + Send + Sync;
162
163/// BiPredicate name constant for always-true bi-predicates
164const ALWAYS_TRUE_NAME: &str = "always_true";
165
166/// BiPredicate name constant for always-false bi-predicates
167const ALWAYS_FALSE_NAME: &str = "always_false";
168
169/// A bi-predicate trait for testing whether two values satisfy a
170/// condition.
171///
172/// This trait represents a **pure judgment operation** - it tests
173/// whether two given values meet certain criteria without modifying
174/// either the values or the bi-predicate itself (from the user's
175/// perspective). This semantic clarity distinguishes bi-predicates
176/// from consumers or transformers.
177///
178/// ## Design Rationale
179///
180/// This is a **minimal trait** that only defines:
181/// - The core `test` method using `&self` (immutable borrow)
182/// - Type conversion methods (`into_box`, `into_rc`, `into_arc`)
183/// - Closure conversion method (`into_fn`)
184///
185/// Logical composition methods (`and`, `or`, `not`, `xor`, `nand`,
186/// `nor`) are intentionally **not** part of the trait. Instead, they
187/// are implemented on concrete types (`BoxBiPredicate`,
188/// `RcBiPredicate`, `ArcBiPredicate`), allowing each implementation
189/// to maintain its specific ownership characteristics:
190///
191/// - `BoxBiPredicate`: Methods consume `self` (single ownership)
192/// - `RcBiPredicate`: Methods borrow `&self` (shared ownership)
193/// - `ArcBiPredicate`: Methods borrow `&self` (thread-safe shared
194/// ownership)
195///
196/// ## Why `&self` Instead of `&mut self`?
197///
198/// Bi-predicates use `&self` because:
199///
200/// 1. **Semantic Clarity**: A bi-predicate is a judgment, not a
201/// mutation
202/// 2. **Flexibility**: Can be used in immutable contexts
203/// 3. **Simplicity**: No need for `mut` in user code
204/// 4. **Interior Mutability**: State (if needed) can be managed with
205/// `RefCell`, `Cell`, or `Mutex`
206///
207/// ## Automatic Implementation for Closures
208///
209/// Any closure matching `Fn(&T, &U) -> bool` automatically implements
210/// this trait, providing seamless integration with Rust's closure
211/// system.
212///
213/// ## Examples
214///
215/// ### Basic Usage
216///
217/// ```rust
218/// use prism3_function::bi_predicate::BiPredicate;
219///
220/// let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
221/// assert!(is_sum_positive.test(&5, &3));
222/// assert!(!is_sum_positive.test(&-5, &-3));
223/// ```
224///
225/// ### Type Conversion
226///
227/// ```rust
228/// use prism3_function::bi_predicate::{BiPredicate,
229/// BoxBiPredicate};
230///
231/// let closure = |x: &i32, y: &i32| x + y > 0;
232/// let boxed: BoxBiPredicate<i32, i32> = closure.into_box();
233/// assert!(boxed.test(&5, &3));
234/// ```
235///
236/// ### Stateful BiPredicate with Interior Mutability
237///
238/// ```rust
239/// use prism3_function::bi_predicate::{BiPredicate,
240/// BoxBiPredicate};
241/// use std::cell::Cell;
242///
243/// let count = Cell::new(0);
244/// let counting_pred = BoxBiPredicate::new(move |x: &i32, y: &i32| {
245/// count.set(count.get() + 1);
246/// x + y > 0
247/// });
248///
249/// // Note: No `mut` needed - interior mutability handles state
250/// assert!(counting_pred.test(&5, &3));
251/// assert!(!counting_pred.test(&-5, &-3));
252/// ```
253///
254/// ## Author
255///
256/// Haixing Hu
257pub trait BiPredicate<T, U> {
258 /// Tests whether the given values satisfy this bi-predicate.
259 ///
260 /// # Parameters
261 ///
262 /// * `first` - The first value to test.
263 /// * `second` - The second value to test.
264 ///
265 /// # Returns
266 ///
267 /// `true` if the values satisfy this bi-predicate, `false`
268 /// otherwise.
269 fn test(&self, first: &T, second: &U) -> bool;
270
271 /// Converts this bi-predicate into a `BoxBiPredicate`.
272 ///
273 /// # Returns
274 ///
275 /// A `BoxBiPredicate` wrapping this bi-predicate.
276 ///
277 /// # Default Implementation
278 ///
279 /// The default implementation wraps the bi-predicate in a
280 /// closure that calls `test`, providing automatic conversion
281 /// for custom types that only implement the core `test`
282 /// method.
283 fn into_box(self) -> BoxBiPredicate<T, U>
284 where
285 Self: Sized + 'static,
286 T: 'static,
287 U: 'static,
288 {
289 BoxBiPredicate::new(move |first, second| self.test(first, second))
290 }
291
292 /// Converts this bi-predicate into an `RcBiPredicate`.
293 ///
294 /// # Returns
295 ///
296 /// An `RcBiPredicate` wrapping this bi-predicate.
297 ///
298 /// # Default Implementation
299 ///
300 /// The default implementation wraps the bi-predicate in a
301 /// closure that calls `test`, providing automatic conversion
302 /// for custom types that only implement the core `test`
303 /// method.
304 fn into_rc(self) -> RcBiPredicate<T, U>
305 where
306 Self: Sized + 'static,
307 T: 'static,
308 U: 'static,
309 {
310 RcBiPredicate::new(move |first, second| self.test(first, second))
311 }
312
313 /// Converts this bi-predicate into an `ArcBiPredicate`.
314 ///
315 /// # Returns
316 ///
317 /// An `ArcBiPredicate` wrapping this bi-predicate.
318 ///
319 /// # Default Implementation
320 ///
321 /// The default implementation wraps the bi-predicate in a
322 /// closure that calls `test`, providing automatic conversion
323 /// for custom types that only implement the core `test`
324 /// method. Note that this requires `Send + Sync` bounds for
325 /// thread-safe sharing.
326 fn into_arc(self) -> ArcBiPredicate<T, U>
327 where
328 Self: Sized + Send + Sync + 'static,
329 T: Send + Sync + 'static,
330 U: Send + Sync + 'static,
331 {
332 ArcBiPredicate::new(move |first, second| self.test(first, second))
333 }
334
335 /// Converts this bi-predicate into a closure that can be used
336 /// directly with standard library methods.
337 ///
338 /// This method consumes the bi-predicate and returns a closure
339 /// with signature `Fn(&T, &U) -> bool`. Since `Fn` is a subtrait
340 /// of `FnMut`, the returned closure can be used in any context
341 /// that requires either `Fn(&T, &U) -> bool` or
342 /// `FnMut(&T, &U) -> bool`.
343 ///
344 /// # Returns
345 ///
346 /// A closure implementing `Fn(&T, &U) -> bool` (also usable as
347 /// `FnMut(&T, &U) -> bool`).
348 ///
349 /// # Default Implementation
350 ///
351 /// The default implementation returns a closure that calls the
352 /// `test` method, providing automatic conversion for custom
353 /// types.
354 ///
355 /// # Examples
356 ///
357 /// ## Using with Iterator Methods
358 ///
359 /// ```rust
360 /// use prism3_function::bi_predicate::{BiPredicate,
361 /// BoxBiPredicate};
362 ///
363 /// let pred = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
364 ///
365 /// let pairs = vec![(1, 2), (-1, 3), (5, -6)];
366 /// let mut closure = pred.into_fn();
367 /// let positives: Vec<_> = pairs.iter()
368 /// .filter(|(x, y)| closure(x, y))
369 /// .collect();
370 /// assert_eq!(positives, vec![&(1, 2), &(-1, 3)]);
371 /// ```
372 fn into_fn(self) -> impl Fn(&T, &U) -> bool
373 where
374 Self: Sized + 'static,
375 T: 'static,
376 U: 'static,
377 {
378 move |first, second| self.test(first, second)
379 }
380
381 fn to_box(&self) -> BoxBiPredicate<T, U>
382 where
383 Self: Sized + Clone + 'static,
384 T: 'static,
385 U: 'static,
386 {
387 self.clone().into_box()
388 }
389
390 fn to_rc(&self) -> RcBiPredicate<T, U>
391 where
392 Self: Sized + Clone + 'static,
393 T: 'static,
394 U: 'static,
395 {
396 self.clone().into_rc()
397 }
398
399 fn to_arc(&self) -> ArcBiPredicate<T, U>
400 where
401 Self: Sized + Clone + Send + Sync + 'static,
402 T: Send + Sync + 'static,
403 U: Send + Sync + 'static,
404 {
405 self.clone().into_arc()
406 }
407
408 fn to_fn(&self) -> impl Fn(&T, &U) -> bool
409 where
410 Self: Sized + Clone + 'static,
411 T: 'static,
412 U: 'static,
413 {
414 self.clone().into_fn()
415 }
416}
417
418/// A Box-based bi-predicate with single ownership.
419///
420/// This type is suitable for one-time use scenarios where the
421/// bi-predicate does not need to be cloned or shared. Composition
422/// methods consume `self`, reflecting the single-ownership model.
423///
424/// # Examples
425///
426/// ```rust
427/// use prism3_function::bi_predicate::{BiPredicate, BoxBiPredicate};
428///
429/// let pred = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
430/// assert!(pred.test(&5, &3));
431///
432/// // Chaining consumes the bi-predicate
433/// let combined = pred.and(BoxBiPredicate::new(|x, y| x > y));
434/// assert!(combined.test(&10, &5));
435/// ```
436///
437/// # Author
438///
439/// Haixing Hu
440pub struct BoxBiPredicate<T, U> {
441 function: Box<BiPredicateFn<T, U>>,
442 name: Option<String>,
443}
444
445impl<T, U> BoxBiPredicate<T, U> {
446 /// Creates a new `BoxBiPredicate` from a closure.
447 ///
448 /// # Parameters
449 ///
450 /// * `f` - The closure to wrap.
451 ///
452 /// # Returns
453 ///
454 /// A new `BoxBiPredicate` instance.
455 pub fn new<F>(f: F) -> Self
456 where
457 F: Fn(&T, &U) -> bool + 'static,
458 {
459 Self {
460 function: Box::new(f),
461 name: None,
462 }
463 }
464
465 /// Creates a named `BoxBiPredicate` from a closure.
466 ///
467 /// # Parameters
468 ///
469 /// * `name` - The name for this bi-predicate.
470 /// * `f` - The closure to wrap.
471 ///
472 /// # Returns
473 ///
474 /// A new named `BoxBiPredicate` instance.
475 pub fn new_with_name<F>(name: &str, f: F) -> Self
476 where
477 F: Fn(&T, &U) -> bool + 'static,
478 {
479 Self {
480 function: Box::new(f),
481 name: Some(name.to_string()),
482 }
483 }
484
485 /// Creates a bi-predicate that always returns `true`.
486 ///
487 /// # Returns
488 ///
489 /// A new `BoxBiPredicate` that always returns `true`.
490 ///
491 /// # Examples
492 ///
493 /// ```rust
494 /// use prism3_function::bi_predicate::{BiPredicate, BoxBiPredicate};
495 ///
496 /// let pred: BoxBiPredicate<i32, i32> = BoxBiPredicate::always_true();
497 /// assert!(pred.test(&42, &10));
498 /// assert!(pred.test(&-1, &5));
499 /// assert!(pred.test(&0, &0));
500 /// ```
501 pub fn always_true() -> Self {
502 Self {
503 function: Box::new(|_, _| true),
504 name: Some(ALWAYS_TRUE_NAME.to_string()),
505 }
506 }
507
508 /// Creates a bi-predicate that always returns `false`.
509 ///
510 /// # Returns
511 ///
512 /// A new `BoxBiPredicate` that always returns `false`.
513 ///
514 /// # Examples
515 ///
516 /// ```rust
517 /// use prism3_function::bi_predicate::{BiPredicate, BoxBiPredicate};
518 ///
519 /// let pred: BoxBiPredicate<i32, i32> = BoxBiPredicate::always_false();
520 /// assert!(!pred.test(&42, &10));
521 /// assert!(!pred.test(&-1, &5));
522 /// assert!(!pred.test(&0, &0));
523 /// ```
524 pub fn always_false() -> Self {
525 Self {
526 function: Box::new(|_, _| false),
527 name: Some(ALWAYS_FALSE_NAME.to_string()),
528 }
529 }
530
531 /// Returns the name of this bi-predicate, if set.
532 ///
533 /// # Returns
534 ///
535 /// An `Option` containing the bi-predicate's name.
536 pub fn name(&self) -> Option<&str> {
537 self.name.as_deref()
538 }
539
540 /// Sets the name of this bi-predicate.
541 ///
542 /// # Parameters
543 ///
544 /// * `name` - The new name for this bi-predicate.
545 pub fn set_name(&mut self, name: &str) {
546 self.name = Some(name.to_string());
547 }
548
549 /// Returns a bi-predicate that represents the logical AND of this
550 /// bi-predicate and another.
551 ///
552 /// This method consumes `self` due to single-ownership semantics.
553 ///
554 /// # Parameters
555 ///
556 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
557 /// is passed by value and will transfer ownership.** If you need to
558 /// preserve the original bi-predicate, clone it first (if it implements
559 /// `Clone`). Can be:
560 /// - A closure: `|x: &T, y: &U| -> bool`
561 /// - A function pointer: `fn(&T, &U) -> bool`
562 /// - Another `BoxBiPredicate<T, U>`
563 /// - An `RcBiPredicate<T, U>`
564 /// - An `ArcBiPredicate<T, U>`
565 /// - Any type implementing `BiPredicate<T, U>`
566 ///
567 /// # Returns
568 ///
569 /// A new `BoxBiPredicate` representing the logical AND.
570 pub fn and<P>(self, other: P) -> BoxBiPredicate<T, U>
571 where
572 P: BiPredicate<T, U> + 'static,
573 T: 'static,
574 U: 'static,
575 {
576 BoxBiPredicate::new(move |first, second| {
577 (self.function)(first, second) && other.test(first, second)
578 })
579 }
580
581 /// Returns a bi-predicate that represents the logical OR of this
582 /// bi-predicate and another.
583 ///
584 /// This method consumes `self` due to single-ownership semantics.
585 ///
586 /// # Parameters
587 ///
588 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
589 /// is passed by value and will transfer ownership.** If you need to
590 /// preserve the original bi-predicate, clone it first (if it implements
591 /// `Clone`). Can be:
592 /// - A closure: `|x: &T, y: &U| -> bool`
593 /// - A function pointer: `fn(&T, &U) -> bool`
594 /// - Another `BoxBiPredicate<T, U>`
595 /// - An `RcBiPredicate<T, U>`
596 /// - An `ArcBiPredicate<T, U>`
597 /// - Any type implementing `BiPredicate<T, U>`
598 ///
599 /// # Returns
600 ///
601 /// A new `BoxBiPredicate` representing the logical OR.
602 pub fn or<P>(self, other: P) -> BoxBiPredicate<T, U>
603 where
604 P: BiPredicate<T, U> + 'static,
605 T: 'static,
606 U: 'static,
607 {
608 BoxBiPredicate::new(move |first, second| {
609 (self.function)(first, second) || other.test(first, second)
610 })
611 }
612
613 /// Returns a bi-predicate that represents the logical negation of
614 /// this bi-predicate.
615 ///
616 /// This method consumes `self` due to single-ownership semantics.
617 ///
618 /// # Returns
619 ///
620 /// A new `BoxBiPredicate` representing the logical negation.
621 #[allow(clippy::should_implement_trait)]
622 pub fn not(self) -> BoxBiPredicate<T, U>
623 where
624 T: 'static,
625 U: 'static,
626 {
627 BoxBiPredicate::new(move |first, second| !(self.function)(first, second))
628 }
629
630 /// Returns a bi-predicate that represents the logical NAND (NOT
631 /// AND) of this bi-predicate and another.
632 ///
633 /// NAND returns `true` unless both bi-predicates are `true`.
634 /// Equivalent to `!(self AND other)`.
635 ///
636 /// This method consumes `self` due to single-ownership semantics.
637 ///
638 /// # Parameters
639 ///
640 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
641 /// is passed by value and will transfer ownership.** If you need to
642 /// preserve the original bi-predicate, clone it first (if it implements
643 /// `Clone`). Can be:
644 /// - A closure: `|x: &T, y: &U| -> bool`
645 /// - A function pointer: `fn(&T, &U) -> bool`
646 /// - Another `BoxBiPredicate<T, U>`
647 /// - An `RcBiPredicate<T, U>`
648 /// - An `ArcBiPredicate<T, U>`
649 /// - Any type implementing `BiPredicate<T, U>`
650 ///
651 /// # Returns
652 ///
653 /// A new `BoxBiPredicate` representing the logical NAND.
654 pub fn nand<P>(self, other: P) -> BoxBiPredicate<T, U>
655 where
656 P: BiPredicate<T, U> + 'static,
657 T: 'static,
658 U: 'static,
659 {
660 BoxBiPredicate::new(move |first, second| {
661 !((self.function)(first, second) && other.test(first, second))
662 })
663 }
664
665 /// Returns a bi-predicate that represents the logical XOR
666 /// (exclusive OR) of this bi-predicate and another.
667 ///
668 /// XOR returns `true` if exactly one of the bi-predicates is
669 /// `true`.
670 ///
671 /// This method consumes `self` due to single-ownership semantics.
672 ///
673 /// # Parameters
674 ///
675 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
676 /// is passed by value and will transfer ownership.** If you need to
677 /// preserve the original bi-predicate, clone it first (if it implements
678 /// `Clone`). Can be:
679 /// - A closure: `|x: &T, y: &U| -> bool`
680 /// - A function pointer: `fn(&T, &U) -> bool`
681 /// - Another `BoxBiPredicate<T, U>`
682 /// - An `RcBiPredicate<T, U>`
683 /// - An `ArcBiPredicate<T, U>`
684 /// - Any type implementing `BiPredicate<T, U>`
685 ///
686 /// # Returns
687 ///
688 /// A new `BoxBiPredicate` representing the logical XOR.
689 pub fn xor<P>(self, other: P) -> BoxBiPredicate<T, U>
690 where
691 P: BiPredicate<T, U> + 'static,
692 T: 'static,
693 U: 'static,
694 {
695 BoxBiPredicate::new(move |first, second| {
696 (self.function)(first, second) ^ other.test(first, second)
697 })
698 }
699
700 /// Returns a bi-predicate that represents the logical NOR (NOT
701 /// OR) of this bi-predicate and another.
702 ///
703 /// NOR returns `true` only if both bi-predicates are `false`.
704 /// Equivalent to `!(self OR other)`.
705 ///
706 /// This method consumes `self` due to single-ownership semantics.
707 ///
708 /// # Parameters
709 ///
710 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
711 /// is passed by value and will transfer ownership.** If you need to
712 /// preserve the original bi-predicate, clone it first (if it implements
713 /// `Clone`). Can be:
714 /// - A closure: `|x: &T, y: &U| -> bool`
715 /// - A function pointer: `fn(&T, &U) -> bool`
716 /// - Another `BoxBiPredicate<T, U>`
717 /// - An `RcBiPredicate<T, U>`
718 /// - An `ArcBiPredicate<T, U>`
719 /// - Any type implementing `BiPredicate<T, U>`
720 ///
721 /// # Returns
722 ///
723 /// A new `BoxBiPredicate` representing the logical NOR.
724 pub fn nor<P>(self, other: P) -> BoxBiPredicate<T, U>
725 where
726 P: BiPredicate<T, U> + 'static,
727 T: 'static,
728 U: 'static,
729 {
730 BoxBiPredicate::new(move |first, second| {
731 !((self.function)(first, second) || other.test(first, second))
732 })
733 }
734}
735
736impl<T, U> BiPredicate<T, U> for BoxBiPredicate<T, U> {
737 fn test(&self, first: &T, second: &U) -> bool {
738 (self.function)(first, second)
739 }
740
741 // Use optimized zero-cost conversion for into_box
742 fn into_box(self) -> BoxBiPredicate<T, U>
743 where
744 T: 'static,
745 U: 'static,
746 {
747 self
748 }
749
750 fn into_rc(self) -> RcBiPredicate<T, U>
751 where
752 T: 'static,
753 U: 'static,
754 {
755 RcBiPredicate {
756 function: Rc::new(move |first, second| (self.function)(first, second)),
757 name: self.name.clone(),
758 }
759 }
760
761 // do NOT override BoxBiPredicate::into_arc() because BoxBiPredicate is not Send + Sync
762 // and calling BoxBiPredicate::into_arc() will cause a compile error
763
764 fn into_fn(self) -> impl Fn(&T, &U) -> bool
765 where
766 Self: Sized + 'static,
767 T: 'static,
768 U: 'static,
769 {
770 move |first, second| (self.function)(first, second)
771 }
772
773 // do NOT override BoxBiPredicate::to_xxx() because BoxBiPredicate is not Clone
774 // and calling BoxBiPredicate::to_xxx() will cause a compile error
775}
776
777impl<T, U> Display for BoxBiPredicate<T, U> {
778 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
779 write!(
780 f,
781 "BoxBiPredicate({})",
782 self.name.as_deref().unwrap_or("unnamed")
783 )
784 }
785}
786
787impl<T, U> Debug for BoxBiPredicate<T, U> {
788 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
789 f.debug_struct("BoxBiPredicate")
790 .field("name", &self.name)
791 .finish()
792 }
793}
794
795/// An Rc-based bi-predicate with single-threaded shared ownership.
796///
797/// This type is suitable for scenarios where the bi-predicate needs
798/// to be reused in a single-threaded context. Composition methods
799/// borrow `&self`, allowing the original bi-predicate to remain
800/// usable after composition.
801///
802/// # Examples
803///
804/// ```rust
805/// use prism3_function::bi_predicate::{BiPredicate, RcBiPredicate};
806///
807/// let pred = RcBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
808/// assert!(pred.test(&5, &3));
809///
810/// // Original bi-predicate remains usable after composition
811/// let combined = pred.and(RcBiPredicate::new(|x, y| x > y));
812/// assert!(pred.test(&5, &3)); // Still works
813/// ```
814///
815/// # Author
816///
817/// Haixing Hu
818pub struct RcBiPredicate<T, U> {
819 function: Rc<BiPredicateFn<T, U>>,
820 name: Option<String>,
821}
822
823impl<T, U> RcBiPredicate<T, U> {
824 /// Creates a new `RcBiPredicate` from a closure.
825 ///
826 /// # Parameters
827 ///
828 /// * `f` - The closure to wrap.
829 ///
830 /// # Returns
831 ///
832 /// A new `RcBiPredicate` instance.
833 pub fn new<F>(f: F) -> Self
834 where
835 F: Fn(&T, &U) -> bool + 'static,
836 {
837 Self {
838 function: Rc::new(f),
839 name: None,
840 }
841 }
842
843 /// Creates a named `RcBiPredicate` from a closure.
844 ///
845 /// # Parameters
846 ///
847 /// * `name` - The name for this bi-predicate.
848 /// * `f` - The closure to wrap.
849 ///
850 /// # Returns
851 ///
852 /// A new named `RcBiPredicate` instance.
853 pub fn new_with_name<F>(name: &str, f: F) -> Self
854 where
855 F: Fn(&T, &U) -> bool + 'static,
856 {
857 Self {
858 function: Rc::new(f),
859 name: Some(name.to_string()),
860 }
861 }
862
863 /// Creates a bi-predicate that always returns `true`.
864 ///
865 /// # Returns
866 ///
867 /// A new `RcBiPredicate` that always returns `true`.
868 ///
869 /// # Examples
870 ///
871 /// ```rust
872 /// use prism3_function::bi_predicate::{BiPredicate, RcBiPredicate};
873 ///
874 /// let pred: RcBiPredicate<i32, i32> = RcBiPredicate::always_true();
875 /// assert!(pred.test(&42, &10));
876 /// assert!(pred.test(&-1, &5));
877 /// assert!(pred.test(&0, &0));
878 /// ```
879 pub fn always_true() -> Self {
880 Self {
881 function: Rc::new(|_, _| true),
882 name: Some(ALWAYS_TRUE_NAME.to_string()),
883 }
884 }
885
886 /// Creates a bi-predicate that always returns `false`.
887 ///
888 /// # Returns
889 ///
890 /// A new `RcBiPredicate` that always returns `false`.
891 ///
892 /// # Examples
893 ///
894 /// ```rust
895 /// use prism3_function::bi_predicate::{BiPredicate, RcBiPredicate};
896 ///
897 /// let pred: RcBiPredicate<i32, i32> = RcBiPredicate::always_false();
898 /// assert!(!pred.test(&42, &10));
899 /// assert!(!pred.test(&-1, &5));
900 /// assert!(!pred.test(&0, &0));
901 /// ```
902 pub fn always_false() -> Self {
903 Self {
904 function: Rc::new(|_, _| false),
905 name: Some(ALWAYS_FALSE_NAME.to_string()),
906 }
907 }
908
909 /// Returns the name of this bi-predicate, if set.
910 ///
911 /// # Returns
912 ///
913 /// An `Option` containing the bi-predicate's name.
914 pub fn name(&self) -> Option<&str> {
915 self.name.as_deref()
916 }
917
918 /// Sets the name of this bi-predicate.
919 ///
920 /// # Parameters
921 ///
922 /// * `name` - The new name for this bi-predicate.
923 pub fn set_name(&mut self, name: &str) {
924 self.name = Some(name.to_string());
925 }
926
927 /// Returns a bi-predicate that represents the logical AND of this
928 /// bi-predicate and another.
929 ///
930 /// # Parameters
931 ///
932 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
933 /// is passed by value and will transfer ownership.** If you need to
934 /// preserve the original bi-predicate, clone it first (if it implements
935 /// `Clone`). Can be:
936 /// - A closure: `|x: &T, y: &U| -> bool`
937 /// - A function pointer: `fn(&T, &U) -> bool`
938 /// - A `BoxBiPredicate<T, U>`
939 /// - Another `RcBiPredicate<T, U>` (will be moved)
940 /// - An `ArcBiPredicate<T, U>`
941 /// - Any type implementing `BiPredicate<T, U>`
942 ///
943 /// # Returns
944 ///
945 /// A new `RcBiPredicate` representing the logical AND.
946 pub fn and<P>(&self, other: P) -> RcBiPredicate<T, U>
947 where
948 P: BiPredicate<T, U> + 'static,
949 T: 'static,
950 U: 'static,
951 {
952 let self_fn = Rc::clone(&self.function);
953 RcBiPredicate {
954 function: Rc::new(move |first, second| {
955 self_fn(first, second) && other.test(first, second)
956 }),
957 name: None,
958 }
959 }
960
961 /// Returns a bi-predicate that represents the logical OR of this
962 /// bi-predicate and another.
963 ///
964 /// # Parameters
965 ///
966 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
967 /// is passed by value and will transfer ownership.** If you need to
968 /// preserve the original bi-predicate, clone it first (if it implements
969 /// `Clone`). Can be:
970 /// - A closure: `|x: &T, y: &U| -> bool`
971 /// - A function pointer: `fn(&T, &U) -> bool`
972 /// - A `BoxBiPredicate<T, U>`
973 /// - Another `RcBiPredicate<T, U>` (will be moved)
974 /// - An `ArcBiPredicate<T, U>`
975 /// - Any type implementing `BiPredicate<T, U>`
976 ///
977 /// # Returns
978 ///
979 /// A new `RcBiPredicate` representing the logical OR.
980 pub fn or<P>(&self, other: P) -> RcBiPredicate<T, U>
981 where
982 P: BiPredicate<T, U> + 'static,
983 T: 'static,
984 U: 'static,
985 {
986 let self_fn = Rc::clone(&self.function);
987 RcBiPredicate {
988 function: Rc::new(move |first, second| {
989 self_fn(first, second) || other.test(first, second)
990 }),
991 name: None,
992 }
993 }
994
995 /// Returns a bi-predicate that represents the logical negation of
996 /// this bi-predicate.
997 ///
998 /// # Returns
999 ///
1000 /// A new `RcBiPredicate` representing the logical negation.
1001 #[allow(clippy::should_implement_trait)]
1002 pub fn not(&self) -> RcBiPredicate<T, U>
1003 where
1004 T: 'static,
1005 U: 'static,
1006 {
1007 let self_fn = Rc::clone(&self.function);
1008 RcBiPredicate {
1009 function: Rc::new(move |first, second| !self_fn(first, second)),
1010 name: None,
1011 }
1012 }
1013
1014 /// Returns a bi-predicate that represents the logical NAND (NOT
1015 /// AND) of this bi-predicate and another.
1016 ///
1017 /// NAND returns `true` unless both bi-predicates are `true`.
1018 /// Equivalent to `!(self AND other)`.
1019 ///
1020 /// # Parameters
1021 ///
1022 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1023 /// is passed by value and will transfer ownership.** If you need to
1024 /// preserve the original bi-predicate, clone it first (if it implements
1025 /// `Clone`). Can be:
1026 /// - A closure: `|x: &T, y: &U| -> bool`
1027 /// - A function pointer: `fn(&T, &U) -> bool`
1028 /// - A `BoxBiPredicate<T, U>`
1029 /// - Another `RcBiPredicate<T, U>` (will be moved)
1030 /// - An `ArcBiPredicate<T, U>`
1031 /// - Any type implementing `BiPredicate<T, U>`
1032 ///
1033 /// # Returns
1034 ///
1035 /// A new `RcBiPredicate` representing the logical NAND.
1036 pub fn nand<P>(&self, other: P) -> RcBiPredicate<T, U>
1037 where
1038 P: BiPredicate<T, U> + 'static,
1039 T: 'static,
1040 U: 'static,
1041 {
1042 let self_fn = Rc::clone(&self.function);
1043 RcBiPredicate {
1044 function: Rc::new(move |first, second| {
1045 !(self_fn(first, second) && other.test(first, second))
1046 }),
1047 name: None,
1048 }
1049 }
1050
1051 /// Returns a bi-predicate that represents the logical XOR
1052 /// (exclusive OR) of this bi-predicate and another.
1053 ///
1054 /// XOR returns `true` if exactly one of the bi-predicates is
1055 /// `true`.
1056 ///
1057 /// # Parameters
1058 ///
1059 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1060 /// is passed by value and will transfer ownership.** If you need to
1061 /// preserve the original bi-predicate, clone it first (if it implements
1062 /// `Clone`). Can be:
1063 /// - A closure: `|x: &T, y: &U| -> bool`
1064 /// - A function pointer: `fn(&T, &U) -> bool`
1065 /// - A `BoxBiPredicate<T, U>`
1066 /// - Another `RcBiPredicate<T, U>` (will be moved)
1067 /// - An `ArcBiPredicate<T, U>`
1068 /// - Any type implementing `BiPredicate<T, U>`
1069 ///
1070 /// # Returns
1071 ///
1072 /// A new `RcBiPredicate` representing the logical XOR.
1073 pub fn xor<P>(&self, other: P) -> RcBiPredicate<T, U>
1074 where
1075 P: BiPredicate<T, U> + 'static,
1076 T: 'static,
1077 U: 'static,
1078 {
1079 let self_fn = Rc::clone(&self.function);
1080 RcBiPredicate {
1081 function: Rc::new(move |first, second| {
1082 self_fn(first, second) ^ other.test(first, second)
1083 }),
1084 name: None,
1085 }
1086 }
1087
1088 /// Returns a bi-predicate that represents the logical NOR (NOT
1089 /// OR) of this bi-predicate and another.
1090 ///
1091 /// NOR returns `true` only if both bi-predicates are `false`.
1092 /// Equivalent to `!(self OR other)`.
1093 ///
1094 /// # Parameters
1095 ///
1096 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1097 /// is passed by value and will transfer ownership.** If you need to
1098 /// preserve the original bi-predicate, clone it first (if it implements
1099 /// `Clone`). Can be:
1100 /// - A closure: `|x: &T, y: &U| -> bool`
1101 /// - A function pointer: `fn(&T, &U) -> bool`
1102 /// - A `BoxBiPredicate<T, U>`
1103 /// - Another `RcBiPredicate<T, U>` (will be moved)
1104 /// - An `ArcBiPredicate<T, U>`
1105 /// - Any type implementing `BiPredicate<T, U>`
1106 ///
1107 /// # Returns
1108 ///
1109 /// A new `RcBiPredicate` representing the logical NOR.
1110 pub fn nor<P>(&self, other: P) -> RcBiPredicate<T, U>
1111 where
1112 P: BiPredicate<T, U> + 'static,
1113 T: 'static,
1114 U: 'static,
1115 {
1116 let self_fn = Rc::clone(&self.function);
1117 RcBiPredicate {
1118 function: Rc::new(move |first, second| {
1119 !(self_fn(first, second) || other.test(first, second))
1120 }),
1121 name: None,
1122 }
1123 }
1124}
1125
1126impl<T, U> BiPredicate<T, U> for RcBiPredicate<T, U> {
1127 fn test(&self, first: &T, second: &U) -> bool {
1128 (self.function)(first, second)
1129 }
1130
1131 // Use optimized conversion for into_box that preserves the
1132 // existing Rc
1133 fn into_box(self) -> BoxBiPredicate<T, U>
1134 where
1135 T: 'static,
1136 U: 'static,
1137 {
1138 BoxBiPredicate {
1139 function: Box::new(move |first, second| (self.function)(first, second)),
1140 name: self.name,
1141 }
1142 }
1143
1144 // Use optimized zero-cost conversion for into_rc
1145 fn into_rc(self) -> RcBiPredicate<T, U>
1146 where
1147 T: 'static,
1148 U: 'static,
1149 {
1150 self
1151 }
1152
1153 // do NOT override RcBiPredicate::into_arc() because RcBiPredicate is not Send + Sync
1154 // and calling RcBiPredicate::into_arc() will cause a compile error
1155
1156 fn into_fn(self) -> impl Fn(&T, &U) -> bool
1157 where
1158 Self: Sized + 'static,
1159 T: 'static,
1160 U: 'static,
1161 {
1162 move |first, second| (self.function)(first, second)
1163 }
1164
1165 fn to_box(&self) -> BoxBiPredicate<T, U>
1166 where
1167 T: 'static,
1168 U: 'static,
1169 {
1170 let self_fn = self.function.clone();
1171 BoxBiPredicate {
1172 function: Box::new(move |first, second| self_fn(first, second)),
1173 name: self.name.clone(),
1174 }
1175 }
1176
1177 // do NOT override RcBiPredicate::to_rc() because RcBiPredicate is not Clone
1178 // and calling RcBiPredicate::to_rc() will cause a compile error
1179
1180 fn to_rc(&self) -> RcBiPredicate<T, U>
1181 where
1182 T: 'static,
1183 U: 'static,
1184 {
1185 self.clone()
1186 }
1187
1188 fn to_fn(&self) -> impl Fn(&T, &U) -> bool
1189 where
1190 T: 'static,
1191 U: 'static,
1192 {
1193 let self_fn = self.function.clone();
1194 move |first, second| self_fn(first, second)
1195 }
1196}
1197
1198impl<T, U> Clone for RcBiPredicate<T, U> {
1199 /// Clones this bi-predicate.
1200 ///
1201 /// Creates a new instance that shares the underlying function with
1202 /// the original, allowing multiple references to the same
1203 /// bi-predicate logic.
1204 fn clone(&self) -> Self {
1205 RcBiPredicate {
1206 function: Rc::clone(&self.function),
1207 name: self.name.clone(),
1208 }
1209 }
1210}
1211
1212impl<T, U> Display for RcBiPredicate<T, U> {
1213 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1214 write!(
1215 f,
1216 "RcBiPredicate({})",
1217 self.name.as_deref().unwrap_or("unnamed")
1218 )
1219 }
1220}
1221
1222impl<T, U> Debug for RcBiPredicate<T, U> {
1223 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1224 f.debug_struct("RcBiPredicate")
1225 .field("name", &self.name)
1226 .finish()
1227 }
1228}
1229
1230/// An Arc-based bi-predicate with thread-safe shared ownership.
1231///
1232/// This type is suitable for scenarios where the bi-predicate needs
1233/// to be shared across threads. Composition methods borrow `&self`,
1234/// allowing the original bi-predicate to remain usable after
1235/// composition.
1236///
1237/// # Examples
1238///
1239/// ```rust
1240/// use prism3_function::bi_predicate::{BiPredicate, ArcBiPredicate};
1241///
1242/// let pred = ArcBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
1243/// assert!(pred.test(&5, &3));
1244///
1245/// // Original bi-predicate remains usable after composition
1246/// let combined = pred.and(ArcBiPredicate::new(|x, y| x > y));
1247/// assert!(pred.test(&5, &3)); // Still works
1248///
1249/// // Can be cloned and sent across threads
1250/// let pred_clone = pred.clone();
1251/// std::thread::spawn(move || {
1252/// assert!(pred_clone.test(&10, &5));
1253/// }).join().unwrap();
1254/// ```
1255///
1256/// # Author
1257///
1258/// Haixing Hu
1259pub struct ArcBiPredicate<T, U> {
1260 function: Arc<SendSyncBiPredicateFn<T, U>>,
1261 name: Option<String>,
1262}
1263
1264impl<T, U> ArcBiPredicate<T, U> {
1265 /// Creates a new `ArcBiPredicate` from a closure.
1266 ///
1267 /// # Parameters
1268 ///
1269 /// * `f` - The closure to wrap.
1270 ///
1271 /// # Returns
1272 ///
1273 /// A new `ArcBiPredicate` instance.
1274 pub fn new<F>(f: F) -> Self
1275 where
1276 F: Fn(&T, &U) -> bool + Send + Sync + 'static,
1277 {
1278 Self {
1279 function: Arc::new(f),
1280 name: None,
1281 }
1282 }
1283
1284 /// Creates a named `ArcBiPredicate` from a closure.
1285 ///
1286 /// # Parameters
1287 ///
1288 /// * `name` - The name for this bi-predicate.
1289 /// * `f` - The closure to wrap.
1290 ///
1291 /// # Returns
1292 ///
1293 /// A new named `ArcBiPredicate` instance.
1294 pub fn new_with_name<F>(name: &str, f: F) -> Self
1295 where
1296 F: Fn(&T, &U) -> bool + Send + Sync + 'static,
1297 {
1298 Self {
1299 function: Arc::new(f),
1300 name: Some(name.to_string()),
1301 }
1302 }
1303
1304 /// Creates a bi-predicate that always returns `true`.
1305 ///
1306 /// # Returns
1307 ///
1308 /// A new `ArcBiPredicate` that always returns `true`.
1309 ///
1310 /// # Examples
1311 ///
1312 /// ```rust
1313 /// use prism3_function::bi_predicate::{BiPredicate, ArcBiPredicate};
1314 ///
1315 /// let pred: ArcBiPredicate<i32, i32> = ArcBiPredicate::always_true();
1316 /// assert!(pred.test(&42, &10));
1317 /// assert!(pred.test(&-1, &5));
1318 /// assert!(pred.test(&0, &0));
1319 /// ```
1320 pub fn always_true() -> Self {
1321 Self {
1322 function: Arc::new(|_, _| true),
1323 name: Some(ALWAYS_TRUE_NAME.to_string()),
1324 }
1325 }
1326
1327 /// Creates a bi-predicate that always returns `false`.
1328 ///
1329 /// # Returns
1330 ///
1331 /// A new `ArcBiPredicate` that always returns `false`.
1332 ///
1333 /// # Examples
1334 ///
1335 /// ```rust
1336 /// use prism3_function::bi_predicate::{BiPredicate, ArcBiPredicate};
1337 ///
1338 /// let pred: ArcBiPredicate<i32, i32> = ArcBiPredicate::always_false();
1339 /// assert!(!pred.test(&42, &10));
1340 /// assert!(!pred.test(&-1, &5));
1341 /// assert!(!pred.test(&0, &0));
1342 /// ```
1343 pub fn always_false() -> Self {
1344 Self {
1345 function: Arc::new(|_, _| false),
1346 name: Some(ALWAYS_FALSE_NAME.to_string()),
1347 }
1348 }
1349
1350 /// Returns the name of this bi-predicate, if set.
1351 ///
1352 /// # Returns
1353 ///
1354 /// An `Option` containing the bi-predicate's name.
1355 pub fn name(&self) -> Option<&str> {
1356 self.name.as_deref()
1357 }
1358
1359 /// Sets the name of this bi-predicate.
1360 ///
1361 /// # Parameters
1362 ///
1363 /// * `name` - The new name for this bi-predicate.
1364 pub fn set_name(&mut self, name: &str) {
1365 self.name = Some(name.to_string());
1366 }
1367
1368 /// Returns a bi-predicate that represents the logical AND of this
1369 /// bi-predicate and another.
1370 ///
1371 /// # Parameters
1372 ///
1373 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1374 /// is passed by value and will transfer ownership.** If you need to
1375 /// preserve the original bi-predicate, clone it first (if it implements
1376 /// `Clone`). Can be:
1377 /// - A closure: `|x: &T, y: &U| -> bool`
1378 /// - A function pointer: `fn(&T, &U) -> bool`
1379 /// - A `BoxBiPredicate<T, U>`
1380 /// - An `RcBiPredicate<T, U>`
1381 /// - Another `ArcBiPredicate<T, U>` (will be moved)
1382 /// - Any type implementing `BiPredicate<T, U> + Send + Sync`
1383 ///
1384 /// # Returns
1385 ///
1386 /// A new `ArcBiPredicate` representing the logical AND.
1387 pub fn and<P>(&self, other: P) -> ArcBiPredicate<T, U>
1388 where
1389 T: Send + Sync + 'static,
1390 U: Send + Sync + 'static,
1391 P: BiPredicate<T, U> + Send + Sync + 'static,
1392 {
1393 let self_fn = Arc::clone(&self.function);
1394 ArcBiPredicate {
1395 function: Arc::new(move |first, second| {
1396 self_fn(first, second) && other.test(first, second)
1397 }),
1398 name: None,
1399 }
1400 }
1401
1402 /// Returns a bi-predicate that represents the logical OR of this
1403 /// bi-predicate and another.
1404 ///
1405 /// # Parameters
1406 ///
1407 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1408 /// is passed by value and will transfer ownership.** If you need to
1409 /// preserve the original bi-predicate, clone it first (if it implements
1410 /// `Clone`). Can be:
1411 /// - A closure: `|x: &T, y: &U| -> bool`
1412 /// - A function pointer: `fn(&T, &U) -> bool`
1413 /// - A `BoxBiPredicate<T, U>`
1414 /// - An `RcBiPredicate<T, U>`
1415 /// - Another `ArcBiPredicate<T, U>` (will be moved)
1416 /// - Any type implementing `BiPredicate<T, U> + Send + Sync`
1417 ///
1418 /// # Returns
1419 ///
1420 /// A new `ArcBiPredicate` representing the logical OR.
1421 /// Thread-safe.
1422 pub fn or<P>(&self, other: P) -> ArcBiPredicate<T, U>
1423 where
1424 T: Send + Sync + 'static,
1425 U: Send + Sync + 'static,
1426 P: BiPredicate<T, U> + Send + Sync + 'static,
1427 {
1428 let self_fn = Arc::clone(&self.function);
1429 ArcBiPredicate {
1430 function: Arc::new(move |first, second| {
1431 self_fn(first, second) || other.test(first, second)
1432 }),
1433 name: None,
1434 }
1435 }
1436
1437 /// Returns a bi-predicate that represents the logical negation of
1438 /// this bi-predicate.
1439 ///
1440 /// # Returns
1441 ///
1442 /// A new `ArcBiPredicate` representing the logical negation.
1443 #[allow(clippy::should_implement_trait)]
1444 pub fn not(&self) -> ArcBiPredicate<T, U>
1445 where
1446 T: Send + Sync + 'static,
1447 U: Send + Sync + 'static,
1448 {
1449 let self_fn = Arc::clone(&self.function);
1450 ArcBiPredicate {
1451 function: Arc::new(move |first, second| !self_fn(first, second)),
1452 name: None,
1453 }
1454 }
1455
1456 /// Returns a bi-predicate that represents the logical NAND (NOT
1457 /// AND) of this bi-predicate and another.
1458 ///
1459 /// NAND returns `true` unless both bi-predicates are `true`.
1460 /// Equivalent to `!(self AND other)`.
1461 ///
1462 /// # Parameters
1463 ///
1464 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1465 /// is passed by value and will transfer ownership.** If you need to
1466 /// preserve the original bi-predicate, clone it first (if it implements
1467 /// `Clone`). Can be:
1468 /// - A closure: `|x: &T, y: &U| -> bool`
1469 /// - A function pointer: `fn(&T, &U) -> bool`
1470 /// - A `BoxBiPredicate<T, U>`
1471 /// - An `RcBiPredicate<T, U>`
1472 /// - Another `ArcBiPredicate<T, U>` (will be moved)
1473 /// - Any type implementing `BiPredicate<T, U> + Send + Sync`
1474 ///
1475 /// # Returns
1476 ///
1477 /// A new `ArcBiPredicate` representing the logical NAND.
1478 /// Thread-safe.
1479 pub fn nand<P>(&self, other: P) -> ArcBiPredicate<T, U>
1480 where
1481 T: Send + Sync + 'static,
1482 U: Send + Sync + 'static,
1483 P: BiPredicate<T, U> + Send + Sync + 'static,
1484 {
1485 let self_fn = Arc::clone(&self.function);
1486 ArcBiPredicate {
1487 function: Arc::new(move |first, second| {
1488 !(self_fn(first, second) && other.test(first, second))
1489 }),
1490 name: None,
1491 }
1492 }
1493
1494 /// Returns a bi-predicate that represents the logical XOR
1495 /// (exclusive OR) of this bi-predicate and another.
1496 ///
1497 /// XOR returns `true` if exactly one of the bi-predicates is
1498 /// `true`.
1499 ///
1500 /// # Parameters
1501 ///
1502 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1503 /// is passed by value and will transfer ownership.** If you need to
1504 /// preserve the original bi-predicate, clone it first (if it implements
1505 /// `Clone`). Can be:
1506 /// - A closure: `|x: &T, y: &U| -> bool`
1507 /// - A function pointer: `fn(&T, &U) -> bool`
1508 /// - A `BoxBiPredicate<T, U>`
1509 /// - An `RcBiPredicate<T, U>`
1510 /// - Another `ArcBiPredicate<T, U>` (will be moved)
1511 /// - Any type implementing `BiPredicate<T, U> + Send + Sync`
1512 ///
1513 /// # Returns
1514 ///
1515 /// A new `ArcBiPredicate` representing the logical XOR.
1516 pub fn xor<P>(&self, other: P) -> ArcBiPredicate<T, U>
1517 where
1518 T: Send + Sync + 'static,
1519 U: Send + Sync + 'static,
1520 P: BiPredicate<T, U> + Send + Sync + 'static,
1521 {
1522 let self_fn = Arc::clone(&self.function);
1523 ArcBiPredicate {
1524 function: Arc::new(move |first, second| {
1525 self_fn(first, second) ^ other.test(first, second)
1526 }),
1527 name: None,
1528 }
1529 }
1530
1531 /// Returns a bi-predicate that represents the logical NOR (NOT
1532 /// OR) of this bi-predicate and another.
1533 ///
1534 /// NOR returns `true` only if both bi-predicates are `false`.
1535 /// Equivalent to `!(self OR other)`.
1536 ///
1537 /// # Parameters
1538 ///
1539 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1540 /// is passed by value and will transfer ownership.** If you need to
1541 /// preserve the original bi-predicate, clone it first (if it implements
1542 /// `Clone`). Can be:
1543 /// - A closure: `|x: &T, y: &U| -> bool`
1544 /// - A function pointer: `fn(&T, &U) -> bool`
1545 /// - A `BoxBiPredicate<T, U>`
1546 /// - An `RcBiPredicate<T, U>`
1547 /// - Another `ArcBiPredicate<T, U>` (will be moved)
1548 /// - Any type implementing `BiPredicate<T, U> + Send + Sync`
1549 ///
1550 /// # Returns
1551 ///
1552 /// A new `ArcBiPredicate` representing the logical NOR.
1553 /// Thread-safe.
1554 pub fn nor<P>(&self, other: P) -> ArcBiPredicate<T, U>
1555 where
1556 T: Send + Sync + 'static,
1557 U: Send + Sync + 'static,
1558 P: BiPredicate<T, U> + Send + Sync + 'static,
1559 {
1560 let self_fn = Arc::clone(&self.function);
1561 ArcBiPredicate {
1562 function: Arc::new(move |first, second| {
1563 !(self_fn(first, second) || other.test(first, second))
1564 }),
1565 name: None,
1566 }
1567 }
1568}
1569
1570impl<T, U> BiPredicate<T, U> for ArcBiPredicate<T, U> {
1571 fn test(&self, first: &T, second: &U) -> bool {
1572 (self.function)(first, second)
1573 }
1574
1575 // Use optimized conversion for into_box that preserves the
1576 // existing Arc
1577 fn into_box(self) -> BoxBiPredicate<T, U>
1578 where
1579 T: 'static,
1580 U: 'static,
1581 {
1582 BoxBiPredicate {
1583 function: Box::new(move |first, second| (self.function)(first, second)),
1584 name: self.name,
1585 }
1586 }
1587
1588 // Use optimized conversion for into_rc that preserves the
1589 // existing Arc
1590 fn into_rc(self) -> RcBiPredicate<T, U>
1591 where
1592 T: 'static,
1593 U: 'static,
1594 {
1595 RcBiPredicate {
1596 function: Rc::new(move |first, second| (self.function)(first, second)),
1597 name: self.name,
1598 }
1599 }
1600
1601 // Use optimized zero-cost conversion for into_arc
1602 fn into_arc(self) -> ArcBiPredicate<T, U>
1603 where
1604 T: Send + Sync + 'static,
1605 U: Send + Sync + 'static,
1606 {
1607 self
1608 }
1609
1610 // Use optimized conversion for into_fn that preserves the
1611 // existing Arc
1612 fn into_fn(self) -> impl Fn(&T, &U) -> bool
1613 where
1614 Self: Sized + 'static,
1615 T: 'static,
1616 U: 'static,
1617 {
1618 move |first, second| (self.function)(first, second)
1619 }
1620
1621 fn to_box(&self) -> BoxBiPredicate<T, U>
1622 where
1623 T: 'static,
1624 U: 'static,
1625 {
1626 let self_fn = self.function.clone();
1627 BoxBiPredicate {
1628 function: Box::new(move |first, second| self_fn(first, second)),
1629 name: self.name.clone(),
1630 }
1631 }
1632
1633 fn to_rc(&self) -> RcBiPredicate<T, U>
1634 where
1635 T: 'static,
1636 U: 'static,
1637 {
1638 let self_fn = self.function.clone();
1639 RcBiPredicate {
1640 function: Rc::new(move |first, second| self_fn(first, second)),
1641 name: self.name.clone(),
1642 }
1643 }
1644
1645 fn to_arc(&self) -> ArcBiPredicate<T, U>
1646 where
1647 T: Send + Sync + 'static,
1648 U: Send + Sync + 'static,
1649 {
1650 self.clone()
1651 }
1652
1653 fn to_fn(&self) -> impl Fn(&T, &U) -> bool
1654 where
1655 T: 'static,
1656 U: 'static,
1657 {
1658 let self_fn = self.function.clone();
1659 move |first, second| self_fn(first, second)
1660 }
1661}
1662
1663impl<T, U> Clone for ArcBiPredicate<T, U> {
1664 /// Clones this bi-predicate.
1665 ///
1666 /// Creates a new instance that shares the underlying function with
1667 /// the original, allowing multiple references to the same
1668 /// bi-predicate logic.
1669 fn clone(&self) -> Self {
1670 ArcBiPredicate {
1671 function: Arc::clone(&self.function),
1672 name: self.name.clone(),
1673 }
1674 }
1675}
1676
1677impl<T, U> Display for ArcBiPredicate<T, U> {
1678 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1679 write!(
1680 f,
1681 "ArcBiPredicate({})",
1682 self.name.as_deref().unwrap_or("unnamed")
1683 )
1684 }
1685}
1686
1687impl<T, U> Debug for ArcBiPredicate<T, U> {
1688 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1689 f.debug_struct("ArcBiPredicate")
1690 .field("name", &self.name)
1691 .finish()
1692 }
1693}
1694
1695// Blanket implementation for all closures that match
1696// Fn(&T, &U) -> bool. This provides optimal implementations for
1697// closures by wrapping them directly into the target type.
1698impl<T: 'static, U: 'static, F> BiPredicate<T, U> for F
1699where
1700 F: Fn(&T, &U) -> bool + 'static,
1701{
1702 fn test(&self, first: &T, second: &U) -> bool {
1703 self(first, second)
1704 }
1705
1706 // Optimal implementation for closures: wrap directly in Box
1707 fn into_box(self) -> BoxBiPredicate<T, U> {
1708 BoxBiPredicate::new(self)
1709 }
1710
1711 // Optimal implementation for closures: wrap directly in Rc
1712 fn into_rc(self) -> RcBiPredicate<T, U> {
1713 RcBiPredicate::new(self)
1714 }
1715
1716 // Optimal implementation for closures: wrap directly in Arc
1717 fn into_arc(self) -> ArcBiPredicate<T, U>
1718 where
1719 Self: Send + Sync,
1720 T: Send + Sync,
1721 U: Send + Sync,
1722 {
1723 ArcBiPredicate::new(self)
1724 }
1725
1726 // Optimal implementation for closures: return self (zero-cost)
1727 fn into_fn(self) -> impl Fn(&T, &U) -> bool {
1728 self
1729 }
1730
1731 fn to_box(&self) -> BoxBiPredicate<T, U>
1732 where
1733 Self: Sized + Clone + 'static,
1734 T: 'static,
1735 U: 'static,
1736 {
1737 BoxBiPredicate::new(self.clone())
1738 }
1739
1740 fn to_rc(&self) -> RcBiPredicate<T, U>
1741 where
1742 Self: Sized + Clone + 'static,
1743 T: 'static,
1744 U: 'static,
1745 {
1746 RcBiPredicate::new(self.clone())
1747 }
1748
1749 fn to_arc(&self) -> ArcBiPredicate<T, U>
1750 where
1751 Self: Sized + Clone + Send + Sync + 'static,
1752 T: Send + Sync + 'static,
1753 U: Send + Sync + 'static,
1754 {
1755 ArcBiPredicate::new(self.clone())
1756 }
1757
1758 fn to_fn(&self) -> impl Fn(&T, &U) -> bool
1759 where
1760 Self: Sized + Clone + 'static,
1761 T: 'static,
1762 U: 'static,
1763 {
1764 self.clone()
1765 }
1766}
1767
1768/// Extension trait providing logical composition methods for closures.
1769///
1770/// This trait is automatically implemented for all closures and
1771/// function pointers that match `Fn(&T, &U) -> bool`, enabling method
1772/// chaining starting from a closure.
1773///
1774/// # Examples
1775///
1776/// ```rust
1777/// use prism3_function::bi_predicate::{BiPredicate, FnBiPredicateOps};
1778///
1779/// let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
1780/// let first_larger = |x: &i32, y: &i32| x > y;
1781///
1782/// // Combine bi-predicates using extension methods
1783/// let pred = is_sum_positive.and(first_larger);
1784/// assert!(pred.test(&10, &5));
1785/// assert!(!pred.test(&3, &8));
1786/// ```
1787///
1788/// # Author
1789///
1790/// Haixing Hu
1791pub trait FnBiPredicateOps<T, U>: Fn(&T, &U) -> bool + Sized + 'static {
1792 /// Returns a bi-predicate that represents the logical AND of this
1793 /// bi-predicate and another.
1794 ///
1795 /// # Parameters
1796 ///
1797 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1798 /// is passed by value and will transfer ownership.** If you need to
1799 /// preserve the original bi-predicate, clone it first (if it implements
1800 /// `Clone`). Can be:
1801 /// - Another closure: `|x: &T, y: &U| -> bool`
1802 /// - A function pointer: `fn(&T, &U) -> bool`
1803 /// - A `BoxBiPredicate<T, U>`
1804 /// - An `RcBiPredicate<T, U>`
1805 /// - An `ArcBiPredicate<T, U>`
1806 /// - Any type implementing `BiPredicate<T, U>`
1807 ///
1808 /// # Returns
1809 ///
1810 /// A `BoxBiPredicate` representing the logical AND.
1811 fn and<P>(self, other: P) -> BoxBiPredicate<T, U>
1812 where
1813 P: BiPredicate<T, U> + 'static,
1814 T: 'static,
1815 U: 'static,
1816 {
1817 BoxBiPredicate::new(move |first, second| self(first, second) && other.test(first, second))
1818 }
1819
1820 /// Returns a bi-predicate that represents the logical OR of this
1821 /// bi-predicate and another.
1822 ///
1823 /// # Parameters
1824 ///
1825 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1826 /// is passed by value and will transfer ownership.** If you need to
1827 /// preserve the original bi-predicate, clone it first (if it implements
1828 /// `Clone`). Can be:
1829 /// - Another closure: `|x: &T, y: &U| -> bool`
1830 /// - A function pointer: `fn(&T, &U) -> bool`
1831 /// - A `BoxBiPredicate<T, U>`
1832 /// - An `RcBiPredicate<T, U>`
1833 /// - An `ArcBiPredicate<T, U>`
1834 /// - Any type implementing `BiPredicate<T, U>`
1835 ///
1836 /// # Returns
1837 ///
1838 /// A `BoxBiPredicate` representing the logical OR.
1839 fn or<P>(self, other: P) -> BoxBiPredicate<T, U>
1840 where
1841 P: BiPredicate<T, U> + 'static,
1842 T: 'static,
1843 U: 'static,
1844 {
1845 BoxBiPredicate::new(move |first, second| self(first, second) || other.test(first, second))
1846 }
1847
1848 /// Returns a bi-predicate that represents the logical negation of
1849 /// this bi-predicate.
1850 ///
1851 /// # Returns
1852 ///
1853 /// A `BoxBiPredicate` representing the logical negation.
1854 fn not(self) -> BoxBiPredicate<T, U>
1855 where
1856 T: 'static,
1857 U: 'static,
1858 {
1859 BoxBiPredicate::new(move |first, second| !self(first, second))
1860 }
1861
1862 /// Returns a bi-predicate that represents the logical NAND (NOT
1863 /// AND) of this bi-predicate and another.
1864 ///
1865 /// NAND returns `true` unless both bi-predicates are `true`.
1866 /// Equivalent to `!(self AND other)`.
1867 ///
1868 /// # Parameters
1869 ///
1870 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1871 /// is passed by value and will transfer ownership.** If you need to
1872 /// preserve the original bi-predicate, clone it first (if it implements
1873 /// `Clone`). Can be:
1874 /// - Another closure: `|x: &T, y: &U| -> bool`
1875 /// - A function pointer: `fn(&T, &U) -> bool`
1876 /// - A `BoxBiPredicate<T, U>`
1877 /// - An `RcBiPredicate<T, U>`
1878 /// - An `ArcBiPredicate<T, U>`
1879 /// - Any type implementing `BiPredicate<T, U>`
1880 ///
1881 /// # Returns
1882 ///
1883 /// A `BoxBiPredicate` representing the logical NAND.
1884 fn nand<P>(self, other: P) -> BoxBiPredicate<T, U>
1885 where
1886 P: BiPredicate<T, U> + 'static,
1887 T: 'static,
1888 U: 'static,
1889 {
1890 BoxBiPredicate::new(move |first, second| {
1891 !(self(first, second) && other.test(first, second))
1892 })
1893 }
1894
1895 /// Returns a bi-predicate that represents the logical XOR
1896 /// (exclusive OR) of this bi-predicate and another.
1897 ///
1898 /// XOR returns `true` if exactly one of the bi-predicates is
1899 /// `true`.
1900 ///
1901 /// # Parameters
1902 ///
1903 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1904 /// is passed by value and will transfer ownership.** If you need to
1905 /// preserve the original bi-predicate, clone it first (if it implements
1906 /// `Clone`). Can be:
1907 /// - Another closure: `|x: &T, y: &U| -> bool`
1908 /// - A function pointer: `fn(&T, &U) -> bool`
1909 /// - A `BoxBiPredicate<T, U>`
1910 /// - An `RcBiPredicate<T, U>`
1911 /// - An `ArcBiPredicate<T, U>`
1912 /// - Any type implementing `BiPredicate<T, U>`
1913 ///
1914 /// # Returns
1915 ///
1916 /// A `BoxBiPredicate` representing the logical XOR.
1917 fn xor<P>(self, other: P) -> BoxBiPredicate<T, U>
1918 where
1919 P: BiPredicate<T, U> + 'static,
1920 T: 'static,
1921 U: 'static,
1922 {
1923 BoxBiPredicate::new(move |first, second| self(first, second) ^ other.test(first, second))
1924 }
1925
1926 /// Returns a bi-predicate that represents the logical NOR (NOT
1927 /// OR) of this bi-predicate and another.
1928 ///
1929 /// NOR returns `true` only if both bi-predicates are `false`.
1930 /// Equivalent to `!(self OR other)`.
1931 ///
1932 /// # Parameters
1933 ///
1934 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1935 /// is passed by value and will transfer ownership.** If you need to
1936 /// preserve the original bi-predicate, clone it first (if it implements
1937 /// `Clone`). Can be:
1938 /// - Another closure: `|x: &T, y: &U| -> bool`
1939 /// - A function pointer: `fn(&T, &U) -> bool`
1940 /// - A `BoxBiPredicate<T, U>`
1941 /// - An `RcBiPredicate<T, U>`
1942 /// - An `ArcBiPredicate<T, U>`
1943 /// - Any type implementing `BiPredicate<T, U>`
1944 ///
1945 /// # Returns
1946 ///
1947 /// A `BoxBiPredicate` representing the logical NOR.
1948 fn nor<P>(self, other: P) -> BoxBiPredicate<T, U>
1949 where
1950 P: BiPredicate<T, U> + 'static,
1951 T: 'static,
1952 U: 'static,
1953 {
1954 BoxBiPredicate::new(move |first, second| {
1955 !(self(first, second) || other.test(first, second))
1956 })
1957 }
1958}
1959
1960// Blanket implementation for all closures
1961impl<T, U, F> FnBiPredicateOps<T, U> for F where F: Fn(&T, &U) -> bool + 'static {}