Skip to main content

qubit_function/
comparator.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! # Comparator Abstraction
11//!
12//! Provides a Rust implementation similar to Java's `Comparator` interface
13//! for comparison operations and chaining.
14//!
15//! ## Design Overview
16//!
17//! This module adopts the **Trait + Multiple Implementations** design
18//! pattern, which is the most flexible and elegant approach for
19//! implementing comparators in Rust. It achieves a perfect balance
20//! between semantic clarity, type safety, and API flexibility.
21//!
22//! ### Core Components
23//!
24//! 1. **`Comparator<T>` trait**: A minimalist unified interface that only
25//!    defines the core `compare` method and type conversion methods
26//!    (`into_*`). It does NOT include chaining methods like
27//!    `then_comparing`, etc.
28//!
29//! 2. **Three Concrete Struct Implementations**:
30//!    - [`BoxComparator<T>`]: Box-based single ownership implementation
31//!      for one-time use scenarios
32//!    - [`ArcComparator<T>`]: Arc-based thread-safe shared ownership
33//!      implementation for multi-threaded scenarios
34//!    - [`RcComparator<T>`]: Rc-based single-threaded shared ownership
35//!      implementation for single-threaded reuse
36//!
37//! 3. **Specialized Composition Methods**: Each struct implements its own
38//!    inherent methods (`reversed`, `then_comparing`, etc.) that return
39//!    the same concrete type, preserving their specific characteristics
40//!    (e.g., `ArcComparator` compositions remain `ArcComparator` and stay
41//!    cloneable and thread-safe).
42//!
43//! 4. **Extension Trait for Closures**: The `FnComparatorOps<T>`
44//!    extension trait provides composition methods for all closures and
45//!    function pointers, returning `BoxComparator<T>` to initiate method
46//!    chaining.
47//!
48//! 5. **Unified Trait Implementation**: All closures and the three
49//!    structs implement the `Comparator<T>` trait, enabling them to be
50//!    handled uniformly by generic functions.
51//!
52//! ## Ownership Model Coverage
53//!
54//! The three implementations correspond to three typical ownership
55//! scenarios:
56//!
57//! | Type | Ownership | Clonable | Thread-Safe | API | Use Case |
58//! |:-----|:----------|:---------|:------------|:----|:---------|
59//! | [`BoxComparator`] | Single | ❌ | ❌ | consumes `self` | One-time |
60//! | [`ArcComparator`] | Shared | ✅ | ✅ | borrows `&self` | Multi-thread |
61//! | [`RcComparator`] | Shared | ✅ | ❌ | borrows `&self` | Single-thread |
62//!
63//! ## Key Design Advantages
64//!
65//! ### 1. Type Preservation through Specialization
66//!
67//! By implementing composition methods on concrete structs rather than in
68//! the trait, each type maintains its specific characteristics through
69//! composition:
70//!
71//! ```rust
72//! use qubit_function::comparator::{Comparator, ArcComparator};
73//! use std::cmp::Ordering;
74//!
75//! let arc_cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
76//! let another = ArcComparator::new(|a: &i32, b: &i32| b.cmp(a));
77//!
78//! // Composition returns ArcComparator, preserving clonability and
79//! // thread-safety
80//! let combined = arc_cmp.then_comparing(&another);
81//! let cloned = combined.clone();  // ✅ Still cloneable
82//!
83//! // Original comparators remain usable
84//! assert_eq!(arc_cmp.compare(&5, &3), Ordering::Greater);
85//! ```
86//!
87//! ### 2. Elegant API without Explicit Cloning
88//!
89//! `ArcComparator` and `RcComparator` use `&self` in their composition
90//! methods, providing a natural experience without requiring explicit
91//! `.clone()` calls:
92//!
93//! ```rust
94//! use qubit_function::comparator::{Comparator, ArcComparator};
95//!
96//! let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
97//!
98//! // No need for explicit clone()
99//! let reversed = cmp.reversed();
100//! let chained = cmp.then_comparing(&ArcComparator::new(|a: &i32, b: &i32| b.cmp(a)));
101//!
102//! // cmp is still available
103//! cmp.compare(&1, &2);
104//! ```
105//!
106//! ### 3. Efficient Closure Composition
107//!
108//! The `FnComparatorOps` extension trait allows direct composition on
109//! closures:
110//!
111//! ```rust
112//! use qubit_function::comparator::{Comparator, FnComparatorOps, BoxComparator};
113//! use std::cmp::Ordering;
114//!
115//! let cmp = (|a: &i32, b: &i32| a.cmp(b))
116//!     .reversed()
117//!     .then_comparing(BoxComparator::new(|a: &i32, b: &i32| b.cmp(a)));
118//!
119//! assert_eq!(cmp.compare(&5, &3), Ordering::Less);
120//! ```
121//!
122//! ## Usage Examples
123//!
124//! ### Basic Comparison
125//!
126//! ```rust
127//! use qubit_function::comparator::{Comparator, BoxComparator};
128//! use std::cmp::Ordering;
129//!
130//! let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
131//! assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
132//! ```
133//!
134//! ### Reversed Comparison
135//!
136//! ```rust
137//! use qubit_function::comparator::{Comparator, BoxComparator};
138//! use std::cmp::Ordering;
139//!
140//! let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
141//! let rev = cmp.reversed();
142//! assert_eq!(rev.compare(&5, &3), Ordering::Less);
143//! ```
144//!
145//! ### Chained Comparison
146//!
147//! ```rust
148//! use qubit_function::comparator::{Comparator, BoxComparator};
149//! use std::cmp::Ordering;
150//!
151//! #[derive(Debug)]
152//! struct Person {
153//!     name: String,
154//!     age: i32,
155//! }
156//!
157//! let by_name = BoxComparator::new(|a: &Person, b: &Person| {
158//!     a.name.cmp(&b.name)
159//! });
160//! let by_age = BoxComparator::new(|a: &Person, b: &Person| {
161//!     a.age.cmp(&b.age)
162//! });
163//! let cmp = by_name.then_comparing(by_age);
164//!
165//! let p1 = Person { name: "Alice".to_string(), age: 30 };
166//! let p2 = Person { name: "Alice".to_string(), age: 25 };
167//! assert_eq!(cmp.compare(&p1, &p2), Ordering::Greater);
168//! ```
169//!
170use std::cmp::Ordering;
171use std::rc::Rc;
172use std::sync::Arc;
173
174mod box_comparator;
175pub use box_comparator::BoxComparator;
176mod arc_comparator;
177pub use arc_comparator::ArcComparator;
178mod rc_comparator;
179pub use rc_comparator::RcComparator;
180mod fn_comparator_ops;
181pub use fn_comparator_ops::FnComparatorOps;
182
183// ==========================================================================
184// Type Aliases
185// ==========================================================================
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 qubit_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///
208pub trait Comparator<T> {
209    /// Compares two values and returns an ordering.
210    ///
211    /// # Parameters
212    ///
213    /// * `a` - The first value to compare
214    /// * `b` - The second value to compare
215    ///
216    /// # Returns
217    ///
218    /// An `Ordering` indicating whether `a` is less than, equal to, or
219    /// greater than `b`.
220    ///
221    /// # Examples
222    ///
223    /// ```rust
224    /// use qubit_function::comparator::{Comparator, BoxComparator};
225    /// use std::cmp::Ordering;
226    ///
227    /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
228    /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
229    /// assert_eq!(cmp.compare(&3, &5), Ordering::Less);
230    /// assert_eq!(cmp.compare(&5, &5), Ordering::Equal);
231    /// ```
232    fn compare(&self, a: &T, b: &T) -> Ordering;
233
234    /// Converts this comparator into a `BoxComparator`.
235    ///
236    /// # Returns
237    ///
238    /// A new `BoxComparator` wrapping this comparator.
239    ///
240    /// # Examples
241    ///
242    /// ```rust
243    /// use qubit_function::comparator::{Comparator, BoxComparator};
244    ///
245    /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
246    /// let boxed = cmp.into_box();
247    /// ```
248    #[inline]
249    fn into_box(self) -> BoxComparator<T>
250    where
251        Self: Sized + 'static,
252    {
253        BoxComparator::new(move |a, b| self.compare(a, b))
254    }
255
256    /// Converts this comparator into an `ArcComparator`.
257    ///
258    /// # Returns
259    ///
260    /// A new `ArcComparator` wrapping this comparator.
261    ///
262    /// # Examples
263    ///
264    /// ```rust
265    /// use qubit_function::comparator::{Comparator, ArcComparator};
266    ///
267    /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
268    /// let arc = cmp.into_arc();
269    /// ```
270    #[inline]
271    fn into_arc(self) -> ArcComparator<T>
272    where
273        Self: Sized + Send + Sync + 'static,
274    {
275        ArcComparator::new(move |a, b| self.compare(a, b))
276    }
277
278    /// Converts this comparator into an `RcComparator`.
279    ///
280    /// # Returns
281    ///
282    /// A new `RcComparator` wrapping this comparator.
283    ///
284    /// # Examples
285    ///
286    /// ```rust
287    /// use qubit_function::comparator::{Comparator, RcComparator};
288    ///
289    /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
290    /// let rc = cmp.into_rc();
291    /// ```
292    #[inline]
293    fn into_rc(self) -> RcComparator<T>
294    where
295        Self: Sized + 'static,
296    {
297        RcComparator::new(move |a, b| self.compare(a, b))
298    }
299
300    /// Converts this comparator into a closure that implements
301    /// `Fn(&T, &T) -> Ordering`.
302    ///
303    /// This method consumes the comparator and returns a closure that
304    /// can be used anywhere a function or closure is expected.
305    ///
306    /// # Returns
307    ///
308    /// An implementation that can be called as `Fn(&T, &T) -> Ordering`.
309    ///
310    /// # Examples
311    ///
312    /// ```rust
313    /// use qubit_function::comparator::{Comparator, BoxComparator};
314    /// use std::cmp::Ordering;
315    ///
316    /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
317    /// let func = cmp.into_fn();
318    /// assert_eq!(func(&5, &3), Ordering::Greater);
319    /// ```
320    #[inline]
321    fn into_fn(self) -> impl Fn(&T, &T) -> Ordering
322    where
323        Self: Sized + 'static,
324    {
325        move |a: &T, b: &T| self.compare(a, b)
326    }
327}
328
329/// Blanket implementation of `Comparator` for all closures and function
330/// pointers.
331///
332/// This allows any closure or function with the signature
333/// `Fn(&T, &T) -> Ordering` to be used as a comparator.
334///
335/// # Examples
336///
337/// ```rust
338/// use qubit_function::comparator::Comparator;
339/// use std::cmp::Ordering;
340///
341/// let cmp = |a: &i32, b: &i32| a.cmp(b);
342/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
343/// ```
344impl<T, F> Comparator<T> for F
345where
346    F: Fn(&T, &T) -> Ordering,
347{
348    #[inline]
349    fn compare(&self, a: &T, b: &T) -> Ordering {
350        self(a, b)
351    }
352}