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
13#![allow(unused_imports)]
14
15use super::*;
16
17/// An Rc-based single-threaded comparator with shared ownership.
18///
19/// `RcComparator` wraps a comparator function in an `Rc`, providing
20/// single-threaded shared ownership semantics. It is cloneable and uses
21/// `&self` 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, RcComparator};
31/// use std::cmp::Ordering;
32///
33/// let cmp = RcComparator::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 RcComparator<T> {
41 pub(super) function: Rc<dyn Fn(&T, &T) -> Ordering>,
42}
43
44impl<T> RcComparator<T> {
45 /// Creates a new `RcComparator` from a closure.
46 ///
47 /// # Parameters
48 ///
49 /// * `f` - The closure to wrap
50 ///
51 /// # Returns
52 ///
53 /// A new `RcComparator` instance.
54 ///
55 /// # Examples
56 ///
57 /// ```rust
58 /// use qubit_function::comparator::RcComparator;
59 ///
60 /// let cmp = RcComparator::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 + 'static,
66 {
67 Self {
68 function: Rc::new(f),
69 }
70 }
71
72 /// Returns a comparator that imposes the reverse ordering.
73 ///
74 /// # Returns
75 ///
76 /// A new `RcComparator` that reverses the comparison order.
77 ///
78 /// # Examples
79 ///
80 /// ```rust
81 /// use qubit_function::comparator::{Comparator, RcComparator};
82 /// use std::cmp::Ordering;
83 ///
84 /// let cmp = RcComparator::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 RcComparator::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 `RcComparator` that chains this comparator with another.
108 ///
109 /// # Examples
110 ///
111 /// ```rust
112 /// use qubit_function::comparator::{Comparator, RcComparator};
113 /// use std::cmp::Ordering;
114 ///
115 /// let cmp1 = RcComparator::new(|a: &i32, b: &i32| {
116 /// (a % 2).cmp(&(b % 2))
117 /// });
118 /// let cmp2 = RcComparator::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 RcComparator::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 `RcComparator` that compares by the extracted key.
145 ///
146 /// # Examples
147 ///
148 /// ```rust
149 /// use qubit_function::comparator::{Comparator, RcComparator};
150 /// use std::cmp::Ordering;
151 ///
152 /// #[derive(Debug)]
153 /// struct Person {
154 /// name: String,
155 /// age: i32,
156 /// }
157 ///
158 /// let by_age = RcComparator::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 + 'static,
168 {
169 RcComparator::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, RcComparator};
182 /// use std::cmp::Ordering;
183 ///
184 /// let cmp = RcComparator::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 RcComparator<T> {
195 #[inline]
196 fn compare(&self, a: &T, b: &T) -> Ordering {
197 (self.function)(a, b)
198 }
199}