prism3_function/comparator.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025.
4 * 3-Prism Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # Comparator Abstraction
10//!
11//! Provides a Rust implementation similar to Java's `Comparator` interface
12//! for comparison operations and chaining.
13//!
14//! ## Design Overview
15//!
16//! This module adopts the **Trait + Multiple Implementations** design
17//! pattern, which is the most flexible and elegant approach for
18//! implementing comparators in Rust. It achieves a perfect balance
19//! between semantic clarity, type safety, and API flexibility.
20//!
21//! ### Core Components
22//!
23//! 1. **`Comparator<T>` trait**: A minimalist unified interface that only
24//! defines the core `compare` method and type conversion methods
25//! (`into_*`). It does NOT include chaining methods like
26//! `then_comparing`, etc.
27//!
28//! 2. **Three Concrete Struct Implementations**:
29//! - [`BoxComparator<T>`]: Box-based single ownership implementation
30//! for one-time use scenarios
31//! - [`ArcComparator<T>`]: Arc-based thread-safe shared ownership
32//! implementation for multi-threaded scenarios
33//! - [`RcComparator<T>`]: Rc-based single-threaded shared ownership
34//! implementation for single-threaded reuse
35//!
36//! 3. **Specialized Composition Methods**: Each struct implements its own
37//! inherent methods (`reversed`, `then_comparing`, etc.) that return
38//! the same concrete type, preserving their specific characteristics
39//! (e.g., `ArcComparator` compositions remain `ArcComparator` and stay
40//! cloneable and thread-safe).
41//!
42//! 4. **Extension Trait for Closures**: The `FnComparatorOps<T>`
43//! extension trait provides composition methods for all closures and
44//! function pointers, returning `BoxComparator<T>` to initiate method
45//! chaining.
46//!
47//! 5. **Unified Trait Implementation**: All closures and the three
48//! structs implement the `Comparator<T>` trait, enabling them to be
49//! handled uniformly by generic functions.
50//!
51//! ## Ownership Model Coverage
52//!
53//! The three implementations correspond to three typical ownership
54//! scenarios:
55//!
56//! | Type | Ownership | Clonable | Thread-Safe | API | Use Case |
57//! |:-----|:----------|:---------|:------------|:----|:---------|
58//! | [`BoxComparator`] | Single | ❌ | ❌ | consumes `self` | One-time |
59//! | [`ArcComparator`] | Shared | ✅ | ✅ | borrows `&self` | Multi-thread |
60//! | [`RcComparator`] | Shared | ✅ | ❌ | borrows `&self` | Single-thread |
61//!
62//! ## Key Design Advantages
63//!
64//! ### 1. Type Preservation through Specialization
65//!
66//! By implementing composition methods on concrete structs rather than in
67//! the trait, each type maintains its specific characteristics through
68//! composition:
69//!
70//! ```rust
71//! use prism3_function::comparator::{Comparator, ArcComparator};
72//! use std::cmp::Ordering;
73//!
74//! let arc_cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
75//! let another = ArcComparator::new(|a: &i32, b: &i32| b.cmp(a));
76//!
77//! // Composition returns ArcComparator, preserving clonability and
78//! // thread-safety
79//! let combined = arc_cmp.then_comparing(&another);
80//! let cloned = combined.clone(); // ✅ Still cloneable
81//!
82//! // Original comparators remain usable
83//! assert_eq!(arc_cmp.compare(&5, &3), Ordering::Greater);
84//! ```
85//!
86//! ### 2. Elegant API without Explicit Cloning
87//!
88//! `ArcComparator` and `RcComparator` use `&self` in their composition
89//! methods, providing a natural experience without requiring explicit
90//! `.clone()` calls:
91//!
92//! ```rust
93//! use prism3_function::comparator::{Comparator, ArcComparator};
94//!
95//! let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
96//!
97//! // No need for explicit clone()
98//! let reversed = cmp.reversed();
99//! let chained = cmp.then_comparing(&ArcComparator::new(|a, b| b.cmp(a)));
100//!
101//! // cmp is still available
102//! cmp.compare(&1, &2);
103//! ```
104//!
105//! ### 3. Efficient Closure Composition
106//!
107//! The `FnComparatorOps` extension trait allows direct composition on
108//! closures:
109//!
110//! ```rust
111//! use prism3_function::comparator::{Comparator, FnComparatorOps};
112//! use std::cmp::Ordering;
113//!
114//! let cmp = (|a: &i32, b: &i32| a.cmp(b))
115//! .reversed()
116//! .then_comparing(|a: &i32, b: &i32| b.cmp(a));
117//!
118//! assert_eq!(cmp.compare(&5, &3), Ordering::Less);
119//! ```
120//!
121//! ## Usage Examples
122//!
123//! ### Basic Comparison
124//!
125//! ```rust
126//! use prism3_function::comparator::{Comparator, BoxComparator};
127//! use std::cmp::Ordering;
128//!
129//! let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
130//! assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
131//! ```
132//!
133//! ### Reversed Comparison
134//!
135//! ```rust
136//! use prism3_function::comparator::{Comparator, BoxComparator};
137//! use std::cmp::Ordering;
138//!
139//! let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
140//! let rev = cmp.reversed();
141//! assert_eq!(rev.compare(&5, &3), Ordering::Less);
142//! ```
143//!
144//! ### Chained Comparison
145//!
146//! ```rust
147//! use prism3_function::comparator::{Comparator, BoxComparator};
148//! use std::cmp::Ordering;
149//!
150//! #[derive(Debug)]
151//! struct Person {
152//! name: String,
153//! age: i32,
154//! }
155//!
156//! let by_name = BoxComparator::new(|a: &Person, b: &Person| {
157//! a.name.cmp(&b.name)
158//! });
159//! let by_age = BoxComparator::new(|a: &Person, b: &Person| {
160//! a.age.cmp(&b.age)
161//! });
162//! let cmp = by_name.then_comparing(by_age);
163//!
164//! let p1 = Person { name: "Alice".to_string(), age: 30 };
165//! let p2 = Person { name: "Alice".to_string(), age: 25 };
166//! assert_eq!(cmp.compare(&p1, &p2), Ordering::Greater);
167//! ```
168//!
169//! ## Author
170//!
171//! Haixing Hu
172use std::cmp::Ordering;
173use std::rc::Rc;
174use std::sync::Arc;
175
176// ==========================================================================
177// Type Aliases
178// ==========================================================================
179
180/// A trait for comparison operations.
181///
182/// This trait defines the core comparison operation and conversion methods.
183/// It does NOT include composition methods like `reversed` or
184/// `then_comparing` to maintain a clean separation between the trait
185/// interface and specialized implementations.
186///
187/// # Type Parameters
188///
189/// * `T` - The type of values being compared
190///
191/// # Examples
192///
193/// ```rust
194/// use prism3_function::comparator::{Comparator, BoxComparator};
195/// use std::cmp::Ordering;
196///
197/// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
198/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
199/// ```
200///
201/// # Author
202///
203/// Haixing Hu
204pub trait Comparator<T> {
205 /// Compares two values and returns an ordering.
206 ///
207 /// # Parameters
208 ///
209 /// * `a` - The first value to compare
210 /// * `b` - The second value to compare
211 ///
212 /// # Returns
213 ///
214 /// An `Ordering` indicating whether `a` is less than, equal to, or
215 /// greater than `b`.
216 ///
217 /// # Examples
218 ///
219 /// ```rust
220 /// use prism3_function::comparator::{Comparator, BoxComparator};
221 /// use std::cmp::Ordering;
222 ///
223 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
224 /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
225 /// assert_eq!(cmp.compare(&3, &5), Ordering::Less);
226 /// assert_eq!(cmp.compare(&5, &5), Ordering::Equal);
227 /// ```
228 fn compare(&self, a: &T, b: &T) -> Ordering;
229
230 /// Converts this comparator into a `BoxComparator`.
231 ///
232 /// # Returns
233 ///
234 /// A new `BoxComparator` wrapping this comparator.
235 ///
236 /// # Examples
237 ///
238 /// ```rust
239 /// use prism3_function::comparator::{Comparator, BoxComparator};
240 ///
241 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
242 /// let boxed = cmp.into_box();
243 /// ```
244 fn into_box(self) -> BoxComparator<T>
245 where
246 Self: Sized + 'static,
247 T: 'static,
248 {
249 BoxComparator::new(move |a, b| self.compare(a, b))
250 }
251
252 /// Converts this comparator into an `ArcComparator`.
253 ///
254 /// # Returns
255 ///
256 /// A new `ArcComparator` wrapping this comparator.
257 ///
258 /// # Examples
259 ///
260 /// ```rust
261 /// use prism3_function::comparator::{Comparator, ArcComparator};
262 ///
263 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
264 /// let arc = cmp.into_arc();
265 /// ```
266 fn into_arc(self) -> ArcComparator<T>
267 where
268 Self: Sized + Send + Sync + 'static,
269 T: 'static,
270 {
271 ArcComparator::new(move |a, b| self.compare(a, b))
272 }
273
274 /// Converts this comparator into an `RcComparator`.
275 ///
276 /// # Returns
277 ///
278 /// A new `RcComparator` wrapping this comparator.
279 ///
280 /// # Examples
281 ///
282 /// ```rust
283 /// use prism3_function::comparator::{Comparator, RcComparator};
284 ///
285 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
286 /// let rc = cmp.into_rc();
287 /// ```
288 fn into_rc(self) -> RcComparator<T>
289 where
290 Self: Sized + 'static,
291 T: 'static,
292 {
293 RcComparator::new(move |a, b| self.compare(a, b))
294 }
295
296 /// Converts this comparator into a closure that implements
297 /// `Fn(&T, &T) -> Ordering`.
298 ///
299 /// This method consumes the comparator and returns a closure that
300 /// can be used anywhere a function or closure is expected.
301 ///
302 /// # Returns
303 ///
304 /// An implementation that can be called as `Fn(&T, &T) -> Ordering`.
305 ///
306 /// # Examples
307 ///
308 /// ```rust
309 /// use prism3_function::comparator::{Comparator, BoxComparator};
310 /// use std::cmp::Ordering;
311 ///
312 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
313 /// let func = cmp.into_fn();
314 /// assert_eq!(func(&5, &3), Ordering::Greater);
315 /// ```
316 fn into_fn(self) -> impl Fn(&T, &T) -> Ordering
317 where
318 Self: Sized + 'static,
319 T: 'static,
320 {
321 move |a: &T, b: &T| self.compare(a, b)
322 }
323}
324
325/// Blanket implementation of `Comparator` for all closures and function
326/// pointers.
327///
328/// This allows any closure or function with the signature
329/// `Fn(&T, &T) -> Ordering` to be used as a comparator.
330///
331/// # Examples
332///
333/// ```rust
334/// use prism3_function::comparator::Comparator;
335/// use std::cmp::Ordering;
336///
337/// let cmp = |a: &i32, b: &i32| a.cmp(b);
338/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
339/// ```
340impl<T, F> Comparator<T> for F
341where
342 F: Fn(&T, &T) -> Ordering,
343{
344 fn compare(&self, a: &T, b: &T) -> Ordering {
345 self(a, b)
346 }
347}
348
349/// A boxed comparator with single ownership.
350///
351/// `BoxComparator` wraps a comparator function in a `Box`, providing single
352/// ownership semantics. It is not cloneable and consumes `self` in
353/// composition operations.
354///
355/// # Type Parameters
356///
357/// * `T` - The type of values being compared
358///
359/// # Examples
360///
361/// ```rust
362/// use prism3_function::comparator::{Comparator, BoxComparator};
363/// use std::cmp::Ordering;
364///
365/// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
366/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
367/// ```
368///
369/// # Author
370///
371/// Haixing Hu
372pub struct BoxComparator<T> {
373 function: Box<dyn Fn(&T, &T) -> Ordering>,
374}
375
376impl<T: 'static> BoxComparator<T> {
377 /// Creates a new `BoxComparator` from a closure.
378 ///
379 /// # Parameters
380 ///
381 /// * `f` - The closure to wrap
382 ///
383 /// # Returns
384 ///
385 /// A new `BoxComparator` instance.
386 ///
387 /// # Examples
388 ///
389 /// ```rust
390 /// use prism3_function::comparator::BoxComparator;
391 ///
392 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
393 /// ```
394 pub fn new<F>(f: F) -> Self
395 where
396 F: Fn(&T, &T) -> Ordering + 'static,
397 {
398 Self {
399 function: Box::new(f),
400 }
401 }
402
403 /// Returns a comparator that imposes the reverse ordering.
404 ///
405 /// # Returns
406 ///
407 /// A new `BoxComparator` that reverses the comparison order.
408 ///
409 /// # Examples
410 ///
411 /// ```rust
412 /// use prism3_function::comparator::{Comparator, BoxComparator};
413 /// use std::cmp::Ordering;
414 ///
415 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
416 /// let rev = cmp.reversed();
417 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
418 /// ```
419 pub fn reversed(self) -> Self {
420 BoxComparator::new(move |a, b| (self.function)(b, a))
421 }
422
423 /// Returns a comparator that uses this comparator first, then another
424 /// comparator if this one considers the values equal.
425 ///
426 /// # Parameters
427 ///
428 /// * `other` - The comparator to use for tie-breaking. **Note: This
429 /// parameter is passed by value and will transfer ownership.** If you
430 /// need to preserve the original comparator, clone it first (if it
431 /// implements `Clone`). Can be:
432 /// - A `BoxComparator<T>`
433 /// - An `RcComparator<T>`
434 /// - An `ArcComparator<T>`
435 /// - Any type implementing `Comparator<T>`
436 ///
437 /// # Returns
438 ///
439 /// A new `BoxComparator` that chains this comparator with another.
440 ///
441 /// # Examples
442 ///
443 /// ```rust
444 /// use prism3_function::comparator::{Comparator, BoxComparator};
445 /// use std::cmp::Ordering;
446 ///
447 /// #[derive(Debug)]
448 /// struct Person {
449 /// name: String,
450 /// age: i32,
451 /// }
452 ///
453 /// let by_name = BoxComparator::new(|a: &Person, b: &Person| {
454 /// a.name.cmp(&b.name)
455 /// });
456 /// let by_age = BoxComparator::new(|a: &Person, b: &Person| {
457 /// a.age.cmp(&b.age)
458 /// });
459 ///
460 /// // by_age is moved here
461 /// let cmp = by_name.then_comparing(by_age);
462 ///
463 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
464 /// let p2 = Person { name: "Alice".to_string(), age: 25 };
465 /// assert_eq!(cmp.compare(&p1, &p2), Ordering::Greater);
466 /// // by_age.compare(&p1, &p2); // Would not compile - moved
467 /// ```
468 pub fn then_comparing(self, other: Self) -> Self {
469 BoxComparator::new(move |a, b| match (self.function)(a, b) {
470 Ordering::Equal => (other.function)(a, b),
471 ord => ord,
472 })
473 }
474
475 /// Returns a comparator that compares values by a key extracted by the
476 /// given function.
477 ///
478 /// # Parameters
479 ///
480 /// * `key_fn` - A function that extracts a comparable key from values
481 ///
482 /// # Returns
483 ///
484 /// A new `BoxComparator` that compares by the extracted key.
485 ///
486 /// # Examples
487 ///
488 /// ```rust
489 /// use prism3_function::comparator::{Comparator, BoxComparator};
490 /// use std::cmp::Ordering;
491 ///
492 /// #[derive(Debug)]
493 /// struct Person {
494 /// name: String,
495 /// age: i32,
496 /// }
497 ///
498 /// let by_age = BoxComparator::comparing(|p: &Person| &p.age);
499 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
500 /// let p2 = Person { name: "Bob".to_string(), age: 25 };
501 /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
502 /// ```
503 pub fn comparing<K, F>(key_fn: F) -> Self
504 where
505 K: Ord,
506 F: Fn(&T) -> &K + 'static,
507 {
508 BoxComparator::new(move |a: &T, b: &T| key_fn(a).cmp(key_fn(b)))
509 }
510
511 /// Converts this comparator into a closure.
512 ///
513 /// # Returns
514 ///
515 /// A closure that implements `Fn(&T, &T) -> Ordering`.
516 ///
517 /// # Examples
518 ///
519 /// ```rust
520 /// use prism3_function::comparator::{Comparator, BoxComparator};
521 /// use std::cmp::Ordering;
522 ///
523 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
524 /// let func = cmp.into_fn();
525 /// assert_eq!(func(&5, &3), Ordering::Greater);
526 /// ```
527 pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
528 move |a: &T, b: &T| (self.function)(a, b)
529 }
530}
531
532impl<T> Comparator<T> for BoxComparator<T> {
533 fn compare(&self, a: &T, b: &T) -> Ordering {
534 (self.function)(a, b)
535 }
536}
537
538/// An Arc-based thread-safe comparator with shared ownership.
539///
540/// `ArcComparator` wraps a comparator function in an `Arc`, providing
541/// thread-safe shared ownership semantics. It is cloneable and uses `&self`
542/// in composition operations.
543///
544/// # Type Parameters
545///
546/// * `T` - The type of values being compared
547///
548/// # Examples
549///
550/// ```rust
551/// use prism3_function::comparator::{Comparator, ArcComparator};
552/// use std::cmp::Ordering;
553///
554/// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
555/// let cloned = cmp.clone();
556/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
557/// assert_eq!(cloned.compare(&5, &3), Ordering::Greater);
558/// ```
559///
560/// # Author
561///
562/// Haixing Hu
563#[derive(Clone)]
564pub struct ArcComparator<T> {
565 function: Arc<dyn Fn(&T, &T) -> Ordering + Send + Sync>,
566}
567
568impl<T: 'static> ArcComparator<T> {
569 /// Creates a new `ArcComparator` from a closure.
570 ///
571 /// # Parameters
572 ///
573 /// * `f` - The closure to wrap
574 ///
575 /// # Returns
576 ///
577 /// A new `ArcComparator` instance.
578 ///
579 /// # Examples
580 ///
581 /// ```rust
582 /// use prism3_function::comparator::ArcComparator;
583 ///
584 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
585 /// ```
586 pub fn new<F>(f: F) -> Self
587 where
588 F: Fn(&T, &T) -> Ordering + Send + Sync + 'static,
589 {
590 Self {
591 function: Arc::new(f),
592 }
593 }
594
595 /// Returns a comparator that imposes the reverse ordering.
596 ///
597 /// # Returns
598 ///
599 /// A new `ArcComparator` that reverses the comparison order.
600 ///
601 /// # Examples
602 ///
603 /// ```rust
604 /// use prism3_function::comparator::{Comparator, ArcComparator};
605 /// use std::cmp::Ordering;
606 ///
607 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
608 /// let rev = cmp.reversed();
609 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
610 /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater); // cmp still works
611 /// ```
612 pub fn reversed(&self) -> Self {
613 let self_fn = self.function.clone();
614 ArcComparator::new(move |a, b| self_fn(b, a))
615 }
616
617 /// Returns a comparator that uses this comparator first, then another
618 /// comparator if this one considers the values equal.
619 ///
620 /// # Parameters
621 ///
622 /// * `other` - The comparator to use for tie-breaking
623 ///
624 /// # Returns
625 ///
626 /// A new `ArcComparator` that chains this comparator with another.
627 ///
628 /// # Examples
629 ///
630 /// ```rust
631 /// use prism3_function::comparator::{Comparator, ArcComparator};
632 /// use std::cmp::Ordering;
633 ///
634 /// let cmp1 = ArcComparator::new(|a: &i32, b: &i32| {
635 /// (a % 2).cmp(&(b % 2))
636 /// });
637 /// let cmp2 = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
638 /// let chained = cmp1.then_comparing(&cmp2);
639 /// assert_eq!(chained.compare(&4, &2), Ordering::Greater);
640 /// ```
641 pub fn then_comparing(&self, other: &Self) -> Self {
642 let first = self.function.clone();
643 let second = other.function.clone();
644 ArcComparator::new(move |a, b| match first(a, b) {
645 Ordering::Equal => second(a, b),
646 ord => ord,
647 })
648 }
649
650 /// Returns a comparator that compares values by a key extracted by the
651 /// given function.
652 ///
653 /// # Parameters
654 ///
655 /// * `key_fn` - A function that extracts a comparable key from values
656 ///
657 /// # Returns
658 ///
659 /// A new `ArcComparator` that compares by the extracted key.
660 ///
661 /// # Examples
662 ///
663 /// ```rust
664 /// use prism3_function::comparator::{Comparator, ArcComparator};
665 /// use std::cmp::Ordering;
666 ///
667 /// #[derive(Debug)]
668 /// struct Person {
669 /// name: String,
670 /// age: i32,
671 /// }
672 ///
673 /// let by_age = ArcComparator::comparing(|p: &Person| &p.age);
674 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
675 /// let p2 = Person { name: "Bob".to_string(), age: 25 };
676 /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
677 /// ```
678 pub fn comparing<K, F>(key_fn: F) -> Self
679 where
680 K: Ord,
681 F: Fn(&T) -> &K + Send + Sync + 'static,
682 {
683 ArcComparator::new(move |a, b| key_fn(a).cmp(key_fn(b)))
684 }
685
686 /// Converts this comparator into a closure.
687 ///
688 /// # Returns
689 ///
690 /// A closure that implements `Fn(&T, &T) -> Ordering`.
691 ///
692 /// # Examples
693 ///
694 /// ```rust
695 /// use prism3_function::comparator::{Comparator, ArcComparator};
696 /// use std::cmp::Ordering;
697 ///
698 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
699 /// let func = cmp.into_fn();
700 /// assert_eq!(func(&5, &3), Ordering::Greater);
701 /// ```
702 pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
703 move |a: &T, b: &T| (self.function)(a, b)
704 }
705}
706
707impl<T> Comparator<T> for ArcComparator<T> {
708 fn compare(&self, a: &T, b: &T) -> Ordering {
709 (self.function)(a, b)
710 }
711}
712
713/// An Rc-based single-threaded comparator with shared ownership.
714///
715/// `RcComparator` wraps a comparator function in an `Rc`, providing
716/// single-threaded shared ownership semantics. It is cloneable and uses
717/// `&self` in composition operations.
718///
719/// # Type Parameters
720///
721/// * `T` - The type of values being compared
722///
723/// # Examples
724///
725/// ```rust
726/// use prism3_function::comparator::{Comparator, RcComparator};
727/// use std::cmp::Ordering;
728///
729/// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
730/// let cloned = cmp.clone();
731/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
732/// assert_eq!(cloned.compare(&5, &3), Ordering::Greater);
733/// ```
734///
735/// # Author
736///
737/// Haixing Hu
738#[derive(Clone)]
739pub struct RcComparator<T> {
740 function: Rc<dyn Fn(&T, &T) -> Ordering>,
741}
742
743impl<T: 'static> RcComparator<T> {
744 /// Creates a new `RcComparator` from a closure.
745 ///
746 /// # Parameters
747 ///
748 /// * `f` - The closure to wrap
749 ///
750 /// # Returns
751 ///
752 /// A new `RcComparator` instance.
753 ///
754 /// # Examples
755 ///
756 /// ```rust
757 /// use prism3_function::comparator::RcComparator;
758 ///
759 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
760 /// ```
761 pub fn new<F>(f: F) -> Self
762 where
763 F: Fn(&T, &T) -> Ordering + 'static,
764 {
765 Self {
766 function: Rc::new(f),
767 }
768 }
769
770 /// Returns a comparator that imposes the reverse ordering.
771 ///
772 /// # Returns
773 ///
774 /// A new `RcComparator` that reverses the comparison order.
775 ///
776 /// # Examples
777 ///
778 /// ```rust
779 /// use prism3_function::comparator::{Comparator, RcComparator};
780 /// use std::cmp::Ordering;
781 ///
782 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
783 /// let rev = cmp.reversed();
784 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
785 /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater); // cmp still works
786 /// ```
787 pub fn reversed(&self) -> Self {
788 let self_fn = self.function.clone();
789 RcComparator::new(move |a, b| self_fn(b, a))
790 }
791
792 /// Returns a comparator that uses this comparator first, then another
793 /// comparator if this one considers the values equal.
794 ///
795 /// # Parameters
796 ///
797 /// * `other` - The comparator to use for tie-breaking
798 ///
799 /// # Returns
800 ///
801 /// A new `RcComparator` that chains this comparator with another.
802 ///
803 /// # Examples
804 ///
805 /// ```rust
806 /// use prism3_function::comparator::{Comparator, RcComparator};
807 /// use std::cmp::Ordering;
808 ///
809 /// let cmp1 = RcComparator::new(|a: &i32, b: &i32| {
810 /// (a % 2).cmp(&(b % 2))
811 /// });
812 /// let cmp2 = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
813 /// let chained = cmp1.then_comparing(&cmp2);
814 /// assert_eq!(chained.compare(&4, &2), Ordering::Greater);
815 /// ```
816 pub fn then_comparing(&self, other: &Self) -> Self {
817 let first = self.function.clone();
818 let second = other.function.clone();
819 RcComparator::new(move |a, b| match first(a, b) {
820 Ordering::Equal => second(a, b),
821 ord => ord,
822 })
823 }
824
825 /// Returns a comparator that compares values by a key extracted by the
826 /// given function.
827 ///
828 /// # Parameters
829 ///
830 /// * `key_fn` - A function that extracts a comparable key from values
831 ///
832 /// # Returns
833 ///
834 /// A new `RcComparator` that compares by the extracted key.
835 ///
836 /// # Examples
837 ///
838 /// ```rust
839 /// use prism3_function::comparator::{Comparator, RcComparator};
840 /// use std::cmp::Ordering;
841 ///
842 /// #[derive(Debug)]
843 /// struct Person {
844 /// name: String,
845 /// age: i32,
846 /// }
847 ///
848 /// let by_age = RcComparator::comparing(|p: &Person| &p.age);
849 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
850 /// let p2 = Person { name: "Bob".to_string(), age: 25 };
851 /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
852 /// ```
853 pub fn comparing<K, F>(key_fn: F) -> Self
854 where
855 K: Ord,
856 F: Fn(&T) -> &K + 'static,
857 {
858 RcComparator::new(move |a, b| key_fn(a).cmp(key_fn(b)))
859 }
860
861 /// Converts this comparator into a closure.
862 ///
863 /// # Returns
864 ///
865 /// A closure that implements `Fn(&T, &T) -> Ordering`.
866 ///
867 /// # Examples
868 ///
869 /// ```rust
870 /// use prism3_function::comparator::{Comparator, RcComparator};
871 /// use std::cmp::Ordering;
872 ///
873 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
874 /// let func = cmp.into_fn();
875 /// assert_eq!(func(&5, &3), Ordering::Greater);
876 /// ```
877 pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
878 move |a: &T, b: &T| (self.function)(a, b)
879 }
880}
881
882impl<T> Comparator<T> for RcComparator<T> {
883 fn compare(&self, a: &T, b: &T) -> Ordering {
884 (self.function)(a, b)
885 }
886}
887
888/// Extension trait providing composition methods for closures and function
889/// pointers.
890///
891/// This trait is automatically implemented for all closures and function
892/// pointers with the signature `Fn(&T, &T) -> Ordering`, allowing them to
893/// be composed directly without explicit wrapping.
894///
895/// # Examples
896///
897/// ```rust
898/// use prism3_function::comparator::{Comparator, FnComparatorOps};
899/// use std::cmp::Ordering;
900///
901/// let cmp = (|a: &i32, b: &i32| a.cmp(b))
902/// .reversed()
903/// .then_comparing(BoxComparator::new(|a, b| b.cmp(a)));
904///
905/// assert_eq!(cmp.compare(&5, &3), Ordering::Less);
906/// ```
907///
908/// # Author
909///
910/// Haixing Hu
911pub trait FnComparatorOps<T>: Fn(&T, &T) -> Ordering + Sized {
912 /// Returns a comparator that imposes the reverse ordering.
913 ///
914 /// # Returns
915 ///
916 /// A new `BoxComparator` that reverses the comparison order.
917 ///
918 /// # Examples
919 ///
920 /// ```rust
921 /// use prism3_function::comparator::{Comparator, FnComparatorOps};
922 /// use std::cmp::Ordering;
923 ///
924 /// let rev = (|a: &i32, b: &i32| a.cmp(b)).reversed();
925 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
926 /// ```
927 fn reversed(self) -> BoxComparator<T>
928 where
929 Self: 'static,
930 T: 'static,
931 {
932 BoxComparator::new(self).reversed()
933 }
934
935 /// Returns a comparator that uses this comparator first, then another
936 /// comparator if this one considers the values equal.
937 ///
938 /// # Parameters
939 ///
940 /// * `other` - The comparator to use for tie-breaking
941 ///
942 /// # Returns
943 ///
944 /// A new `BoxComparator` that chains this comparator with another.
945 ///
946 /// # Examples
947 ///
948 /// ```rust
949 /// use prism3_function::comparator::{Comparator, FnComparatorOps,
950 /// BoxComparator};
951 /// use std::cmp::Ordering;
952 ///
953 /// let cmp = (|a: &i32, b: &i32| (a % 2).cmp(&(b % 2)))
954 /// .then_comparing(BoxComparator::new(|a, b| a.cmp(b)));
955 /// assert_eq!(cmp.compare(&4, &2), Ordering::Greater);
956 /// ```
957 fn then_comparing(self, other: BoxComparator<T>) -> BoxComparator<T>
958 where
959 Self: 'static,
960 T: 'static,
961 {
962 BoxComparator::new(self).then_comparing(other)
963 }
964}
965
966impl<T, F> FnComparatorOps<T> for F where F: Fn(&T, &T) -> Ordering {}