Expand description
§Comparator Abstraction
Provides a Rust implementation similar to Java’s Comparator interface
for comparison operations and chaining.
§Design Overview
This module adopts the Trait + Multiple Implementations design pattern, which is the most flexible and elegant approach for implementing comparators in Rust. It achieves a perfect balance between semantic clarity, type safety, and API flexibility.
§Core Components
-
Comparator<T>trait: A minimalist unified interface that only defines the corecomparemethod and type conversion methods (into_*). It does NOT include chaining methods likethen_comparing, etc. -
Three Concrete Struct Implementations:
BoxComparator<T>: Box-based single ownership implementation for one-time use scenariosArcComparator<T>: Arc-based thread-safe shared ownership implementation for multi-threaded scenariosRcComparator<T>: Rc-based single-threaded shared ownership implementation for single-threaded reuse
-
Specialized Composition Methods: Each struct implements its own inherent methods (
reversed,then_comparing, etc.) that return the same concrete type, preserving their specific characteristics (e.g.,ArcComparatorcompositions remainArcComparatorand stay cloneable and thread-safe). -
Extension Trait for Closures: The
FnComparatorOps<T>extension trait provides composition methods for all closures and function pointers, returningBoxComparator<T>to initiate method chaining. -
Unified Trait Implementation: All closures and the three structs implement the
Comparator<T>trait, enabling them to be handled uniformly by generic functions.
§Ownership Model Coverage
The three implementations correspond to three typical ownership scenarios:
| Type | Ownership | Clonable | Thread-Safe | API | Use Case |
|---|---|---|---|---|---|
BoxComparator | Single | ❌ | ❌ | consumes self | One-time |
ArcComparator | Shared | ✅ | ✅ | borrows &self | Multi-thread |
RcComparator | Shared | ✅ | ❌ | borrows &self | Single-thread |
§Key Design Advantages
§1. Type Preservation through Specialization
By implementing composition methods on concrete structs rather than in the trait, each type maintains its specific characteristics through composition:
use prism3_function::comparator::{Comparator, ArcComparator};
use std::cmp::Ordering;
let arc_cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
let another = ArcComparator::new(|a: &i32, b: &i32| b.cmp(a));
// Composition returns ArcComparator, preserving clonability and
// thread-safety
let combined = arc_cmp.then_comparing(&another);
let cloned = combined.clone(); // ✅ Still cloneable
// Original comparators remain usable
assert_eq!(arc_cmp.compare(&5, &3), Ordering::Greater);§2. Elegant API without Explicit Cloning
ArcComparator and RcComparator use &self in their composition
methods, providing a natural experience without requiring explicit
.clone() calls:
use prism3_function::comparator::{Comparator, ArcComparator};
let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
// No need for explicit clone()
let reversed = cmp.reversed();
let chained = cmp.then_comparing(&ArcComparator::new(|a, b| b.cmp(a)));
// cmp is still available
cmp.compare(&1, &2);§3. Efficient Closure Composition
The FnComparatorOps extension trait allows direct composition on
closures:
use prism3_function::comparator::{Comparator, FnComparatorOps};
use std::cmp::Ordering;
let cmp = (|a: &i32, b: &i32| a.cmp(b))
.reversed()
.then_comparing(|a: &i32, b: &i32| b.cmp(a));
assert_eq!(cmp.compare(&5, &3), Ordering::Less);§Usage Examples
§Basic Comparison
use prism3_function::comparator::{Comparator, BoxComparator};
use std::cmp::Ordering;
let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
assert_eq!(cmp.compare(&5, &3), Ordering::Greater);§Reversed Comparison
use prism3_function::comparator::{Comparator, BoxComparator};
use std::cmp::Ordering;
let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
let rev = cmp.reversed();
assert_eq!(rev.compare(&5, &3), Ordering::Less);§Chained Comparison
use prism3_function::comparator::{Comparator, BoxComparator};
use std::cmp::Ordering;
#[derive(Debug)]
struct Person {
name: String,
age: i32,
}
let by_name = BoxComparator::new(|a: &Person, b: &Person| {
a.name.cmp(&b.name)
});
let by_age = BoxComparator::new(|a: &Person, b: &Person| {
a.age.cmp(&b.age)
});
let cmp = by_name.then_comparing(by_age);
let p1 = Person { name: "Alice".to_string(), age: 30 };
let p2 = Person { name: "Alice".to_string(), age: 25 };
assert_eq!(cmp.compare(&p1, &p2), Ordering::Greater);§Author
Haixing Hu
Structs§
- ArcComparator
- An Arc-based thread-safe comparator with shared ownership.
- BoxComparator
- A boxed comparator with single ownership.
- RcComparator
- An Rc-based single-threaded comparator with shared ownership.
Traits§
- Comparator
- A trait for comparison operations.
- FnComparator
Ops - Extension trait providing composition methods for closures and function pointers.