Skip to main content

qubit_function/comparator/
arc_comparator.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! Defines the `ArcComparator` public type.
10
11#![allow(unused_imports)]
12
13use super::*;
14
15/// An Arc-based thread-safe comparator with shared ownership.
16///
17/// `ArcComparator` wraps a comparator function in an `Arc`, providing
18/// thread-safe shared ownership semantics. It is cloneable and uses `&self`
19/// in composition operations.
20///
21/// # Type Parameters
22///
23/// * `T` - The type of values being compared
24///
25/// # Examples
26///
27/// ```rust
28/// use qubit_function::comparator::{Comparator, ArcComparator};
29/// use std::cmp::Ordering;
30///
31/// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
32/// let cloned = cmp.clone();
33/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
34/// assert_eq!(cloned.compare(&5, &3), Ordering::Greater);
35/// ```
36///
37/// # Author
38///
39/// Haixing Hu
40#[derive(Clone)]
41pub struct ArcComparator<T> {
42    pub(super) function: Arc<dyn Fn(&T, &T) -> Ordering + Send + Sync>,
43}
44
45impl<T> ArcComparator<T> {
46    /// Creates a new `ArcComparator` from a closure.
47    ///
48    /// # Parameters
49    ///
50    /// * `f` - The closure to wrap
51    ///
52    /// # Returns
53    ///
54    /// A new `ArcComparator` instance.
55    ///
56    /// # Examples
57    ///
58    /// ```rust
59    /// use qubit_function::comparator::ArcComparator;
60    ///
61    /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
62    /// ```
63    #[inline]
64    pub fn new<F>(f: F) -> Self
65    where
66        F: Fn(&T, &T) -> Ordering + Send + Sync + 'static,
67    {
68        Self {
69            function: Arc::new(f),
70        }
71    }
72
73    /// Returns a comparator that imposes the reverse ordering.
74    ///
75    /// # Returns
76    ///
77    /// A new `ArcComparator` that reverses the comparison order.
78    ///
79    /// # Examples
80    ///
81    /// ```rust
82    /// use qubit_function::comparator::{Comparator, ArcComparator};
83    /// use std::cmp::Ordering;
84    ///
85    /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
86    /// let rev = cmp.reversed();
87    /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
88    /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater); // cmp still works
89    /// ```
90    #[inline]
91    pub fn reversed(&self) -> Self
92    where
93        T: 'static,
94    {
95        let self_fn = self.function.clone();
96        ArcComparator::new(move |a, b| self_fn(b, a))
97    }
98
99    /// Returns a comparator that uses this comparator first, then another
100    /// comparator if this one considers the values equal.
101    ///
102    /// # Parameters
103    ///
104    /// * `other` - The comparator to use for tie-breaking
105    ///
106    /// # Returns
107    ///
108    /// A new `ArcComparator` that chains this comparator with another.
109    ///
110    /// # Examples
111    ///
112    /// ```rust
113    /// use qubit_function::comparator::{Comparator, ArcComparator};
114    /// use std::cmp::Ordering;
115    ///
116    /// let cmp1 = ArcComparator::new(|a: &i32, b: &i32| {
117    ///     (a % 2).cmp(&(b % 2))
118    /// });
119    /// let cmp2 = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
120    /// let chained = cmp1.then_comparing(&cmp2);
121    /// assert_eq!(chained.compare(&4, &2), Ordering::Greater);
122    /// ```
123    #[inline]
124    pub fn then_comparing(&self, other: &Self) -> Self
125    where
126        T: 'static,
127    {
128        let first = self.function.clone();
129        let second = other.function.clone();
130        ArcComparator::new(move |a, b| match first(a, b) {
131            Ordering::Equal => second(a, b),
132            ord => ord,
133        })
134    }
135
136    /// Returns a comparator that compares values by a key extracted by the
137    /// given function.
138    ///
139    /// # Parameters
140    ///
141    /// * `key_fn` - A function that extracts a comparable key from values
142    ///
143    /// # Returns
144    ///
145    /// A new `ArcComparator` that compares by the extracted key.
146    ///
147    /// # Examples
148    ///
149    /// ```rust
150    /// use qubit_function::comparator::{Comparator, ArcComparator};
151    /// use std::cmp::Ordering;
152    ///
153    /// #[derive(Debug)]
154    /// struct Person {
155    ///     name: String,
156    ///     age: i32,
157    /// }
158    ///
159    /// let by_age = ArcComparator::comparing(|p: &Person| &p.age);
160    /// let p1 = Person { name: "Alice".to_string(), age: 30 };
161    /// let p2 = Person { name: "Bob".to_string(), age: 25 };
162    /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
163    /// ```
164    #[inline]
165    pub fn comparing<K, F>(key_fn: F) -> Self
166    where
167        K: Ord,
168        F: Fn(&T) -> &K + Send + Sync + 'static,
169    {
170        ArcComparator::new(move |a, b| key_fn(a).cmp(key_fn(b)))
171    }
172
173    /// Converts this comparator into a closure.
174    ///
175    /// # Returns
176    ///
177    /// A closure that implements `Fn(&T, &T) -> Ordering`.
178    ///
179    /// # Examples
180    ///
181    /// ```rust
182    /// use qubit_function::comparator::{Comparator, ArcComparator};
183    /// use std::cmp::Ordering;
184    ///
185    /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
186    /// let func = cmp.into_fn();
187    /// assert_eq!(func(&5, &3), Ordering::Greater);
188    /// ```
189    #[inline]
190    pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
191        move |a: &T, b: &T| (self.function)(a, b)
192    }
193}
194
195impl<T> Comparator<T> for ArcComparator<T> {
196    #[inline]
197    fn compare(&self, a: &T, b: &T) -> Ordering {
198        (self.function)(a, b)
199    }
200}