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 { function: Arc::new(f) }
72 }
73
74 /// Returns a comparator that imposes the reverse ordering.
75 ///
76 /// # Returns
77 ///
78 /// A new `ArcComparator` that reverses the comparison order.
79 ///
80 /// # Examples
81 ///
82 /// ```rust
83 /// use qubit_function::comparator::{Comparator, ArcComparator};
84 /// use std::cmp::Ordering;
85 ///
86 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
87 /// let rev = cmp.reversed();
88 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
89 /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater); // cmp still works
90 /// ```
91 #[inline]
92 pub fn reversed(&self) -> Self
93 where
94 T: 'static,
95 {
96 let self_fn = self.function.clone();
97 ArcComparator::new(move |a, b| self_fn(b, a))
98 }
99
100 /// Returns a comparator that uses this comparator first, then another
101 /// comparator if this one considers the values equal.
102 ///
103 /// # Parameters
104 ///
105 /// * `other` - The comparator to use for tie-breaking
106 ///
107 /// # Returns
108 ///
109 /// A new `ArcComparator` that chains this comparator with another.
110 ///
111 /// # Examples
112 ///
113 /// ```rust
114 /// use qubit_function::comparator::{Comparator, ArcComparator};
115 /// use std::cmp::Ordering;
116 ///
117 /// let cmp1 = ArcComparator::new(|a: &i32, b: &i32| {
118 /// (a % 2).cmp(&(b % 2))
119 /// });
120 /// let cmp2 = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
121 /// let chained = cmp1.then_comparing(&cmp2);
122 /// assert_eq!(chained.compare(&4, &2), Ordering::Greater);
123 /// ```
124 #[inline]
125 pub fn then_comparing(&self, other: &Self) -> Self
126 where
127 T: 'static,
128 {
129 let first = self.function.clone();
130 let second = other.function.clone();
131 ArcComparator::new(move |a, b| match first(a, b) {
132 Ordering::Equal => second(a, b),
133 ord => ord,
134 })
135 }
136
137 /// Returns a comparator that compares values by a key extracted by the
138 /// given function.
139 ///
140 /// # Parameters
141 ///
142 /// * `key_fn` - A function that extracts a comparable key from values
143 ///
144 /// # Returns
145 ///
146 /// A new `ArcComparator` that compares by the extracted key.
147 ///
148 /// # Examples
149 ///
150 /// ```rust
151 /// use qubit_function::comparator::{Comparator, ArcComparator};
152 /// use std::cmp::Ordering;
153 ///
154 /// #[derive(Debug)]
155 /// struct Person {
156 /// name: String,
157 /// age: i32,
158 /// }
159 ///
160 /// let by_age = ArcComparator::comparing(|p: &Person| &p.age);
161 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
162 /// let p2 = Person { name: "Bob".to_string(), age: 25 };
163 /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
164 /// ```
165 #[inline]
166 pub fn comparing<K, F>(key_fn: F) -> Self
167 where
168 K: Ord,
169 F: Fn(&T) -> &K + Send + Sync + 'static,
170 {
171 ArcComparator::new(move |a, b| key_fn(a).cmp(key_fn(b)))
172 }
173
174 /// Converts this comparator into a closure.
175 ///
176 /// # Returns
177 ///
178 /// A closure that implements `Fn(&T, &T) -> Ordering`.
179 ///
180 /// # Examples
181 ///
182 /// ```rust
183 /// use qubit_function::comparator::{Comparator, ArcComparator};
184 /// use std::cmp::Ordering;
185 ///
186 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
187 /// let func = cmp.into_fn();
188 /// assert_eq!(func(&5, &3), Ordering::Greater);
189 /// ```
190 #[inline]
191 pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
192 move |a: &T, b: &T| (self.function)(a, b)
193 }
194}
195
196impl<T> Comparator<T> for ArcComparator<T> {
197 #[inline]
198 fn compare(&self, a: &T, b: &T) -> Ordering {
199 (self.function)(a, b)
200 }
201}