qubit_function/comparator/rc_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 `RcComparator` public type.
12
13use super::{
14 Comparator,
15 Ordering,
16 Rc,
17};
18
19type RcComparatorFn<T> = Rc<dyn Fn(&T, &T) -> Ordering>;
20
21/// An Rc-based single-threaded comparator with shared ownership.
22///
23/// `RcComparator` wraps a comparator function in an `Rc`, providing
24/// single-threaded shared ownership semantics. It is cloneable and uses
25/// `&self` 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, RcComparator};
35/// use std::cmp::Ordering;
36///
37/// let cmp = RcComparator::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 RcComparator<T> {
45 pub(super) function: RcComparatorFn<T>,
46}
47
48impl<T> RcComparator<T> {
49 /// Creates a new `RcComparator` from a closure.
50 ///
51 /// # Parameters
52 ///
53 /// * `f` - The closure to wrap
54 ///
55 /// # Returns
56 ///
57 /// A new `RcComparator` instance.
58 ///
59 /// # Examples
60 ///
61 /// ```rust
62 /// use qubit_function::comparator::RcComparator;
63 ///
64 /// let cmp = RcComparator::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 + 'static,
70 {
71 Self {
72 function: Rc::new(f),
73 }
74 }
75
76 /// Returns a comparator that imposes the reverse ordering.
77 ///
78 /// # Returns
79 ///
80 /// A new `RcComparator` that reverses the comparison order.
81 ///
82 /// # Examples
83 ///
84 /// ```rust
85 /// use qubit_function::comparator::{Comparator, RcComparator};
86 /// use std::cmp::Ordering;
87 ///
88 /// let cmp = RcComparator::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 RcComparator::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 `RcComparator` that chains this comparator with another.
112 ///
113 /// # Examples
114 ///
115 /// ```rust
116 /// use qubit_function::comparator::{Comparator, RcComparator};
117 /// use std::cmp::Ordering;
118 ///
119 /// let cmp1 = RcComparator::new(|a: &i32, b: &i32| {
120 /// (a % 2).cmp(&(b % 2))
121 /// });
122 /// let cmp2 = RcComparator::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 RcComparator::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 `RcComparator` that compares by the extracted key.
149 ///
150 /// # Examples
151 ///
152 /// ```rust
153 /// use qubit_function::comparator::{Comparator, RcComparator};
154 /// use std::cmp::Ordering;
155 ///
156 /// #[derive(Debug)]
157 /// struct Person {
158 /// name: String,
159 /// age: i32,
160 /// }
161 ///
162 /// let by_age = RcComparator::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 + 'static,
172 {
173 RcComparator::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, RcComparator};
186 /// use std::cmp::Ordering;
187 ///
188 /// let cmp = RcComparator::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 RcComparator<T> {
199 #[inline]
200 fn compare(&self, a: &T, b: &T) -> Ordering {
201 (self.function)(a, b)
202 }
203}