Skip to main content

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