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 {}