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 fn into_box(self) -> BoxBiPredicate<T, U>
277 where
278 Self: Sized + 'static,
279 T: 'static,
280 U: 'static;
281
282 /// Converts this bi-predicate into an `RcBiPredicate`.
283 ///
284 /// # Returns
285 ///
286 /// An `RcBiPredicate` wrapping this bi-predicate.
287 fn into_rc(self) -> RcBiPredicate<T, U>
288 where
289 Self: Sized + 'static,
290 T: 'static,
291 U: 'static;
292
293 /// Converts this bi-predicate into an `ArcBiPredicate`.
294 ///
295 /// # Returns
296 ///
297 /// An `ArcBiPredicate` wrapping this bi-predicate.
298 fn into_arc(self) -> ArcBiPredicate<T, U>
299 where
300 Self: Sized + Send + Sync + 'static,
301 T: Send + Sync + 'static,
302 U: Send + Sync + 'static;
303
304 /// Converts this bi-predicate into a closure that can be used
305 /// directly with standard library methods.
306 ///
307 /// This method consumes the bi-predicate and returns a closure
308 /// with signature `Fn(&T, &U) -> bool`. Since `Fn` is a subtrait
309 /// of `FnMut`, the returned closure can be used in any context
310 /// that requires either `Fn(&T, &U) -> bool` or
311 /// `FnMut(&T, &U) -> bool`.
312 ///
313 /// # Returns
314 ///
315 /// A closure implementing `Fn(&T, &U) -> bool` (also usable as
316 /// `FnMut(&T, &U) -> bool`).
317 ///
318 /// # Examples
319 ///
320 /// ## Using with Iterator Methods
321 ///
322 /// ```rust
323 /// use prism3_function::bi_predicate::{BiPredicate,
324 /// BoxBiPredicate};
325 ///
326 /// let pred = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
327 ///
328 /// let pairs = vec![(1, 2), (-1, 3), (5, -6)];
329 /// let mut closure = pred.into_fn();
330 /// let positives: Vec<_> = pairs.iter()
331 /// .filter(|(x, y)| closure(x, y))
332 /// .collect();
333 /// assert_eq!(positives, vec![&(1, 2), &(-1, 3)]);
334 /// ```
335 fn into_fn(self) -> impl Fn(&T, &U) -> bool
336 where
337 Self: Sized + 'static,
338 T: 'static,
339 U: 'static;
340}
341
342/// A Box-based bi-predicate with single ownership.
343///
344/// This type is suitable for one-time use scenarios where the
345/// bi-predicate does not need to be cloned or shared. Composition
346/// methods consume `self`, reflecting the single-ownership model.
347///
348/// # Examples
349///
350/// ```rust
351/// use prism3_function::bi_predicate::{BiPredicate, BoxBiPredicate};
352///
353/// let pred = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
354/// assert!(pred.test(&5, &3));
355///
356/// // Chaining consumes the bi-predicate
357/// let combined = pred.and(BoxBiPredicate::new(|x, y| x > y));
358/// assert!(combined.test(&10, &5));
359/// ```
360///
361/// # Author
362///
363/// Haixing Hu
364pub struct BoxBiPredicate<T, U> {
365 function: Box<BiPredicateFn<T, U>>,
366 name: Option<String>,
367}
368
369impl<T, U> BoxBiPredicate<T, U> {
370 /// Creates a new `BoxBiPredicate` from a closure.
371 ///
372 /// # Parameters
373 ///
374 /// * `f` - The closure to wrap.
375 ///
376 /// # Returns
377 ///
378 /// A new `BoxBiPredicate` instance.
379 pub fn new<F>(f: F) -> Self
380 where
381 F: Fn(&T, &U) -> bool + 'static,
382 {
383 Self {
384 function: Box::new(f),
385 name: None,
386 }
387 }
388
389 /// Creates a named `BoxBiPredicate` from a closure.
390 ///
391 /// # Parameters
392 ///
393 /// * `name` - The name for this bi-predicate.
394 /// * `f` - The closure to wrap.
395 ///
396 /// # Returns
397 ///
398 /// A new named `BoxBiPredicate` instance.
399 pub fn new_with_name<F>(name: &str, f: F) -> Self
400 where
401 F: Fn(&T, &U) -> bool + 'static,
402 {
403 Self {
404 function: Box::new(f),
405 name: Some(name.to_string()),
406 }
407 }
408
409 /// Creates a bi-predicate that always returns `true`.
410 ///
411 /// # Returns
412 ///
413 /// A new `BoxBiPredicate` that always returns `true`.
414 ///
415 /// # Examples
416 ///
417 /// ```rust
418 /// use prism3_function::bi_predicate::{BiPredicate, BoxBiPredicate};
419 ///
420 /// let pred: BoxBiPredicate<i32, i32> = BoxBiPredicate::always_true();
421 /// assert!(pred.test(&42, &10));
422 /// assert!(pred.test(&-1, &5));
423 /// assert!(pred.test(&0, &0));
424 /// ```
425 pub fn always_true() -> Self {
426 Self {
427 function: Box::new(|_, _| true),
428 name: Some(ALWAYS_TRUE_NAME.to_string()),
429 }
430 }
431
432 /// Creates a bi-predicate that always returns `false`.
433 ///
434 /// # Returns
435 ///
436 /// A new `BoxBiPredicate` that always returns `false`.
437 ///
438 /// # Examples
439 ///
440 /// ```rust
441 /// use prism3_function::bi_predicate::{BiPredicate, BoxBiPredicate};
442 ///
443 /// let pred: BoxBiPredicate<i32, i32> = BoxBiPredicate::always_false();
444 /// assert!(!pred.test(&42, &10));
445 /// assert!(!pred.test(&-1, &5));
446 /// assert!(!pred.test(&0, &0));
447 /// ```
448 pub fn always_false() -> Self {
449 Self {
450 function: Box::new(|_, _| false),
451 name: Some(ALWAYS_FALSE_NAME.to_string()),
452 }
453 }
454
455 /// Returns the name of this bi-predicate, if set.
456 ///
457 /// # Returns
458 ///
459 /// An `Option` containing the bi-predicate's name.
460 pub fn name(&self) -> Option<&str> {
461 self.name.as_deref()
462 }
463
464 /// Sets the name of this bi-predicate.
465 ///
466 /// # Parameters
467 ///
468 /// * `name` - The new name for this bi-predicate.
469 pub fn set_name(&mut self, name: &str) {
470 self.name = Some(name.to_string());
471 }
472
473 /// Returns a bi-predicate that represents the logical AND of this
474 /// bi-predicate and another.
475 ///
476 /// This method consumes `self` due to single-ownership semantics.
477 ///
478 /// # Parameters
479 ///
480 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
481 /// is passed by value and will transfer ownership.** If you need to
482 /// preserve the original bi-predicate, clone it first (if it implements
483 /// `Clone`). Can be:
484 /// - A closure: `|x: &T, y: &U| -> bool`
485 /// - A function pointer: `fn(&T, &U) -> bool`
486 /// - Another `BoxBiPredicate<T, U>`
487 /// - An `RcBiPredicate<T, U>`
488 /// - An `ArcBiPredicate<T, U>`
489 /// - Any type implementing `BiPredicate<T, U>`
490 ///
491 /// # Returns
492 ///
493 /// A new `BoxBiPredicate` representing the logical AND.
494 pub fn and<P>(self, other: P) -> BoxBiPredicate<T, U>
495 where
496 P: BiPredicate<T, U> + 'static,
497 T: 'static,
498 U: 'static,
499 {
500 BoxBiPredicate {
501 function: Box::new(move |first: &T, second: &U| {
502 (self.function)(first, second) && other.test(first, second)
503 }),
504 name: None,
505 }
506 }
507
508 /// Returns a bi-predicate that represents the logical OR of this
509 /// bi-predicate and another.
510 ///
511 /// This method consumes `self` due to single-ownership semantics.
512 ///
513 /// # Parameters
514 ///
515 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
516 /// is passed by value and will transfer ownership.** If you need to
517 /// preserve the original bi-predicate, clone it first (if it implements
518 /// `Clone`). Can be:
519 /// - A closure: `|x: &T, y: &U| -> bool`
520 /// - A function pointer: `fn(&T, &U) -> bool`
521 /// - Another `BoxBiPredicate<T, U>`
522 /// - An `RcBiPredicate<T, U>`
523 /// - An `ArcBiPredicate<T, U>`
524 /// - Any type implementing `BiPredicate<T, U>`
525 ///
526 /// # Returns
527 ///
528 /// A new `BoxBiPredicate` representing the logical OR.
529 pub fn or<P>(self, other: P) -> BoxBiPredicate<T, U>
530 where
531 P: BiPredicate<T, U> + 'static,
532 T: 'static,
533 U: 'static,
534 {
535 BoxBiPredicate {
536 function: Box::new(move |first: &T, second: &U| {
537 (self.function)(first, second) || other.test(first, second)
538 }),
539 name: None,
540 }
541 }
542
543 /// Returns a bi-predicate that represents the logical negation of
544 /// this bi-predicate.
545 ///
546 /// This method consumes `self` due to single-ownership semantics.
547 ///
548 /// # Returns
549 ///
550 /// A new `BoxBiPredicate` representing the logical negation.
551 #[allow(clippy::should_implement_trait)]
552 pub fn not(self) -> BoxBiPredicate<T, U>
553 where
554 T: 'static,
555 U: 'static,
556 {
557 BoxBiPredicate {
558 function: Box::new(move |first: &T, second: &U| !(self.function)(first, second)),
559 name: None,
560 }
561 }
562
563 /// Returns a bi-predicate that represents the logical NAND (NOT
564 /// AND) of this bi-predicate and another.
565 ///
566 /// NAND returns `true` unless both bi-predicates are `true`.
567 /// Equivalent to `!(self AND other)`.
568 ///
569 /// This method consumes `self` due to single-ownership semantics.
570 ///
571 /// # Parameters
572 ///
573 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
574 /// is passed by value and will transfer ownership.** If you need to
575 /// preserve the original bi-predicate, clone it first (if it implements
576 /// `Clone`). Can be:
577 /// - A closure: `|x: &T, y: &U| -> bool`
578 /// - A function pointer: `fn(&T, &U) -> bool`
579 /// - Another `BoxBiPredicate<T, U>`
580 /// - An `RcBiPredicate<T, U>`
581 /// - An `ArcBiPredicate<T, U>`
582 /// - Any type implementing `BiPredicate<T, U>`
583 ///
584 /// # Returns
585 ///
586 /// A new `BoxBiPredicate` representing the logical NAND.
587 pub fn nand<P>(self, other: P) -> BoxBiPredicate<T, U>
588 where
589 P: BiPredicate<T, U> + 'static,
590 T: 'static,
591 U: 'static,
592 {
593 BoxBiPredicate {
594 function: Box::new(move |first: &T, second: &U| {
595 !((self.function)(first, second) && other.test(first, second))
596 }),
597 name: None,
598 }
599 }
600
601 /// Returns a bi-predicate that represents the logical XOR
602 /// (exclusive OR) of this bi-predicate and another.
603 ///
604 /// XOR returns `true` if exactly one of the bi-predicates is
605 /// `true`.
606 ///
607 /// This method consumes `self` due to single-ownership semantics.
608 ///
609 /// # Parameters
610 ///
611 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
612 /// is passed by value and will transfer ownership.** If you need to
613 /// preserve the original bi-predicate, clone it first (if it implements
614 /// `Clone`). Can be:
615 /// - A closure: `|x: &T, y: &U| -> bool`
616 /// - A function pointer: `fn(&T, &U) -> bool`
617 /// - Another `BoxBiPredicate<T, U>`
618 /// - An `RcBiPredicate<T, U>`
619 /// - An `ArcBiPredicate<T, U>`
620 /// - Any type implementing `BiPredicate<T, U>`
621 ///
622 /// # Returns
623 ///
624 /// A new `BoxBiPredicate` representing the logical XOR.
625 pub fn xor<P>(self, other: P) -> BoxBiPredicate<T, U>
626 where
627 P: BiPredicate<T, U> + 'static,
628 T: 'static,
629 U: 'static,
630 {
631 BoxBiPredicate {
632 function: Box::new(move |first: &T, second: &U| {
633 (self.function)(first, second) ^ other.test(first, second)
634 }),
635 name: None,
636 }
637 }
638
639 /// Returns a bi-predicate that represents the logical NOR (NOT
640 /// OR) of this bi-predicate and another.
641 ///
642 /// NOR returns `true` only if both bi-predicates are `false`.
643 /// Equivalent to `!(self OR other)`.
644 ///
645 /// This method consumes `self` due to single-ownership semantics.
646 ///
647 /// # Parameters
648 ///
649 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
650 /// is passed by value and will transfer ownership.** If you need to
651 /// preserve the original bi-predicate, clone it first (if it implements
652 /// `Clone`). Can be:
653 /// - A closure: `|x: &T, y: &U| -> bool`
654 /// - A function pointer: `fn(&T, &U) -> bool`
655 /// - Another `BoxBiPredicate<T, U>`
656 /// - An `RcBiPredicate<T, U>`
657 /// - An `ArcBiPredicate<T, U>`
658 /// - Any type implementing `BiPredicate<T, U>`
659 ///
660 /// # Returns
661 ///
662 /// A new `BoxBiPredicate` representing the logical NOR.
663 pub fn nor<P>(self, other: P) -> BoxBiPredicate<T, U>
664 where
665 P: BiPredicate<T, U> + 'static,
666 T: 'static,
667 U: 'static,
668 {
669 BoxBiPredicate {
670 function: Box::new(move |first: &T, second: &U| {
671 !((self.function)(first, second) || other.test(first, second))
672 }),
673 name: None,
674 }
675 }
676}
677
678impl<T, U> BiPredicate<T, U> for BoxBiPredicate<T, U> {
679 fn test(&self, first: &T, second: &U) -> bool {
680 (self.function)(first, second)
681 }
682
683 fn into_box(self) -> BoxBiPredicate<T, U>
684 where
685 T: 'static,
686 U: 'static,
687 {
688 self
689 }
690
691 fn into_rc(self) -> RcBiPredicate<T, U>
692 where
693 T: 'static,
694 U: 'static,
695 {
696 RcBiPredicate {
697 function: Rc::from(self.function),
698 name: self.name,
699 }
700 }
701
702 fn into_arc(self) -> ArcBiPredicate<T, U>
703 where
704 Self: Send + Sync,
705 T: Send + Sync + 'static,
706 U: Send + Sync + 'static,
707 {
708 panic!("BoxBiPredicate cannot be converted to ArcBiPredicate - use ArcBiPredicate::new directly")
709 }
710
711 fn into_fn(self) -> impl Fn(&T, &U) -> bool
712 where
713 Self: Sized + 'static,
714 T: 'static,
715 U: 'static,
716 {
717 move |first: &T, second: &U| (self.function)(first, second)
718 }
719}
720
721impl<T, U> Display for BoxBiPredicate<T, U> {
722 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
723 write!(
724 f,
725 "BoxBiPredicate({})",
726 self.name.as_deref().unwrap_or("unnamed")
727 )
728 }
729}
730
731impl<T, U> Debug for BoxBiPredicate<T, U> {
732 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
733 f.debug_struct("BoxBiPredicate")
734 .field("name", &self.name)
735 .finish()
736 }
737}
738
739/// An Rc-based bi-predicate with single-threaded shared ownership.
740///
741/// This type is suitable for scenarios where the bi-predicate needs
742/// to be reused in a single-threaded context. Composition methods
743/// borrow `&self`, allowing the original bi-predicate to remain
744/// usable after composition.
745///
746/// # Examples
747///
748/// ```rust
749/// use prism3_function::bi_predicate::{BiPredicate, RcBiPredicate};
750///
751/// let pred = RcBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
752/// assert!(pred.test(&5, &3));
753///
754/// // Original bi-predicate remains usable after composition
755/// let combined = pred.and(RcBiPredicate::new(|x, y| x > y));
756/// assert!(pred.test(&5, &3)); // Still works
757/// ```
758///
759/// # Author
760///
761/// Haixing Hu
762pub struct RcBiPredicate<T, U> {
763 function: Rc<BiPredicateFn<T, U>>,
764 name: Option<String>,
765}
766
767impl<T, U> RcBiPredicate<T, U> {
768 /// Creates a new `RcBiPredicate` from a closure.
769 ///
770 /// # Parameters
771 ///
772 /// * `f` - The closure to wrap.
773 ///
774 /// # Returns
775 ///
776 /// A new `RcBiPredicate` instance.
777 pub fn new<F>(f: F) -> Self
778 where
779 F: Fn(&T, &U) -> bool + 'static,
780 {
781 Self {
782 function: Rc::new(f),
783 name: None,
784 }
785 }
786
787 /// Creates a named `RcBiPredicate` from a closure.
788 ///
789 /// # Parameters
790 ///
791 /// * `name` - The name for this bi-predicate.
792 /// * `f` - The closure to wrap.
793 ///
794 /// # Returns
795 ///
796 /// A new named `RcBiPredicate` instance.
797 pub fn new_with_name<F>(name: &str, f: F) -> Self
798 where
799 F: Fn(&T, &U) -> bool + 'static,
800 {
801 Self {
802 function: Rc::new(f),
803 name: Some(name.to_string()),
804 }
805 }
806
807 /// Creates a bi-predicate that always returns `true`.
808 ///
809 /// # Returns
810 ///
811 /// A new `RcBiPredicate` that always returns `true`.
812 ///
813 /// # Examples
814 ///
815 /// ```rust
816 /// use prism3_function::bi_predicate::{BiPredicate, RcBiPredicate};
817 ///
818 /// let pred: RcBiPredicate<i32, i32> = RcBiPredicate::always_true();
819 /// assert!(pred.test(&42, &10));
820 /// assert!(pred.test(&-1, &5));
821 /// assert!(pred.test(&0, &0));
822 /// ```
823 pub fn always_true() -> Self {
824 Self {
825 function: Rc::new(|_, _| true),
826 name: Some(ALWAYS_TRUE_NAME.to_string()),
827 }
828 }
829
830 /// Creates a bi-predicate that always returns `false`.
831 ///
832 /// # Returns
833 ///
834 /// A new `RcBiPredicate` that always returns `false`.
835 ///
836 /// # Examples
837 ///
838 /// ```rust
839 /// use prism3_function::bi_predicate::{BiPredicate, RcBiPredicate};
840 ///
841 /// let pred: RcBiPredicate<i32, i32> = RcBiPredicate::always_false();
842 /// assert!(!pred.test(&42, &10));
843 /// assert!(!pred.test(&-1, &5));
844 /// assert!(!pred.test(&0, &0));
845 /// ```
846 pub fn always_false() -> Self {
847 Self {
848 function: Rc::new(|_, _| false),
849 name: Some(ALWAYS_FALSE_NAME.to_string()),
850 }
851 }
852
853 /// Returns the name of this bi-predicate, if set.
854 ///
855 /// # Returns
856 ///
857 /// An `Option` containing the bi-predicate's name.
858 pub fn name(&self) -> Option<&str> {
859 self.name.as_deref()
860 }
861
862 /// Sets the name of this bi-predicate.
863 ///
864 /// # Parameters
865 ///
866 /// * `name` - The new name for this bi-predicate.
867 pub fn set_name(&mut self, name: &str) {
868 self.name = Some(name.to_string());
869 }
870
871 /// Returns a bi-predicate that represents the logical AND of this
872 /// bi-predicate and another.
873 ///
874 /// # Parameters
875 ///
876 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
877 /// is passed by value and will transfer ownership.** If you need to
878 /// preserve the original bi-predicate, clone it first (if it implements
879 /// `Clone`). Can be:
880 /// - A closure: `|x: &T, y: &U| -> bool`
881 /// - A function pointer: `fn(&T, &U) -> bool`
882 /// - A `BoxBiPredicate<T, U>`
883 /// - Another `RcBiPredicate<T, U>` (will be moved)
884 /// - An `ArcBiPredicate<T, U>`
885 /// - Any type implementing `BiPredicate<T, U>`
886 ///
887 /// # Returns
888 ///
889 /// A new `RcBiPredicate` representing the logical AND.
890 pub fn and<P>(&self, other: P) -> RcBiPredicate<T, U>
891 where
892 P: BiPredicate<T, U> + 'static,
893 T: 'static,
894 U: 'static,
895 {
896 let self_fn = Rc::clone(&self.function);
897 RcBiPredicate {
898 function: Rc::new(move |first: &T, second: &U| {
899 self_fn(first, second) && other.test(first, second)
900 }),
901 name: None,
902 }
903 }
904
905 /// Returns a bi-predicate that represents the logical OR of this
906 /// bi-predicate and another.
907 ///
908 /// # Parameters
909 ///
910 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
911 /// is passed by value and will transfer ownership.** If you need to
912 /// preserve the original bi-predicate, clone it first (if it implements
913 /// `Clone`). Can be:
914 /// - A closure: `|x: &T, y: &U| -> bool`
915 /// - A function pointer: `fn(&T, &U) -> bool`
916 /// - A `BoxBiPredicate<T, U>`
917 /// - Another `RcBiPredicate<T, U>` (will be moved)
918 /// - An `ArcBiPredicate<T, U>`
919 /// - Any type implementing `BiPredicate<T, U>`
920 ///
921 /// # Returns
922 ///
923 /// A new `RcBiPredicate` representing the logical OR.
924 pub fn or<P>(&self, other: P) -> RcBiPredicate<T, U>
925 where
926 P: BiPredicate<T, U> + 'static,
927 T: 'static,
928 U: 'static,
929 {
930 let self_fn = Rc::clone(&self.function);
931 RcBiPredicate {
932 function: Rc::new(move |first: &T, second: &U| {
933 self_fn(first, second) || other.test(first, second)
934 }),
935 name: None,
936 }
937 }
938
939 /// Returns a bi-predicate that represents the logical negation of
940 /// this bi-predicate.
941 ///
942 /// # Returns
943 ///
944 /// A new `RcBiPredicate` representing the logical negation.
945 #[allow(clippy::should_implement_trait)]
946 pub fn not(&self) -> RcBiPredicate<T, U>
947 where
948 T: 'static,
949 U: 'static,
950 {
951 let self_fn = Rc::clone(&self.function);
952 RcBiPredicate {
953 function: Rc::new(move |first: &T, second: &U| !self_fn(first, second)),
954 name: None,
955 }
956 }
957
958 /// Returns a bi-predicate that represents the logical NAND (NOT
959 /// AND) of this bi-predicate and another.
960 ///
961 /// NAND returns `true` unless both bi-predicates are `true`.
962 /// Equivalent to `!(self AND other)`.
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 NAND.
980 pub fn nand<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: &T, second: &U| {
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 XOR
996 /// (exclusive OR) of this bi-predicate and another.
997 ///
998 /// XOR returns `true` if exactly one of the bi-predicates is
999 /// `true`.
1000 ///
1001 /// # Parameters
1002 ///
1003 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1004 /// is passed by value and will transfer ownership.** If you need to
1005 /// preserve the original bi-predicate, clone it first (if it implements
1006 /// `Clone`). Can be:
1007 /// - A closure: `|x: &T, y: &U| -> bool`
1008 /// - A function pointer: `fn(&T, &U) -> bool`
1009 /// - A `BoxBiPredicate<T, U>`
1010 /// - Another `RcBiPredicate<T, U>` (will be moved)
1011 /// - An `ArcBiPredicate<T, U>`
1012 /// - Any type implementing `BiPredicate<T, U>`
1013 ///
1014 /// # Returns
1015 ///
1016 /// A new `RcBiPredicate` representing the logical XOR.
1017 pub fn xor<P>(&self, other: P) -> RcBiPredicate<T, U>
1018 where
1019 P: BiPredicate<T, U> + 'static,
1020 T: 'static,
1021 U: 'static,
1022 {
1023 let self_fn = Rc::clone(&self.function);
1024 RcBiPredicate {
1025 function: Rc::new(move |first: &T, second: &U| {
1026 self_fn(first, second) ^ other.test(first, second)
1027 }),
1028 name: None,
1029 }
1030 }
1031
1032 /// Returns a bi-predicate that represents the logical NOR (NOT
1033 /// OR) of this bi-predicate and another.
1034 ///
1035 /// NOR returns `true` only if both bi-predicates are `false`.
1036 /// Equivalent to `!(self OR other)`.
1037 ///
1038 /// # Parameters
1039 ///
1040 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1041 /// is passed by value and will transfer ownership.** If you need to
1042 /// preserve the original bi-predicate, clone it first (if it implements
1043 /// `Clone`). Can be:
1044 /// - A closure: `|x: &T, y: &U| -> bool`
1045 /// - A function pointer: `fn(&T, &U) -> bool`
1046 /// - A `BoxBiPredicate<T, U>`
1047 /// - Another `RcBiPredicate<T, U>` (will be moved)
1048 /// - An `ArcBiPredicate<T, U>`
1049 /// - Any type implementing `BiPredicate<T, U>`
1050 ///
1051 /// # Returns
1052 ///
1053 /// A new `RcBiPredicate` representing the logical NOR.
1054 pub fn nor<P>(&self, other: P) -> RcBiPredicate<T, U>
1055 where
1056 P: BiPredicate<T, U> + 'static,
1057 T: 'static,
1058 U: 'static,
1059 {
1060 let self_fn = Rc::clone(&self.function);
1061 RcBiPredicate {
1062 function: Rc::new(move |first: &T, second: &U| {
1063 !(self_fn(first, second) || other.test(first, second))
1064 }),
1065 name: None,
1066 }
1067 }
1068
1069 /// Converts this bi-predicate to a `BoxBiPredicate`.
1070 ///
1071 /// # Returns
1072 ///
1073 /// A `BoxBiPredicate` wrapping this bi-predicate.
1074 pub fn to_box(&self) -> BoxBiPredicate<T, U>
1075 where
1076 T: 'static,
1077 U: 'static,
1078 {
1079 let self_fn = Rc::clone(&self.function);
1080 BoxBiPredicate {
1081 function: Box::new(move |first: &T, second: &U| self_fn(first, second)),
1082 name: self.name.clone(),
1083 }
1084 }
1085
1086 /// Converts this bi-predicate to a closure that can be used
1087 /// directly with standard library methods.
1088 ///
1089 /// This method creates a new closure without consuming the
1090 /// original bi-predicate, since `RcBiPredicate` uses shared
1091 /// ownership. The returned closure has signature
1092 /// `Fn(&T, &U) -> bool`.
1093 ///
1094 /// # Returns
1095 ///
1096 /// A closure implementing `Fn(&T, &U) -> bool`.
1097 pub fn to_fn(&self) -> impl Fn(&T, &U) -> bool
1098 where
1099 T: 'static,
1100 U: 'static,
1101 {
1102 let function = Rc::clone(&self.function);
1103 move |first: &T, second: &U| function(first, second)
1104 }
1105}
1106
1107impl<T, U> BiPredicate<T, U> for RcBiPredicate<T, U> {
1108 fn test(&self, first: &T, second: &U) -> bool {
1109 (self.function)(first, second)
1110 }
1111
1112 fn into_box(self) -> BoxBiPredicate<T, U>
1113 where
1114 T: 'static,
1115 U: 'static,
1116 {
1117 let self_fn = self.function;
1118 BoxBiPredicate {
1119 function: Box::new(move |first: &T, second: &U| self_fn(first, second)),
1120 name: self.name,
1121 }
1122 }
1123
1124 fn into_rc(self) -> RcBiPredicate<T, U>
1125 where
1126 T: 'static,
1127 U: 'static,
1128 {
1129 self
1130 }
1131
1132 fn into_arc(self) -> ArcBiPredicate<T, U>
1133 where
1134 Self: Send + Sync,
1135 T: Send + Sync + 'static,
1136 U: Send + Sync + 'static,
1137 {
1138 panic!("RcBiPredicate cannot be converted to ArcBiPredicate - use ArcBiPredicate::new directly")
1139 }
1140
1141 fn into_fn(self) -> impl Fn(&T, &U) -> bool
1142 where
1143 Self: Sized + 'static,
1144 T: 'static,
1145 U: 'static,
1146 {
1147 let self_fn = self.function;
1148 move |first: &T, second: &U| self_fn(first, second)
1149 }
1150}
1151
1152impl<T, U> Clone for RcBiPredicate<T, U> {
1153 /// Clones this bi-predicate.
1154 ///
1155 /// Creates a new instance that shares the underlying function with
1156 /// the original, allowing multiple references to the same
1157 /// bi-predicate logic.
1158 fn clone(&self) -> Self {
1159 Self {
1160 function: Rc::clone(&self.function),
1161 name: self.name.clone(),
1162 }
1163 }
1164}
1165
1166impl<T, U> Display for RcBiPredicate<T, U> {
1167 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1168 write!(
1169 f,
1170 "RcBiPredicate({})",
1171 self.name.as_deref().unwrap_or("unnamed")
1172 )
1173 }
1174}
1175
1176impl<T, U> Debug for RcBiPredicate<T, U> {
1177 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1178 f.debug_struct("RcBiPredicate")
1179 .field("name", &self.name)
1180 .finish()
1181 }
1182}
1183
1184/// An Arc-based bi-predicate with thread-safe shared ownership.
1185///
1186/// This type is suitable for scenarios where the bi-predicate needs
1187/// to be shared across threads. Composition methods borrow `&self`,
1188/// allowing the original bi-predicate to remain usable after
1189/// composition.
1190///
1191/// # Examples
1192///
1193/// ```rust
1194/// use prism3_function::bi_predicate::{BiPredicate, ArcBiPredicate};
1195///
1196/// let pred = ArcBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
1197/// assert!(pred.test(&5, &3));
1198///
1199/// // Original bi-predicate remains usable after composition
1200/// let combined = pred.and(ArcBiPredicate::new(|x, y| x > y));
1201/// assert!(pred.test(&5, &3)); // Still works
1202///
1203/// // Can be cloned and sent across threads
1204/// let pred_clone = pred.clone();
1205/// std::thread::spawn(move || {
1206/// assert!(pred_clone.test(&10, &5));
1207/// }).join().unwrap();
1208/// ```
1209///
1210/// # Author
1211///
1212/// Haixing Hu
1213pub struct ArcBiPredicate<T, U> {
1214 function: Arc<SendSyncBiPredicateFn<T, U>>,
1215 name: Option<String>,
1216}
1217
1218impl<T, U> ArcBiPredicate<T, U> {
1219 /// Creates a new `ArcBiPredicate` from a closure.
1220 ///
1221 /// # Parameters
1222 ///
1223 /// * `f` - The closure to wrap.
1224 ///
1225 /// # Returns
1226 ///
1227 /// A new `ArcBiPredicate` instance.
1228 pub fn new<F>(f: F) -> Self
1229 where
1230 F: Fn(&T, &U) -> bool + Send + Sync + 'static,
1231 {
1232 Self {
1233 function: Arc::new(f),
1234 name: None,
1235 }
1236 }
1237
1238 /// Creates a named `ArcBiPredicate` from a closure.
1239 ///
1240 /// # Parameters
1241 ///
1242 /// * `name` - The name for this bi-predicate.
1243 /// * `f` - The closure to wrap.
1244 ///
1245 /// # Returns
1246 ///
1247 /// A new named `ArcBiPredicate` instance.
1248 pub fn new_with_name<F>(name: &str, f: F) -> Self
1249 where
1250 F: Fn(&T, &U) -> bool + Send + Sync + 'static,
1251 {
1252 Self {
1253 function: Arc::new(f),
1254 name: Some(name.to_string()),
1255 }
1256 }
1257
1258 /// Creates a bi-predicate that always returns `true`.
1259 ///
1260 /// # Returns
1261 ///
1262 /// A new `ArcBiPredicate` that always returns `true`.
1263 ///
1264 /// # Examples
1265 ///
1266 /// ```rust
1267 /// use prism3_function::bi_predicate::{BiPredicate, ArcBiPredicate};
1268 ///
1269 /// let pred: ArcBiPredicate<i32, i32> = ArcBiPredicate::always_true();
1270 /// assert!(pred.test(&42, &10));
1271 /// assert!(pred.test(&-1, &5));
1272 /// assert!(pred.test(&0, &0));
1273 /// ```
1274 pub fn always_true() -> Self {
1275 Self {
1276 function: Arc::new(|_, _| true),
1277 name: Some(ALWAYS_TRUE_NAME.to_string()),
1278 }
1279 }
1280
1281 /// Creates a bi-predicate that always returns `false`.
1282 ///
1283 /// # Returns
1284 ///
1285 /// A new `ArcBiPredicate` that always returns `false`.
1286 ///
1287 /// # Examples
1288 ///
1289 /// ```rust
1290 /// use prism3_function::bi_predicate::{BiPredicate, ArcBiPredicate};
1291 ///
1292 /// let pred: ArcBiPredicate<i32, i32> = ArcBiPredicate::always_false();
1293 /// assert!(!pred.test(&42, &10));
1294 /// assert!(!pred.test(&-1, &5));
1295 /// assert!(!pred.test(&0, &0));
1296 /// ```
1297 pub fn always_false() -> Self {
1298 Self {
1299 function: Arc::new(|_, _| false),
1300 name: Some(ALWAYS_FALSE_NAME.to_string()),
1301 }
1302 }
1303
1304 /// Returns the name of this bi-predicate, if set.
1305 ///
1306 /// # Returns
1307 ///
1308 /// An `Option` containing the bi-predicate's name.
1309 pub fn name(&self) -> Option<&str> {
1310 self.name.as_deref()
1311 }
1312
1313 /// Sets the name of this bi-predicate.
1314 ///
1315 /// # Parameters
1316 ///
1317 /// * `name` - The new name for this bi-predicate.
1318 pub fn set_name(&mut self, name: &str) {
1319 self.name = Some(name.to_string());
1320 }
1321
1322 /// Returns a bi-predicate that represents the logical AND of this
1323 /// bi-predicate and another.
1324 ///
1325 /// # Parameters
1326 ///
1327 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1328 /// is passed by value and will transfer ownership.** If you need to
1329 /// preserve the original bi-predicate, clone it first (if it implements
1330 /// `Clone`). Can be:
1331 /// - A closure: `|x: &T, y: &U| -> bool`
1332 /// - A function pointer: `fn(&T, &U) -> bool`
1333 /// - A `BoxBiPredicate<T, U>`
1334 /// - An `RcBiPredicate<T, U>`
1335 /// - Another `ArcBiPredicate<T, U>` (will be moved)
1336 /// - Any type implementing `BiPredicate<T, U> + Send + Sync`
1337 ///
1338 /// # Returns
1339 ///
1340 /// A new `ArcBiPredicate` representing the logical AND.
1341 pub fn and<P>(&self, other: P) -> ArcBiPredicate<T, U>
1342 where
1343 T: Send + Sync + 'static,
1344 U: Send + Sync + 'static,
1345 P: BiPredicate<T, U> + Send + Sync + 'static,
1346 {
1347 let self_fn = Arc::clone(&self.function);
1348 ArcBiPredicate {
1349 function: Arc::new(move |first: &T, second: &U| {
1350 self_fn(first, second) && other.test(first, second)
1351 }),
1352 name: None,
1353 }
1354 }
1355
1356 /// Returns a bi-predicate that represents the logical OR of this
1357 /// bi-predicate and another.
1358 ///
1359 /// # Parameters
1360 ///
1361 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1362 /// is passed by value and will transfer ownership.** If you need to
1363 /// preserve the original bi-predicate, clone it first (if it implements
1364 /// `Clone`). Can be:
1365 /// - A closure: `|x: &T, y: &U| -> bool`
1366 /// - A function pointer: `fn(&T, &U) -> bool`
1367 /// - A `BoxBiPredicate<T, U>`
1368 /// - An `RcBiPredicate<T, U>`
1369 /// - Another `ArcBiPredicate<T, U>` (will be moved)
1370 /// - Any type implementing `BiPredicate<T, U> + Send + Sync`
1371 ///
1372 /// # Returns
1373 ///
1374 /// A new `ArcBiPredicate` representing the logical OR.
1375 /// Thread-safe.
1376 pub fn or<P>(&self, other: P) -> ArcBiPredicate<T, U>
1377 where
1378 T: Send + Sync + 'static,
1379 U: Send + Sync + 'static,
1380 P: BiPredicate<T, U> + Send + Sync + 'static,
1381 {
1382 let self_fn = Arc::clone(&self.function);
1383 ArcBiPredicate {
1384 function: Arc::new(move |first: &T, second: &U| {
1385 self_fn(first, second) || other.test(first, second)
1386 }),
1387 name: None,
1388 }
1389 }
1390
1391 /// Returns a bi-predicate that represents the logical negation of
1392 /// this bi-predicate.
1393 ///
1394 /// # Returns
1395 ///
1396 /// A new `ArcBiPredicate` representing the logical negation.
1397 #[allow(clippy::should_implement_trait)]
1398 pub fn not(&self) -> ArcBiPredicate<T, U>
1399 where
1400 T: Send + Sync + 'static,
1401 U: Send + Sync + 'static,
1402 {
1403 let self_fn = Arc::clone(&self.function);
1404 ArcBiPredicate {
1405 function: Arc::new(move |first: &T, second: &U| !self_fn(first, second)),
1406 name: None,
1407 }
1408 }
1409
1410 /// Returns a bi-predicate that represents the logical NAND (NOT
1411 /// AND) of this bi-predicate and another.
1412 ///
1413 /// NAND returns `true` unless both bi-predicates are `true`.
1414 /// Equivalent to `!(self AND other)`.
1415 ///
1416 /// # Parameters
1417 ///
1418 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1419 /// is passed by value and will transfer ownership.** If you need to
1420 /// preserve the original bi-predicate, clone it first (if it implements
1421 /// `Clone`). Can be:
1422 /// - A closure: `|x: &T, y: &U| -> bool`
1423 /// - A function pointer: `fn(&T, &U) -> bool`
1424 /// - A `BoxBiPredicate<T, U>`
1425 /// - An `RcBiPredicate<T, U>`
1426 /// - Another `ArcBiPredicate<T, U>` (will be moved)
1427 /// - Any type implementing `BiPredicate<T, U> + Send + Sync`
1428 ///
1429 /// # Returns
1430 ///
1431 /// A new `ArcBiPredicate` representing the logical NAND.
1432 /// Thread-safe.
1433 pub fn nand<P>(&self, other: P) -> ArcBiPredicate<T, U>
1434 where
1435 T: Send + Sync + 'static,
1436 U: Send + Sync + 'static,
1437 P: BiPredicate<T, U> + Send + Sync + 'static,
1438 {
1439 let self_fn = Arc::clone(&self.function);
1440 ArcBiPredicate {
1441 function: Arc::new(move |first: &T, second: &U| {
1442 !(self_fn(first, second) && other.test(first, second))
1443 }),
1444 name: None,
1445 }
1446 }
1447
1448 /// Returns a bi-predicate that represents the logical XOR
1449 /// (exclusive OR) of this bi-predicate and another.
1450 ///
1451 /// XOR returns `true` if exactly one of the bi-predicates is
1452 /// `true`.
1453 ///
1454 /// # Parameters
1455 ///
1456 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1457 /// is passed by value and will transfer ownership.** If you need to
1458 /// preserve the original bi-predicate, clone it first (if it implements
1459 /// `Clone`). Can be:
1460 /// - A closure: `|x: &T, y: &U| -> bool`
1461 /// - A function pointer: `fn(&T, &U) -> bool`
1462 /// - A `BoxBiPredicate<T, U>`
1463 /// - An `RcBiPredicate<T, U>`
1464 /// - Another `ArcBiPredicate<T, U>` (will be moved)
1465 /// - Any type implementing `BiPredicate<T, U> + Send + Sync`
1466 ///
1467 /// # Returns
1468 ///
1469 /// A new `ArcBiPredicate` representing the logical XOR.
1470 pub fn xor<P>(&self, other: P) -> ArcBiPredicate<T, U>
1471 where
1472 T: Send + Sync + 'static,
1473 U: Send + Sync + 'static,
1474 P: BiPredicate<T, U> + Send + Sync + 'static,
1475 {
1476 let self_fn = Arc::clone(&self.function);
1477 ArcBiPredicate {
1478 function: Arc::new(move |first: &T, second: &U| {
1479 self_fn(first, second) ^ other.test(first, second)
1480 }),
1481 name: None,
1482 }
1483 }
1484
1485 /// Returns a bi-predicate that represents the logical NOR (NOT
1486 /// OR) of this bi-predicate and another.
1487 ///
1488 /// NOR returns `true` only if both bi-predicates are `false`.
1489 /// Equivalent to `!(self OR other)`.
1490 ///
1491 /// # Parameters
1492 ///
1493 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1494 /// is passed by value and will transfer ownership.** If you need to
1495 /// preserve the original bi-predicate, clone it first (if it implements
1496 /// `Clone`). Can be:
1497 /// - A closure: `|x: &T, y: &U| -> bool`
1498 /// - A function pointer: `fn(&T, &U) -> bool`
1499 /// - A `BoxBiPredicate<T, U>`
1500 /// - An `RcBiPredicate<T, U>`
1501 /// - Another `ArcBiPredicate<T, U>` (will be moved)
1502 /// - Any type implementing `BiPredicate<T, U> + Send + Sync`
1503 ///
1504 /// # Returns
1505 ///
1506 /// A new `ArcBiPredicate` representing the logical NOR.
1507 /// Thread-safe.
1508 pub fn nor<P>(&self, other: P) -> ArcBiPredicate<T, U>
1509 where
1510 T: Send + Sync + 'static,
1511 U: Send + Sync + 'static,
1512 P: BiPredicate<T, U> + Send + Sync + 'static,
1513 {
1514 let self_fn = Arc::clone(&self.function);
1515 ArcBiPredicate {
1516 function: Arc::new(move |first: &T, second: &U| {
1517 !(self_fn(first, second) || other.test(first, second))
1518 }),
1519 name: None,
1520 }
1521 }
1522
1523 /// Converts this bi-predicate to a `BoxBiPredicate`.
1524 ///
1525 /// # Returns
1526 ///
1527 /// A `BoxBiPredicate` wrapping this bi-predicate.
1528 pub fn to_box(&self) -> BoxBiPredicate<T, U>
1529 where
1530 T: 'static,
1531 U: 'static,
1532 {
1533 let self_fn = Arc::clone(&self.function);
1534 BoxBiPredicate {
1535 function: Box::new(move |first: &T, second: &U| self_fn(first, second)),
1536 name: self.name.clone(),
1537 }
1538 }
1539
1540 /// Converts this bi-predicate to an `RcBiPredicate`.
1541 ///
1542 /// # Returns
1543 ///
1544 /// An `RcBiPredicate` wrapping this bi-predicate.
1545 pub fn to_rc(&self) -> RcBiPredicate<T, U>
1546 where
1547 T: 'static,
1548 U: 'static,
1549 {
1550 let self_fn = Arc::clone(&self.function);
1551 RcBiPredicate {
1552 function: Rc::new(move |first: &T, second: &U| self_fn(first, second)),
1553 name: self.name.clone(),
1554 }
1555 }
1556
1557 /// Converts this bi-predicate to a closure that can be used
1558 /// directly with standard library methods.
1559 ///
1560 /// This method creates a new closure without consuming the
1561 /// original bi-predicate, since `ArcBiPredicate` uses shared
1562 /// ownership. The returned closure has signature
1563 /// `Fn(&T, &U) -> bool + Send + Sync` and is thread-safe.
1564 ///
1565 /// # Returns
1566 ///
1567 /// A closure implementing `Fn(&T, &U) -> bool + Send + Sync`.
1568 pub fn to_fn(&self) -> impl Fn(&T, &U) -> bool + Send + Sync
1569 where
1570 T: Send + Sync + 'static,
1571 U: Send + Sync + 'static,
1572 {
1573 let self_fn = Arc::clone(&self.function);
1574 move |first: &T, second: &U| self_fn(first, second)
1575 }
1576}
1577
1578impl<T, U> BiPredicate<T, U> for ArcBiPredicate<T, U> {
1579 fn test(&self, first: &T, second: &U) -> bool {
1580 (self.function)(first, second)
1581 }
1582
1583 fn into_box(self) -> BoxBiPredicate<T, U>
1584 where
1585 T: 'static,
1586 U: 'static,
1587 {
1588 let name = self.name.clone();
1589 BoxBiPredicate {
1590 function: Box::new(move |first, second| self.test(first, second)),
1591 name,
1592 }
1593 }
1594
1595 fn into_rc(self) -> RcBiPredicate<T, U>
1596 where
1597 T: 'static,
1598 U: 'static,
1599 {
1600 let name = self.name.clone();
1601 RcBiPredicate {
1602 function: Rc::new(move |first, second| self.test(first, second)),
1603 name,
1604 }
1605 }
1606
1607 fn into_arc(self) -> ArcBiPredicate<T, U>
1608 where
1609 T: Send + Sync + 'static,
1610 U: Send + Sync + 'static,
1611 {
1612 self
1613 }
1614
1615 fn into_fn(self) -> impl Fn(&T, &U) -> bool
1616 where
1617 Self: Sized + 'static,
1618 T: 'static,
1619 U: 'static,
1620 {
1621 let self_fn = self.function;
1622 move |first: &T, second: &U| self_fn(first, second)
1623 }
1624}
1625
1626impl<T, U> Clone for ArcBiPredicate<T, U> {
1627 /// Clones this bi-predicate.
1628 ///
1629 /// Creates a new instance that shares the underlying function with
1630 /// the original, allowing multiple references to the same
1631 /// bi-predicate logic.
1632 fn clone(&self) -> Self {
1633 Self {
1634 function: Arc::clone(&self.function),
1635 name: self.name.clone(),
1636 }
1637 }
1638}
1639
1640impl<T, U> Display for ArcBiPredicate<T, U> {
1641 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1642 write!(
1643 f,
1644 "ArcBiPredicate({})",
1645 self.name.as_deref().unwrap_or("unnamed")
1646 )
1647 }
1648}
1649
1650impl<T, U> Debug for ArcBiPredicate<T, U> {
1651 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1652 f.debug_struct("ArcBiPredicate")
1653 .field("name", &self.name)
1654 .finish()
1655 }
1656}
1657
1658// Blanket implementation for all closures that match Fn(&T, &U) -> bool
1659impl<T: 'static, U: 'static, F> BiPredicate<T, U> for F
1660where
1661 F: Fn(&T, &U) -> bool + 'static,
1662{
1663 fn test(&self, first: &T, second: &U) -> bool {
1664 self(first, second)
1665 }
1666
1667 fn into_box(self) -> BoxBiPredicate<T, U> {
1668 BoxBiPredicate::new(self)
1669 }
1670
1671 fn into_rc(self) -> RcBiPredicate<T, U> {
1672 RcBiPredicate::new(self)
1673 }
1674
1675 fn into_arc(self) -> ArcBiPredicate<T, U>
1676 where
1677 Self: Send + Sync,
1678 T: Send + Sync,
1679 U: Send + Sync,
1680 {
1681 ArcBiPredicate::new(self)
1682 }
1683
1684 fn into_fn(self) -> impl Fn(&T, &U) -> bool {
1685 self
1686 }
1687}
1688
1689/// Extension trait providing logical composition methods for closures.
1690///
1691/// This trait is automatically implemented for all closures and
1692/// function pointers that match `Fn(&T, &U) -> bool`, enabling method
1693/// chaining starting from a closure.
1694///
1695/// # Examples
1696///
1697/// ```rust
1698/// use prism3_function::bi_predicate::{BiPredicate, FnBiPredicateOps};
1699///
1700/// let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
1701/// let first_larger = |x: &i32, y: &i32| x > y;
1702///
1703/// // Combine bi-predicates using extension methods
1704/// let pred = is_sum_positive.and(first_larger);
1705/// assert!(pred.test(&10, &5));
1706/// assert!(!pred.test(&3, &8));
1707/// ```
1708///
1709/// # Author
1710///
1711/// Haixing Hu
1712pub trait FnBiPredicateOps<T, U>: Fn(&T, &U) -> bool + Sized + 'static {
1713 /// Returns a bi-predicate that represents the logical AND of this
1714 /// bi-predicate and another.
1715 ///
1716 /// # Parameters
1717 ///
1718 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1719 /// is passed by value and will transfer ownership.** If you need to
1720 /// preserve the original bi-predicate, clone it first (if it implements
1721 /// `Clone`). Can be:
1722 /// - Another closure: `|x: &T, y: &U| -> bool`
1723 /// - A function pointer: `fn(&T, &U) -> bool`
1724 /// - A `BoxBiPredicate<T, U>`
1725 /// - An `RcBiPredicate<T, U>`
1726 /// - An `ArcBiPredicate<T, U>`
1727 /// - Any type implementing `BiPredicate<T, U>`
1728 ///
1729 /// # Returns
1730 ///
1731 /// A `BoxBiPredicate` representing the logical AND.
1732 fn and<P>(self, other: P) -> BoxBiPredicate<T, U>
1733 where
1734 P: BiPredicate<T, U> + 'static,
1735 T: 'static,
1736 U: 'static,
1737 {
1738 BoxBiPredicate::new(move |first, second| self(first, second) && other.test(first, second))
1739 }
1740
1741 /// Returns a bi-predicate that represents the logical OR of this
1742 /// bi-predicate and another.
1743 ///
1744 /// # Parameters
1745 ///
1746 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1747 /// is passed by value and will transfer ownership.** If you need to
1748 /// preserve the original bi-predicate, clone it first (if it implements
1749 /// `Clone`). Can be:
1750 /// - Another closure: `|x: &T, y: &U| -> bool`
1751 /// - A function pointer: `fn(&T, &U) -> bool`
1752 /// - A `BoxBiPredicate<T, U>`
1753 /// - An `RcBiPredicate<T, U>`
1754 /// - An `ArcBiPredicate<T, U>`
1755 /// - Any type implementing `BiPredicate<T, U>`
1756 ///
1757 /// # Returns
1758 ///
1759 /// A `BoxBiPredicate` representing the logical OR.
1760 fn or<P>(self, other: P) -> BoxBiPredicate<T, U>
1761 where
1762 P: BiPredicate<T, U> + 'static,
1763 T: 'static,
1764 U: 'static,
1765 {
1766 BoxBiPredicate::new(move |first, second| self(first, second) || other.test(first, second))
1767 }
1768
1769 /// Returns a bi-predicate that represents the logical negation of
1770 /// this bi-predicate.
1771 ///
1772 /// # Returns
1773 ///
1774 /// A `BoxBiPredicate` representing the logical negation.
1775 fn not(self) -> BoxBiPredicate<T, U>
1776 where
1777 T: 'static,
1778 U: 'static,
1779 {
1780 BoxBiPredicate::new(move |first, second| !self(first, second))
1781 }
1782
1783 /// Returns a bi-predicate that represents the logical NAND (NOT
1784 /// AND) of this bi-predicate and another.
1785 ///
1786 /// NAND returns `true` unless both bi-predicates are `true`.
1787 /// Equivalent to `!(self AND other)`.
1788 ///
1789 /// # Parameters
1790 ///
1791 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1792 /// is passed by value and will transfer ownership.** If you need to
1793 /// preserve the original bi-predicate, clone it first (if it implements
1794 /// `Clone`). Can be:
1795 /// - Another closure: `|x: &T, y: &U| -> bool`
1796 /// - A function pointer: `fn(&T, &U) -> bool`
1797 /// - A `BoxBiPredicate<T, U>`
1798 /// - An `RcBiPredicate<T, U>`
1799 /// - An `ArcBiPredicate<T, U>`
1800 /// - Any type implementing `BiPredicate<T, U>`
1801 ///
1802 /// # Returns
1803 ///
1804 /// A `BoxBiPredicate` representing the logical NAND.
1805 fn nand<P>(self, other: P) -> BoxBiPredicate<T, U>
1806 where
1807 P: BiPredicate<T, U> + 'static,
1808 T: 'static,
1809 U: 'static,
1810 {
1811 BoxBiPredicate::new(move |first, second| {
1812 !(self(first, second) && other.test(first, second))
1813 })
1814 }
1815
1816 /// Returns a bi-predicate that represents the logical XOR
1817 /// (exclusive OR) of this bi-predicate and another.
1818 ///
1819 /// XOR returns `true` if exactly one of the bi-predicates is
1820 /// `true`.
1821 ///
1822 /// # Parameters
1823 ///
1824 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1825 /// is passed by value and will transfer ownership.** If you need to
1826 /// preserve the original bi-predicate, clone it first (if it implements
1827 /// `Clone`). Can be:
1828 /// - Another closure: `|x: &T, y: &U| -> bool`
1829 /// - A function pointer: `fn(&T, &U) -> bool`
1830 /// - A `BoxBiPredicate<T, U>`
1831 /// - An `RcBiPredicate<T, U>`
1832 /// - An `ArcBiPredicate<T, U>`
1833 /// - Any type implementing `BiPredicate<T, U>`
1834 ///
1835 /// # Returns
1836 ///
1837 /// A `BoxBiPredicate` representing the logical XOR.
1838 fn xor<P>(self, other: P) -> BoxBiPredicate<T, U>
1839 where
1840 P: BiPredicate<T, U> + 'static,
1841 T: 'static,
1842 U: 'static,
1843 {
1844 BoxBiPredicate::new(move |first, second| self(first, second) ^ other.test(first, second))
1845 }
1846
1847 /// Returns a bi-predicate that represents the logical NOR (NOT
1848 /// OR) of this bi-predicate and another.
1849 ///
1850 /// NOR returns `true` only if both bi-predicates are `false`.
1851 /// Equivalent to `!(self OR other)`.
1852 ///
1853 /// # Parameters
1854 ///
1855 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
1856 /// is passed by value and will transfer ownership.** If you need to
1857 /// preserve the original bi-predicate, clone it first (if it implements
1858 /// `Clone`). Can be:
1859 /// - Another closure: `|x: &T, y: &U| -> bool`
1860 /// - A function pointer: `fn(&T, &U) -> bool`
1861 /// - A `BoxBiPredicate<T, U>`
1862 /// - An `RcBiPredicate<T, U>`
1863 /// - An `ArcBiPredicate<T, U>`
1864 /// - Any type implementing `BiPredicate<T, U>`
1865 ///
1866 /// # Returns
1867 ///
1868 /// A `BoxBiPredicate` representing the logical NOR.
1869 fn nor<P>(self, other: P) -> BoxBiPredicate<T, U>
1870 where
1871 P: BiPredicate<T, U> + 'static,
1872 T: 'static,
1873 U: 'static,
1874 {
1875 BoxBiPredicate::new(move |first, second| {
1876 !(self(first, second) || other.test(first, second))
1877 })
1878 }
1879}
1880
1881// Blanket implementation for all closures
1882impl<T, U, F> FnBiPredicateOps<T, U> for F where F: Fn(&T, &U) -> bool + 'static {}