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
172
173use std::cmp::Ordering;
174use std::rc::Rc;
175use std::sync::Arc;
176
177// ==========================================================================
178// Type Aliases
179// ==========================================================================
180
181/// Type alias for comparator function signature.
182type ComparatorFn<T> = dyn Fn(&T, &T) -> Ordering;
183
184/// Type alias for thread-safe comparator function signature.
185type ThreadSafeComparatorFn<T> = dyn Fn(&T, &T) -> Ordering + Send + Sync;
186
187/// A trait for comparison operations.
188///
189/// This trait defines the core comparison operation and conversion methods.
190/// It does NOT include composition methods like `reversed` or
191/// `then_comparing` to maintain a clean separation between the trait
192/// interface and specialized implementations.
193///
194/// # Type Parameters
195///
196/// * `T` - The type of values being compared
197///
198/// # Examples
199///
200/// ```rust
201/// use prism3_function::comparator::{Comparator, BoxComparator};
202/// use std::cmp::Ordering;
203///
204/// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
205/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
206/// ```
207///
208/// # Author
209///
210/// Haixing Hu
211pub trait Comparator<T> {
212 /// Compares two values and returns an ordering.
213 ///
214 /// # Parameters
215 ///
216 /// * `a` - The first value to compare
217 /// * `b` - The second value to compare
218 ///
219 /// # Returns
220 ///
221 /// An `Ordering` indicating whether `a` is less than, equal to, or
222 /// greater than `b`.
223 ///
224 /// # Examples
225 ///
226 /// ```rust
227 /// use prism3_function::comparator::{Comparator, BoxComparator};
228 /// use std::cmp::Ordering;
229 ///
230 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
231 /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
232 /// assert_eq!(cmp.compare(&3, &5), Ordering::Less);
233 /// assert_eq!(cmp.compare(&5, &5), Ordering::Equal);
234 /// ```
235 fn compare(&self, a: &T, b: &T) -> Ordering;
236
237 /// Converts this comparator into a `BoxComparator`.
238 ///
239 /// # Returns
240 ///
241 /// A new `BoxComparator` wrapping this comparator.
242 ///
243 /// # Examples
244 ///
245 /// ```rust
246 /// use prism3_function::comparator::{Comparator, BoxComparator};
247 ///
248 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
249 /// let boxed = cmp.into_box();
250 /// ```
251 fn into_box(self) -> BoxComparator<T>
252 where
253 Self: Sized + 'static,
254 T: 'static,
255 {
256 BoxComparator::new(move |a, b| self.compare(a, b))
257 }
258
259 /// Converts this comparator into an `ArcComparator`.
260 ///
261 /// # Returns
262 ///
263 /// A new `ArcComparator` wrapping this comparator.
264 ///
265 /// # Examples
266 ///
267 /// ```rust
268 /// use prism3_function::comparator::{Comparator, ArcComparator};
269 ///
270 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
271 /// let arc = cmp.into_arc();
272 /// ```
273 fn into_arc(self) -> ArcComparator<T>
274 where
275 Self: Sized + Send + Sync + 'static,
276 T: 'static,
277 {
278 ArcComparator::new(move |a, b| self.compare(a, b))
279 }
280
281 /// Converts this comparator into an `RcComparator`.
282 ///
283 /// # Returns
284 ///
285 /// A new `RcComparator` wrapping this comparator.
286 ///
287 /// # Examples
288 ///
289 /// ```rust
290 /// use prism3_function::comparator::{Comparator, RcComparator};
291 ///
292 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
293 /// let rc = cmp.into_rc();
294 /// ```
295 fn into_rc(self) -> RcComparator<T>
296 where
297 Self: Sized + 'static,
298 T: 'static,
299 {
300 RcComparator::new(move |a, b| self.compare(a, b))
301 }
302
303 /// Converts this comparator into a closure that implements
304 /// `Fn(&T, &T) -> Ordering`.
305 ///
306 /// This method consumes the comparator and returns a closure that
307 /// can be used anywhere a function or closure is expected.
308 ///
309 /// # Returns
310 ///
311 /// An implementation that can be called as `Fn(&T, &T) -> Ordering`.
312 ///
313 /// # Examples
314 ///
315 /// ```rust
316 /// use prism3_function::comparator::{Comparator, BoxComparator};
317 /// use std::cmp::Ordering;
318 ///
319 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
320 /// let func = cmp.into_fn();
321 /// assert_eq!(func(&5, &3), Ordering::Greater);
322 /// ```
323 fn into_fn(self) -> impl Fn(&T, &T) -> Ordering
324 where
325 Self: Sized + 'static,
326 T: 'static,
327 {
328 move |a: &T, b: &T| self.compare(a, b)
329 }
330}
331
332/// Blanket implementation of `Comparator` for all closures and function
333/// pointers.
334///
335/// This allows any closure or function with the signature
336/// `Fn(&T, &T) -> Ordering` to be used as a comparator.
337///
338/// # Examples
339///
340/// ```rust
341/// use prism3_function::comparator::Comparator;
342/// use std::cmp::Ordering;
343///
344/// let cmp = |a: &i32, b: &i32| a.cmp(b);
345/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
346/// ```
347impl<T, F> Comparator<T> for F
348where
349 F: Fn(&T, &T) -> Ordering,
350{
351 fn compare(&self, a: &T, b: &T) -> Ordering {
352 self(a, b)
353 }
354}
355
356/// A boxed comparator with single ownership.
357///
358/// `BoxComparator` wraps a comparator function in a `Box`, providing single
359/// ownership semantics. It is not cloneable and consumes `self` in
360/// composition operations.
361///
362/// # Type Parameters
363///
364/// * `T` - The type of values being compared
365///
366/// # Examples
367///
368/// ```rust
369/// use prism3_function::comparator::{Comparator, BoxComparator};
370/// use std::cmp::Ordering;
371///
372/// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
373/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
374/// ```
375///
376/// # Author
377///
378/// Haixing Hu
379pub struct BoxComparator<T> {
380 function: Box<ComparatorFn<T>>,
381}
382
383impl<T: 'static> BoxComparator<T> {
384 /// Creates a new `BoxComparator` from a closure.
385 ///
386 /// # Parameters
387 ///
388 /// * `f` - The closure to wrap
389 ///
390 /// # Returns
391 ///
392 /// A new `BoxComparator` instance.
393 ///
394 /// # Examples
395 ///
396 /// ```rust
397 /// use prism3_function::comparator::BoxComparator;
398 ///
399 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
400 /// ```
401 pub fn new<F>(f: F) -> Self
402 where
403 F: Fn(&T, &T) -> Ordering + 'static,
404 {
405 Self {
406 function: Box::new(f),
407 }
408 }
409
410 /// Returns a comparator that imposes the reverse ordering.
411 ///
412 /// # Returns
413 ///
414 /// A new `BoxComparator` that reverses the comparison order.
415 ///
416 /// # Examples
417 ///
418 /// ```rust
419 /// use prism3_function::comparator::{Comparator, BoxComparator};
420 /// use std::cmp::Ordering;
421 ///
422 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
423 /// let rev = cmp.reversed();
424 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
425 /// ```
426 pub fn reversed(self) -> Self {
427 Self {
428 function: Box::new(move |a: &T, b: &T| (self.function)(b, a)),
429 }
430 }
431
432 /// Returns a comparator that uses this comparator first, then another
433 /// comparator if this one considers the values equal.
434 ///
435 /// # Parameters
436 ///
437 /// * `other` - The comparator to use for tie-breaking. **Note: This
438 /// parameter is passed by value and will transfer ownership.** If you
439 /// need to preserve the original comparator, clone it first (if it
440 /// implements `Clone`). Can be:
441 /// - A `BoxComparator<T>`
442 /// - An `RcComparator<T>`
443 /// - An `ArcComparator<T>`
444 /// - Any type implementing `Comparator<T>`
445 ///
446 /// # Returns
447 ///
448 /// A new `BoxComparator` that chains this comparator with another.
449 ///
450 /// # Examples
451 ///
452 /// ```rust
453 /// use prism3_function::comparator::{Comparator, BoxComparator};
454 /// use std::cmp::Ordering;
455 ///
456 /// #[derive(Debug)]
457 /// struct Person {
458 /// name: String,
459 /// age: i32,
460 /// }
461 ///
462 /// let by_name = BoxComparator::new(|a: &Person, b: &Person| {
463 /// a.name.cmp(&b.name)
464 /// });
465 /// let by_age = BoxComparator::new(|a: &Person, b: &Person| {
466 /// a.age.cmp(&b.age)
467 /// });
468 ///
469 /// // by_age is moved here
470 /// let cmp = by_name.then_comparing(by_age);
471 ///
472 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
473 /// let p2 = Person { name: "Alice".to_string(), age: 25 };
474 /// assert_eq!(cmp.compare(&p1, &p2), Ordering::Greater);
475 /// // by_age.compare(&p1, &p2); // Would not compile - moved
476 /// ```
477 pub fn then_comparing(self, other: Self) -> Self {
478 Self {
479 function: Box::new(move |a: &T, b: &T| match (self.function)(a, b) {
480 Ordering::Equal => (other.function)(a, b),
481 ord => ord,
482 }),
483 }
484 }
485
486 /// Returns a comparator that compares values by a key extracted by the
487 /// given function.
488 ///
489 /// # Parameters
490 ///
491 /// * `key_fn` - A function that extracts a comparable key from values
492 ///
493 /// # Returns
494 ///
495 /// A new `BoxComparator` that compares by the extracted key.
496 ///
497 /// # Examples
498 ///
499 /// ```rust
500 /// use prism3_function::comparator::{Comparator, BoxComparator};
501 /// use std::cmp::Ordering;
502 ///
503 /// #[derive(Debug)]
504 /// struct Person {
505 /// name: String,
506 /// age: i32,
507 /// }
508 ///
509 /// let by_age = BoxComparator::comparing(|p: &Person| &p.age);
510 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
511 /// let p2 = Person { name: "Bob".to_string(), age: 25 };
512 /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
513 /// ```
514 pub fn comparing<K, F>(key_fn: F) -> Self
515 where
516 K: Ord,
517 F: Fn(&T) -> &K + 'static,
518 {
519 Self::new(move |a: &T, b: &T| key_fn(a).cmp(key_fn(b)))
520 }
521
522 /// Converts this comparator into a closure.
523 ///
524 /// # Returns
525 ///
526 /// A closure that implements `Fn(&T, &T) -> Ordering`.
527 ///
528 /// # Examples
529 ///
530 /// ```rust
531 /// use prism3_function::comparator::{Comparator, BoxComparator};
532 /// use std::cmp::Ordering;
533 ///
534 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
535 /// let func = cmp.into_fn();
536 /// assert_eq!(func(&5, &3), Ordering::Greater);
537 /// ```
538 pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
539 move |a: &T, b: &T| (self.function)(a, b)
540 }
541}
542
543impl<T> Comparator<T> for BoxComparator<T> {
544 fn compare(&self, a: &T, b: &T) -> Ordering {
545 (self.function)(a, b)
546 }
547}
548
549/// An Arc-based thread-safe comparator with shared ownership.
550///
551/// `ArcComparator` wraps a comparator function in an `Arc`, providing
552/// thread-safe shared ownership semantics. It is cloneable and uses `&self`
553/// in composition operations.
554///
555/// # Type Parameters
556///
557/// * `T` - The type of values being compared
558///
559/// # Examples
560///
561/// ```rust
562/// use prism3_function::comparator::{Comparator, ArcComparator};
563/// use std::cmp::Ordering;
564///
565/// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
566/// let cloned = cmp.clone();
567/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
568/// assert_eq!(cloned.compare(&5, &3), Ordering::Greater);
569/// ```
570///
571/// # Author
572///
573/// Haixing Hu
574#[derive(Clone)]
575pub struct ArcComparator<T> {
576 function: Arc<ThreadSafeComparatorFn<T>>,
577}
578
579impl<T: 'static> ArcComparator<T> {
580 /// Creates a new `ArcComparator` from a closure.
581 ///
582 /// # Parameters
583 ///
584 /// * `f` - The closure to wrap
585 ///
586 /// # Returns
587 ///
588 /// A new `ArcComparator` instance.
589 ///
590 /// # Examples
591 ///
592 /// ```rust
593 /// use prism3_function::comparator::ArcComparator;
594 ///
595 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
596 /// ```
597 pub fn new<F>(f: F) -> Self
598 where
599 F: Fn(&T, &T) -> Ordering + Send + Sync + 'static,
600 {
601 Self {
602 function: Arc::new(f),
603 }
604 }
605
606 /// Returns a comparator that imposes the reverse ordering.
607 ///
608 /// # Returns
609 ///
610 /// A new `ArcComparator` that reverses the comparison order.
611 ///
612 /// # Examples
613 ///
614 /// ```rust
615 /// use prism3_function::comparator::{Comparator, ArcComparator};
616 /// use std::cmp::Ordering;
617 ///
618 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
619 /// let rev = cmp.reversed();
620 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
621 /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater); // cmp still works
622 /// ```
623 pub fn reversed(&self) -> Self {
624 let function = self.function.clone();
625 Self {
626 function: Arc::new(move |a: &T, b: &T| function(b, a)),
627 }
628 }
629
630 /// Returns a comparator that uses this comparator first, then another
631 /// comparator if this one considers the values equal.
632 ///
633 /// # Parameters
634 ///
635 /// * `other` - The comparator to use for tie-breaking
636 ///
637 /// # Returns
638 ///
639 /// A new `ArcComparator` that chains this comparator with another.
640 ///
641 /// # Examples
642 ///
643 /// ```rust
644 /// use prism3_function::comparator::{Comparator, ArcComparator};
645 /// use std::cmp::Ordering;
646 ///
647 /// let cmp1 = ArcComparator::new(|a: &i32, b: &i32| {
648 /// (a % 2).cmp(&(b % 2))
649 /// });
650 /// let cmp2 = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
651 /// let chained = cmp1.then_comparing(&cmp2);
652 /// assert_eq!(chained.compare(&4, &2), Ordering::Greater);
653 /// ```
654 pub fn then_comparing(&self, other: &Self) -> Self {
655 let first = self.function.clone();
656 let second = other.function.clone();
657 Self {
658 function: Arc::new(move |a: &T, b: &T| match first(a, b) {
659 Ordering::Equal => second(a, b),
660 ord => ord,
661 }),
662 }
663 }
664
665 /// Returns a comparator that compares values by a key extracted by the
666 /// given function.
667 ///
668 /// # Parameters
669 ///
670 /// * `key_fn` - A function that extracts a comparable key from values
671 ///
672 /// # Returns
673 ///
674 /// A new `ArcComparator` that compares by the extracted key.
675 ///
676 /// # Examples
677 ///
678 /// ```rust
679 /// use prism3_function::comparator::{Comparator, ArcComparator};
680 /// use std::cmp::Ordering;
681 ///
682 /// #[derive(Debug)]
683 /// struct Person {
684 /// name: String,
685 /// age: i32,
686 /// }
687 ///
688 /// let by_age = ArcComparator::comparing(|p: &Person| &p.age);
689 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
690 /// let p2 = Person { name: "Bob".to_string(), age: 25 };
691 /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
692 /// ```
693 pub fn comparing<K, F>(key_fn: F) -> Self
694 where
695 K: Ord,
696 F: Fn(&T) -> &K + Send + Sync + 'static,
697 {
698 Self::new(move |a: &T, b: &T| key_fn(a).cmp(key_fn(b)))
699 }
700
701 /// Converts this comparator into a closure.
702 ///
703 /// # Returns
704 ///
705 /// A closure that implements `Fn(&T, &T) -> Ordering`.
706 ///
707 /// # Examples
708 ///
709 /// ```rust
710 /// use prism3_function::comparator::{Comparator, ArcComparator};
711 /// use std::cmp::Ordering;
712 ///
713 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
714 /// let func = cmp.into_fn();
715 /// assert_eq!(func(&5, &3), Ordering::Greater);
716 /// ```
717 pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
718 move |a: &T, b: &T| (self.function)(a, b)
719 }
720}
721
722impl<T> Comparator<T> for ArcComparator<T> {
723 fn compare(&self, a: &T, b: &T) -> Ordering {
724 (self.function)(a, b)
725 }
726}
727
728/// An Rc-based single-threaded comparator with shared ownership.
729///
730/// `RcComparator` wraps a comparator function in an `Rc`, providing
731/// single-threaded shared ownership semantics. It is cloneable and uses
732/// `&self` in composition operations.
733///
734/// # Type Parameters
735///
736/// * `T` - The type of values being compared
737///
738/// # Examples
739///
740/// ```rust
741/// use prism3_function::comparator::{Comparator, RcComparator};
742/// use std::cmp::Ordering;
743///
744/// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
745/// let cloned = cmp.clone();
746/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
747/// assert_eq!(cloned.compare(&5, &3), Ordering::Greater);
748/// ```
749///
750/// # Author
751///
752/// Haixing Hu
753#[derive(Clone)]
754pub struct RcComparator<T> {
755 function: Rc<ComparatorFn<T>>,
756}
757
758impl<T: 'static> RcComparator<T> {
759 /// Creates a new `RcComparator` from a closure.
760 ///
761 /// # Parameters
762 ///
763 /// * `f` - The closure to wrap
764 ///
765 /// # Returns
766 ///
767 /// A new `RcComparator` instance.
768 ///
769 /// # Examples
770 ///
771 /// ```rust
772 /// use prism3_function::comparator::RcComparator;
773 ///
774 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
775 /// ```
776 pub fn new<F>(f: F) -> Self
777 where
778 F: Fn(&T, &T) -> Ordering + 'static,
779 {
780 Self {
781 function: Rc::new(f),
782 }
783 }
784
785 /// Returns a comparator that imposes the reverse ordering.
786 ///
787 /// # Returns
788 ///
789 /// A new `RcComparator` that reverses the comparison order.
790 ///
791 /// # Examples
792 ///
793 /// ```rust
794 /// use prism3_function::comparator::{Comparator, RcComparator};
795 /// use std::cmp::Ordering;
796 ///
797 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
798 /// let rev = cmp.reversed();
799 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
800 /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater); // cmp still works
801 /// ```
802 pub fn reversed(&self) -> Self {
803 let function = self.function.clone();
804 Self {
805 function: Rc::new(move |a: &T, b: &T| function(b, a)),
806 }
807 }
808
809 /// Returns a comparator that uses this comparator first, then another
810 /// comparator if this one considers the values equal.
811 ///
812 /// # Parameters
813 ///
814 /// * `other` - The comparator to use for tie-breaking
815 ///
816 /// # Returns
817 ///
818 /// A new `RcComparator` that chains this comparator with another.
819 ///
820 /// # Examples
821 ///
822 /// ```rust
823 /// use prism3_function::comparator::{Comparator, RcComparator};
824 /// use std::cmp::Ordering;
825 ///
826 /// let cmp1 = RcComparator::new(|a: &i32, b: &i32| {
827 /// (a % 2).cmp(&(b % 2))
828 /// });
829 /// let cmp2 = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
830 /// let chained = cmp1.then_comparing(&cmp2);
831 /// assert_eq!(chained.compare(&4, &2), Ordering::Greater);
832 /// ```
833 pub fn then_comparing(&self, other: &Self) -> Self {
834 let first = self.function.clone();
835 let second = other.function.clone();
836 Self {
837 function: Rc::new(move |a: &T, b: &T| match first(a, b) {
838 Ordering::Equal => second(a, b),
839 ord => ord,
840 }),
841 }
842 }
843
844 /// Returns a comparator that compares values by a key extracted by the
845 /// given function.
846 ///
847 /// # Parameters
848 ///
849 /// * `key_fn` - A function that extracts a comparable key from values
850 ///
851 /// # Returns
852 ///
853 /// A new `RcComparator` that compares by the extracted key.
854 ///
855 /// # Examples
856 ///
857 /// ```rust
858 /// use prism3_function::comparator::{Comparator, RcComparator};
859 /// use std::cmp::Ordering;
860 ///
861 /// #[derive(Debug)]
862 /// struct Person {
863 /// name: String,
864 /// age: i32,
865 /// }
866 ///
867 /// let by_age = RcComparator::comparing(|p: &Person| &p.age);
868 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
869 /// let p2 = Person { name: "Bob".to_string(), age: 25 };
870 /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
871 /// ```
872 pub fn comparing<K, F>(key_fn: F) -> Self
873 where
874 K: Ord,
875 F: Fn(&T) -> &K + 'static,
876 {
877 Self::new(move |a: &T, b: &T| key_fn(a).cmp(key_fn(b)))
878 }
879
880 /// Converts this comparator into a closure.
881 ///
882 /// # Returns
883 ///
884 /// A closure that implements `Fn(&T, &T) -> Ordering`.
885 ///
886 /// # Examples
887 ///
888 /// ```rust
889 /// use prism3_function::comparator::{Comparator, RcComparator};
890 /// use std::cmp::Ordering;
891 ///
892 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
893 /// let func = cmp.into_fn();
894 /// assert_eq!(func(&5, &3), Ordering::Greater);
895 /// ```
896 pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
897 move |a: &T, b: &T| (self.function)(a, b)
898 }
899}
900
901impl<T> Comparator<T> for RcComparator<T> {
902 fn compare(&self, a: &T, b: &T) -> Ordering {
903 (self.function)(a, b)
904 }
905}
906
907/// Extension trait providing composition methods for closures and function
908/// pointers.
909///
910/// This trait is automatically implemented for all closures and function
911/// pointers with the signature `Fn(&T, &T) -> Ordering`, allowing them to
912/// be composed directly without explicit wrapping.
913///
914/// # Examples
915///
916/// ```rust
917/// use prism3_function::comparator::{Comparator, FnComparatorOps};
918/// use std::cmp::Ordering;
919///
920/// let cmp = (|a: &i32, b: &i32| a.cmp(b))
921/// .reversed()
922/// .then_comparing(BoxComparator::new(|a, b| b.cmp(a)));
923///
924/// assert_eq!(cmp.compare(&5, &3), Ordering::Less);
925/// ```
926///
927/// # Author
928///
929/// Haixing Hu
930pub trait FnComparatorOps<T>: Fn(&T, &T) -> Ordering + Sized {
931 /// Returns a comparator that imposes the reverse ordering.
932 ///
933 /// # Returns
934 ///
935 /// A new `BoxComparator` that reverses the comparison order.
936 ///
937 /// # Examples
938 ///
939 /// ```rust
940 /// use prism3_function::comparator::{Comparator, FnComparatorOps};
941 /// use std::cmp::Ordering;
942 ///
943 /// let rev = (|a: &i32, b: &i32| a.cmp(b)).reversed();
944 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
945 /// ```
946 fn reversed(self) -> BoxComparator<T>
947 where
948 Self: 'static,
949 T: 'static,
950 {
951 BoxComparator::new(self).reversed()
952 }
953
954 /// Returns a comparator that uses this comparator first, then another
955 /// comparator if this one considers the values equal.
956 ///
957 /// # Parameters
958 ///
959 /// * `other` - The comparator to use for tie-breaking
960 ///
961 /// # Returns
962 ///
963 /// A new `BoxComparator` that chains this comparator with another.
964 ///
965 /// # Examples
966 ///
967 /// ```rust
968 /// use prism3_function::comparator::{Comparator, FnComparatorOps,
969 /// BoxComparator};
970 /// use std::cmp::Ordering;
971 ///
972 /// let cmp = (|a: &i32, b: &i32| (a % 2).cmp(&(b % 2)))
973 /// .then_comparing(BoxComparator::new(|a, b| a.cmp(b)));
974 /// assert_eq!(cmp.compare(&4, &2), Ordering::Greater);
975 /// ```
976 fn then_comparing(self, other: BoxComparator<T>) -> BoxComparator<T>
977 where
978 Self: 'static,
979 T: 'static,
980 {
981 BoxComparator::new(self).then_comparing(other)
982 }
983}
984
985impl<T, F> FnComparatorOps<T> for F where F: Fn(&T, &T) -> Ordering {}