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