Skip to main content

qubit_function/
comparator.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit 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 qubit_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 qubit_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: &i32, b: &i32| 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 qubit_function::comparator::{Comparator, FnComparatorOps, BoxComparator};
112//! use std::cmp::Ordering;
113//!
114//! let cmp = (|a: &i32, b: &i32| a.cmp(b))
115//!     .reversed()
116//!     .then_comparing(BoxComparator::new(|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 qubit_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 qubit_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 qubit_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
176mod box_comparator;
177pub use box_comparator::BoxComparator;
178mod arc_comparator;
179pub use arc_comparator::ArcComparator;
180mod rc_comparator;
181pub use rc_comparator::RcComparator;
182mod fn_comparator_ops;
183pub use fn_comparator_ops::FnComparatorOps;
184
185// ==========================================================================
186// Type Aliases
187// ==========================================================================
188
189/// A trait for comparison operations.
190///
191/// This trait defines the core comparison operation and conversion methods.
192/// It does NOT include composition methods like `reversed` or
193/// `then_comparing` to maintain a clean separation between the trait
194/// interface and specialized implementations.
195///
196/// # Type Parameters
197///
198/// * `T` - The type of values being compared
199///
200/// # Examples
201///
202/// ```rust
203/// use qubit_function::comparator::{Comparator, BoxComparator};
204/// use std::cmp::Ordering;
205///
206/// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
207/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
208/// ```
209///
210/// # Author
211///
212/// Haixing Hu
213pub trait Comparator<T> {
214    /// Compares two values and returns an ordering.
215    ///
216    /// # Parameters
217    ///
218    /// * `a` - The first value to compare
219    /// * `b` - The second value to compare
220    ///
221    /// # Returns
222    ///
223    /// An `Ordering` indicating whether `a` is less than, equal to, or
224    /// greater than `b`.
225    ///
226    /// # Examples
227    ///
228    /// ```rust
229    /// use qubit_function::comparator::{Comparator, BoxComparator};
230    /// use std::cmp::Ordering;
231    ///
232    /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
233    /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
234    /// assert_eq!(cmp.compare(&3, &5), Ordering::Less);
235    /// assert_eq!(cmp.compare(&5, &5), Ordering::Equal);
236    /// ```
237    fn compare(&self, a: &T, b: &T) -> Ordering;
238
239    /// Converts this comparator into a `BoxComparator`.
240    ///
241    /// # Returns
242    ///
243    /// A new `BoxComparator` wrapping this comparator.
244    ///
245    /// # Examples
246    ///
247    /// ```rust
248    /// use qubit_function::comparator::{Comparator, BoxComparator};
249    ///
250    /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
251    /// let boxed = cmp.into_box();
252    /// ```
253    #[inline]
254    fn into_box(self) -> BoxComparator<T>
255    where
256        Self: Sized + 'static,
257    {
258        BoxComparator::new(move |a, b| self.compare(a, b))
259    }
260
261    /// Converts this comparator into an `ArcComparator`.
262    ///
263    /// # Returns
264    ///
265    /// A new `ArcComparator` wrapping this comparator.
266    ///
267    /// # Examples
268    ///
269    /// ```rust
270    /// use qubit_function::comparator::{Comparator, ArcComparator};
271    ///
272    /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
273    /// let arc = cmp.into_arc();
274    /// ```
275    #[inline]
276    fn into_arc(self) -> ArcComparator<T>
277    where
278        Self: Sized + Send + Sync + 'static,
279    {
280        ArcComparator::new(move |a, b| self.compare(a, b))
281    }
282
283    /// Converts this comparator into an `RcComparator`.
284    ///
285    /// # Returns
286    ///
287    /// A new `RcComparator` wrapping this comparator.
288    ///
289    /// # Examples
290    ///
291    /// ```rust
292    /// use qubit_function::comparator::{Comparator, RcComparator};
293    ///
294    /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
295    /// let rc = cmp.into_rc();
296    /// ```
297    #[inline]
298    fn into_rc(self) -> RcComparator<T>
299    where
300        Self: Sized + 'static,
301    {
302        RcComparator::new(move |a, b| self.compare(a, b))
303    }
304
305    /// Converts this comparator into a closure that implements
306    /// `Fn(&T, &T) -> Ordering`.
307    ///
308    /// This method consumes the comparator and returns a closure that
309    /// can be used anywhere a function or closure is expected.
310    ///
311    /// # Returns
312    ///
313    /// An implementation that can be called as `Fn(&T, &T) -> Ordering`.
314    ///
315    /// # Examples
316    ///
317    /// ```rust
318    /// use qubit_function::comparator::{Comparator, BoxComparator};
319    /// use std::cmp::Ordering;
320    ///
321    /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
322    /// let func = cmp.into_fn();
323    /// assert_eq!(func(&5, &3), Ordering::Greater);
324    /// ```
325    #[inline]
326    fn into_fn(self) -> impl Fn(&T, &T) -> Ordering
327    where
328        Self: Sized + 'static,
329    {
330        move |a: &T, b: &T| self.compare(a, b)
331    }
332}
333
334/// Blanket implementation of `Comparator` for all closures and function
335/// pointers.
336///
337/// This allows any closure or function with the signature
338/// `Fn(&T, &T) -> Ordering` to be used as a comparator.
339///
340/// # Examples
341///
342/// ```rust
343/// use qubit_function::comparator::Comparator;
344/// use std::cmp::Ordering;
345///
346/// let cmp = |a: &i32, b: &i32| a.cmp(b);
347/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
348/// ```
349impl<T, F> Comparator<T> for F
350where
351    F: Fn(&T, &T) -> Ordering,
352{
353    #[inline]
354    fn compare(&self, a: &T, b: &T) -> Ordering {
355        self(a, b)
356    }
357}