qubit_function/comparator.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # Comparator Abstraction
10//!
11//! Provides a Rust implementation similar to Java's `Comparator` interface
12//! for comparison operations and chaining.
13//!
14//! ## Design Overview
15//!
16//! This module adopts the **Trait + Multiple Implementations** design
17//! pattern, which is the most flexible and elegant approach for
18//! implementing comparators in Rust. It achieves a perfect balance
19//! between semantic clarity, type safety, and API flexibility.
20//!
21//! ### Core Components
22//!
23//! 1. **`Comparator<T>` trait**: A minimalist unified interface that only
24//! defines the core `compare` method and type conversion methods
25//! (`into_*`). It does NOT include chaining methods like
26//! `then_comparing`, etc.
27//!
28//! 2. **Three Concrete Struct Implementations**:
29//! - [`BoxComparator<T>`]: Box-based single ownership implementation
30//! for one-time use scenarios
31//! - [`ArcComparator<T>`]: Arc-based thread-safe shared ownership
32//! implementation for multi-threaded scenarios
33//! - [`RcComparator<T>`]: Rc-based single-threaded shared ownership
34//! implementation for single-threaded reuse
35//!
36//! 3. **Specialized Composition Methods**: Each struct implements its own
37//! inherent methods (`reversed`, `then_comparing`, etc.) that return
38//! the same concrete type, preserving their specific characteristics
39//! (e.g., `ArcComparator` compositions remain `ArcComparator` and stay
40//! cloneable and thread-safe).
41//!
42//! 4. **Extension Trait for Closures**: The `FnComparatorOps<T>`
43//! extension trait provides composition methods for all closures and
44//! function pointers, returning `BoxComparator<T>` to initiate method
45//! chaining.
46//!
47//! 5. **Unified Trait Implementation**: All closures and the three
48//! structs implement the `Comparator<T>` trait, enabling them to be
49//! handled uniformly by generic functions.
50//!
51//! ## Ownership Model Coverage
52//!
53//! The three implementations correspond to three typical ownership
54//! scenarios:
55//!
56//! | Type | Ownership | Clonable | Thread-Safe | API | Use Case |
57//! |:-----|:----------|:---------|:------------|:----|:---------|
58//! | [`BoxComparator`] | Single | ❌ | ❌ | consumes `self` | One-time |
59//! | [`ArcComparator`] | Shared | ✅ | ✅ | borrows `&self` | Multi-thread |
60//! | [`RcComparator`] | Shared | ✅ | ❌ | borrows `&self` | Single-thread |
61//!
62//! ## Key Design Advantages
63//!
64//! ### 1. Type Preservation through Specialization
65//!
66//! By implementing composition methods on concrete structs rather than in
67//! the trait, each type maintains its specific characteristics through
68//! composition:
69//!
70//! ```rust
71//! use qubit_function::comparator::{Comparator, ArcComparator};
72//! use std::cmp::Ordering;
73//!
74//! let arc_cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
75//! let another = ArcComparator::new(|a: &i32, b: &i32| b.cmp(a));
76//!
77//! // Composition returns ArcComparator, preserving clonability and
78//! // thread-safety
79//! let combined = arc_cmp.then_comparing(&another);
80//! let cloned = combined.clone(); // ✅ Still cloneable
81//!
82//! // Original comparators remain usable
83//! assert_eq!(arc_cmp.compare(&5, &3), Ordering::Greater);
84//! ```
85//!
86//! ### 2. Elegant API without Explicit Cloning
87//!
88//! `ArcComparator` and `RcComparator` use `&self` in their composition
89//! methods, providing a natural experience without requiring explicit
90//! `.clone()` calls:
91//!
92//! ```rust
93//! use qubit_function::comparator::{Comparator, ArcComparator};
94//!
95//! let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
96//!
97//! // No need for explicit clone()
98//! let reversed = cmp.reversed();
99//! let chained = cmp.then_comparing(&ArcComparator::new(|a, b| b.cmp(a)));
100//!
101//! // cmp is still available
102//! cmp.compare(&1, &2);
103//! ```
104//!
105//! ### 3. Efficient Closure Composition
106//!
107//! The `FnComparatorOps` extension trait allows direct composition on
108//! closures:
109//!
110//! ```rust
111//! use qubit_function::comparator::{Comparator, FnComparatorOps};
112//! use std::cmp::Ordering;
113//!
114//! let cmp = (|a: &i32, b: &i32| a.cmp(b))
115//! .reversed()
116//! .then_comparing(|a: &i32, b: &i32| b.cmp(a));
117//!
118//! assert_eq!(cmp.compare(&5, &3), Ordering::Less);
119//! ```
120//!
121//! ## Usage Examples
122//!
123//! ### Basic Comparison
124//!
125//! ```rust
126//! use qubit_function::comparator::{Comparator, BoxComparator};
127//! use std::cmp::Ordering;
128//!
129//! let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
130//! assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
131//! ```
132//!
133//! ### Reversed Comparison
134//!
135//! ```rust
136//! use qubit_function::comparator::{Comparator, BoxComparator};
137//! use std::cmp::Ordering;
138//!
139//! let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
140//! let rev = cmp.reversed();
141//! assert_eq!(rev.compare(&5, &3), Ordering::Less);
142//! ```
143//!
144//! ### Chained Comparison
145//!
146//! ```rust
147//! use qubit_function::comparator::{Comparator, BoxComparator};
148//! use std::cmp::Ordering;
149//!
150//! #[derive(Debug)]
151//! struct Person {
152//! name: String,
153//! age: i32,
154//! }
155//!
156//! let by_name = BoxComparator::new(|a: &Person, b: &Person| {
157//! a.name.cmp(&b.name)
158//! });
159//! let by_age = BoxComparator::new(|a: &Person, b: &Person| {
160//! a.age.cmp(&b.age)
161//! });
162//! let cmp = by_name.then_comparing(by_age);
163//!
164//! let p1 = Person { name: "Alice".to_string(), age: 30 };
165//! let p2 = Person { name: "Alice".to_string(), age: 25 };
166//! assert_eq!(cmp.compare(&p1, &p2), Ordering::Greater);
167//! ```
168//!
169//! ## Author
170//!
171//! Haixing Hu
172use std::cmp::Ordering;
173use std::rc::Rc;
174use std::sync::Arc;
175
176// ==========================================================================
177// Type Aliases
178// ==========================================================================
179
180/// A trait for comparison operations.
181///
182/// This trait defines the core comparison operation and conversion methods.
183/// It does NOT include composition methods like `reversed` or
184/// `then_comparing` to maintain a clean separation between the trait
185/// interface and specialized implementations.
186///
187/// # Type Parameters
188///
189/// * `T` - The type of values being compared
190///
191/// # Examples
192///
193/// ```rust
194/// use qubit_function::comparator::{Comparator, BoxComparator};
195/// use std::cmp::Ordering;
196///
197/// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
198/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
199/// ```
200///
201/// # Author
202///
203/// Haixing Hu
204pub trait Comparator<T> {
205 /// Compares two values and returns an ordering.
206 ///
207 /// # Parameters
208 ///
209 /// * `a` - The first value to compare
210 /// * `b` - The second value to compare
211 ///
212 /// # Returns
213 ///
214 /// An `Ordering` indicating whether `a` is less than, equal to, or
215 /// greater than `b`.
216 ///
217 /// # Examples
218 ///
219 /// ```rust
220 /// use qubit_function::comparator::{Comparator, BoxComparator};
221 /// use std::cmp::Ordering;
222 ///
223 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
224 /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
225 /// assert_eq!(cmp.compare(&3, &5), Ordering::Less);
226 /// assert_eq!(cmp.compare(&5, &5), Ordering::Equal);
227 /// ```
228 fn compare(&self, a: &T, b: &T) -> Ordering;
229
230 /// Converts this comparator into a `BoxComparator`.
231 ///
232 /// # Returns
233 ///
234 /// A new `BoxComparator` wrapping this comparator.
235 ///
236 /// # Examples
237 ///
238 /// ```rust
239 /// use qubit_function::comparator::{Comparator, BoxComparator};
240 ///
241 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
242 /// let boxed = cmp.into_box();
243 /// ```
244 #[inline]
245 fn into_box(self) -> BoxComparator<T>
246 where
247 Self: Sized + 'static,
248 T: 'static,
249 {
250 BoxComparator::new(move |a, b| self.compare(a, b))
251 }
252
253 /// Converts this comparator into an `ArcComparator`.
254 ///
255 /// # Returns
256 ///
257 /// A new `ArcComparator` wrapping this comparator.
258 ///
259 /// # Examples
260 ///
261 /// ```rust
262 /// use qubit_function::comparator::{Comparator, ArcComparator};
263 ///
264 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
265 /// let arc = cmp.into_arc();
266 /// ```
267 #[inline]
268 fn into_arc(self) -> ArcComparator<T>
269 where
270 Self: Sized + Send + Sync + 'static,
271 T: 'static,
272 {
273 ArcComparator::new(move |a, b| self.compare(a, b))
274 }
275
276 /// Converts this comparator into an `RcComparator`.
277 ///
278 /// # Returns
279 ///
280 /// A new `RcComparator` wrapping this comparator.
281 ///
282 /// # Examples
283 ///
284 /// ```rust
285 /// use qubit_function::comparator::{Comparator, RcComparator};
286 ///
287 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
288 /// let rc = cmp.into_rc();
289 /// ```
290 #[inline]
291 fn into_rc(self) -> RcComparator<T>
292 where
293 Self: Sized + 'static,
294 T: 'static,
295 {
296 RcComparator::new(move |a, b| self.compare(a, b))
297 }
298
299 /// Converts this comparator into a closure that implements
300 /// `Fn(&T, &T) -> Ordering`.
301 ///
302 /// This method consumes the comparator and returns a closure that
303 /// can be used anywhere a function or closure is expected.
304 ///
305 /// # Returns
306 ///
307 /// An implementation that can be called as `Fn(&T, &T) -> Ordering`.
308 ///
309 /// # Examples
310 ///
311 /// ```rust
312 /// use qubit_function::comparator::{Comparator, BoxComparator};
313 /// use std::cmp::Ordering;
314 ///
315 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
316 /// let func = cmp.into_fn();
317 /// assert_eq!(func(&5, &3), Ordering::Greater);
318 /// ```
319 #[inline]
320 fn into_fn(self) -> impl Fn(&T, &T) -> Ordering
321 where
322 Self: Sized + 'static,
323 T: 'static,
324 {
325 move |a: &T, b: &T| self.compare(a, b)
326 }
327}
328
329/// Blanket implementation of `Comparator` for all closures and function
330/// pointers.
331///
332/// This allows any closure or function with the signature
333/// `Fn(&T, &T) -> Ordering` to be used as a comparator.
334///
335/// # Examples
336///
337/// ```rust
338/// use qubit_function::comparator::Comparator;
339/// use std::cmp::Ordering;
340///
341/// let cmp = |a: &i32, b: &i32| a.cmp(b);
342/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
343/// ```
344impl<T, F> Comparator<T> for F
345where
346 F: Fn(&T, &T) -> Ordering,
347{
348 #[inline]
349 fn compare(&self, a: &T, b: &T) -> Ordering {
350 self(a, b)
351 }
352}
353
354/// A boxed comparator with single ownership.
355///
356/// `BoxComparator` wraps a comparator function in a `Box`, providing single
357/// ownership semantics. It is not cloneable and consumes `self` in
358/// composition operations.
359///
360/// # Type Parameters
361///
362/// * `T` - The type of values being compared
363///
364/// # Examples
365///
366/// ```rust
367/// use qubit_function::comparator::{Comparator, BoxComparator};
368/// use std::cmp::Ordering;
369///
370/// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
371/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
372/// ```
373///
374/// # Author
375///
376/// Haixing Hu
377pub struct BoxComparator<T> {
378 function: Box<dyn Fn(&T, &T) -> Ordering>,
379}
380
381impl<T: 'static> BoxComparator<T> {
382 /// Creates a new `BoxComparator` from a closure.
383 ///
384 /// # Parameters
385 ///
386 /// * `f` - The closure to wrap
387 ///
388 /// # Returns
389 ///
390 /// A new `BoxComparator` instance.
391 ///
392 /// # Examples
393 ///
394 /// ```rust
395 /// use qubit_function::comparator::BoxComparator;
396 ///
397 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
398 /// ```
399 #[inline]
400 pub fn new<F>(f: F) -> Self
401 where
402 F: Fn(&T, &T) -> Ordering + 'static,
403 {
404 Self {
405 function: Box::new(f),
406 }
407 }
408
409 /// Returns a comparator that imposes the reverse ordering.
410 ///
411 /// # Returns
412 ///
413 /// A new `BoxComparator` that reverses the comparison order.
414 ///
415 /// # Examples
416 ///
417 /// ```rust
418 /// use qubit_function::comparator::{Comparator, BoxComparator};
419 /// use std::cmp::Ordering;
420 ///
421 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
422 /// let rev = cmp.reversed();
423 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
424 /// ```
425 #[inline]
426 pub fn reversed(self) -> Self {
427 BoxComparator::new(move |a, b| (self.function)(b, a))
428 }
429
430 /// Returns a comparator that uses this comparator first, then another
431 /// comparator if this one considers the values equal.
432 ///
433 /// # Parameters
434 ///
435 /// * `other` - The comparator to use for tie-breaking. **Note: This
436 /// parameter is passed by value and will transfer ownership.** If you
437 /// need to preserve the original comparator, clone it first (if it
438 /// implements `Clone`). Can be:
439 /// - A `BoxComparator<T>`
440 /// - An `RcComparator<T>`
441 /// - An `ArcComparator<T>`
442 /// - Any type implementing `Comparator<T>`
443 ///
444 /// # Returns
445 ///
446 /// A new `BoxComparator` that chains this comparator with another.
447 ///
448 /// # Examples
449 ///
450 /// ```rust
451 /// use qubit_function::comparator::{Comparator, BoxComparator};
452 /// use std::cmp::Ordering;
453 ///
454 /// #[derive(Debug)]
455 /// struct Person {
456 /// name: String,
457 /// age: i32,
458 /// }
459 ///
460 /// let by_name = BoxComparator::new(|a: &Person, b: &Person| {
461 /// a.name.cmp(&b.name)
462 /// });
463 /// let by_age = BoxComparator::new(|a: &Person, b: &Person| {
464 /// a.age.cmp(&b.age)
465 /// });
466 ///
467 /// // by_age is moved here
468 /// let cmp = by_name.then_comparing(by_age);
469 ///
470 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
471 /// let p2 = Person { name: "Alice".to_string(), age: 25 };
472 /// assert_eq!(cmp.compare(&p1, &p2), Ordering::Greater);
473 /// // by_age.compare(&p1, &p2); // Would not compile - moved
474 /// ```
475 #[inline]
476 pub fn then_comparing(self, other: Self) -> Self {
477 BoxComparator::new(move |a, b| match (self.function)(a, b) {
478 Ordering::Equal => (other.function)(a, b),
479 ord => ord,
480 })
481 }
482
483 /// Returns a comparator that compares values by a key extracted by the
484 /// given function.
485 ///
486 /// # Parameters
487 ///
488 /// * `key_fn` - A function that extracts a comparable key from values
489 ///
490 /// # Returns
491 ///
492 /// A new `BoxComparator` that compares by the extracted key.
493 ///
494 /// # Examples
495 ///
496 /// ```rust
497 /// use qubit_function::comparator::{Comparator, BoxComparator};
498 /// use std::cmp::Ordering;
499 ///
500 /// #[derive(Debug)]
501 /// struct Person {
502 /// name: String,
503 /// age: i32,
504 /// }
505 ///
506 /// let by_age = BoxComparator::comparing(|p: &Person| &p.age);
507 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
508 /// let p2 = Person { name: "Bob".to_string(), age: 25 };
509 /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
510 /// ```
511 #[inline]
512 pub fn comparing<K, F>(key_fn: F) -> Self
513 where
514 K: Ord,
515 F: Fn(&T) -> &K + 'static,
516 {
517 BoxComparator::new(move |a: &T, b: &T| key_fn(a).cmp(key_fn(b)))
518 }
519
520 /// Converts this comparator into a closure.
521 ///
522 /// # Returns
523 ///
524 /// A closure that implements `Fn(&T, &T) -> Ordering`.
525 ///
526 /// # Examples
527 ///
528 /// ```rust
529 /// use qubit_function::comparator::{Comparator, BoxComparator};
530 /// use std::cmp::Ordering;
531 ///
532 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
533 /// let func = cmp.into_fn();
534 /// assert_eq!(func(&5, &3), Ordering::Greater);
535 /// ```
536 #[inline]
537 pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
538 move |a: &T, b: &T| (self.function)(a, b)
539 }
540}
541
542impl<T> Comparator<T> for BoxComparator<T> {
543 #[inline]
544 fn compare(&self, a: &T, b: &T) -> Ordering {
545 (self.function)(a, b)
546 }
547}
548
549/// An Arc-based thread-safe comparator with shared ownership.
550///
551/// `ArcComparator` wraps a comparator function in an `Arc`, providing
552/// thread-safe shared ownership semantics. It is cloneable and uses `&self`
553/// in composition operations.
554///
555/// # Type Parameters
556///
557/// * `T` - The type of values being compared
558///
559/// # Examples
560///
561/// ```rust
562/// use qubit_function::comparator::{Comparator, ArcComparator};
563/// use std::cmp::Ordering;
564///
565/// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
566/// let cloned = cmp.clone();
567/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
568/// assert_eq!(cloned.compare(&5, &3), Ordering::Greater);
569/// ```
570///
571/// # Author
572///
573/// Haixing Hu
574#[derive(Clone)]
575pub struct ArcComparator<T> {
576 function: Arc<dyn Fn(&T, &T) -> Ordering + Send + Sync>,
577}
578
579impl<T: 'static> ArcComparator<T> {
580 /// Creates a new `ArcComparator` from a closure.
581 ///
582 /// # Parameters
583 ///
584 /// * `f` - The closure to wrap
585 ///
586 /// # Returns
587 ///
588 /// A new `ArcComparator` instance.
589 ///
590 /// # Examples
591 ///
592 /// ```rust
593 /// use qubit_function::comparator::ArcComparator;
594 ///
595 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
596 /// ```
597 #[inline]
598 pub fn new<F>(f: F) -> Self
599 where
600 F: Fn(&T, &T) -> Ordering + Send + Sync + 'static,
601 {
602 Self {
603 function: Arc::new(f),
604 }
605 }
606
607 /// Returns a comparator that imposes the reverse ordering.
608 ///
609 /// # Returns
610 ///
611 /// A new `ArcComparator` that reverses the comparison order.
612 ///
613 /// # Examples
614 ///
615 /// ```rust
616 /// use qubit_function::comparator::{Comparator, ArcComparator};
617 /// use std::cmp::Ordering;
618 ///
619 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
620 /// let rev = cmp.reversed();
621 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
622 /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater); // cmp still works
623 /// ```
624 #[inline]
625 pub fn reversed(&self) -> Self {
626 let self_fn = self.function.clone();
627 ArcComparator::new(move |a, b| self_fn(b, a))
628 }
629
630 /// Returns a comparator that uses this comparator first, then another
631 /// comparator if this one considers the values equal.
632 ///
633 /// # Parameters
634 ///
635 /// * `other` - The comparator to use for tie-breaking
636 ///
637 /// # Returns
638 ///
639 /// A new `ArcComparator` that chains this comparator with another.
640 ///
641 /// # Examples
642 ///
643 /// ```rust
644 /// use qubit_function::comparator::{Comparator, ArcComparator};
645 /// use std::cmp::Ordering;
646 ///
647 /// let cmp1 = ArcComparator::new(|a: &i32, b: &i32| {
648 /// (a % 2).cmp(&(b % 2))
649 /// });
650 /// let cmp2 = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
651 /// let chained = cmp1.then_comparing(&cmp2);
652 /// assert_eq!(chained.compare(&4, &2), Ordering::Greater);
653 /// ```
654 #[inline]
655 pub fn then_comparing(&self, other: &Self) -> Self {
656 let first = self.function.clone();
657 let second = other.function.clone();
658 ArcComparator::new(move |a, b| match first(a, b) {
659 Ordering::Equal => second(a, b),
660 ord => ord,
661 })
662 }
663
664 /// Returns a comparator that compares values by a key extracted by the
665 /// given function.
666 ///
667 /// # Parameters
668 ///
669 /// * `key_fn` - A function that extracts a comparable key from values
670 ///
671 /// # Returns
672 ///
673 /// A new `ArcComparator` that compares by the extracted key.
674 ///
675 /// # Examples
676 ///
677 /// ```rust
678 /// use qubit_function::comparator::{Comparator, ArcComparator};
679 /// use std::cmp::Ordering;
680 ///
681 /// #[derive(Debug)]
682 /// struct Person {
683 /// name: String,
684 /// age: i32,
685 /// }
686 ///
687 /// let by_age = ArcComparator::comparing(|p: &Person| &p.age);
688 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
689 /// let p2 = Person { name: "Bob".to_string(), age: 25 };
690 /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
691 /// ```
692 #[inline]
693 pub fn comparing<K, F>(key_fn: F) -> Self
694 where
695 K: Ord,
696 F: Fn(&T) -> &K + Send + Sync + 'static,
697 {
698 ArcComparator::new(move |a, b| key_fn(a).cmp(key_fn(b)))
699 }
700
701 /// Converts this comparator into a closure.
702 ///
703 /// # Returns
704 ///
705 /// A closure that implements `Fn(&T, &T) -> Ordering`.
706 ///
707 /// # Examples
708 ///
709 /// ```rust
710 /// use qubit_function::comparator::{Comparator, ArcComparator};
711 /// use std::cmp::Ordering;
712 ///
713 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
714 /// let func = cmp.into_fn();
715 /// assert_eq!(func(&5, &3), Ordering::Greater);
716 /// ```
717 #[inline]
718 pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
719 move |a: &T, b: &T| (self.function)(a, b)
720 }
721}
722
723impl<T> Comparator<T> for ArcComparator<T> {
724 #[inline]
725 fn compare(&self, a: &T, b: &T) -> Ordering {
726 (self.function)(a, b)
727 }
728}
729
730/// An Rc-based single-threaded comparator with shared ownership.
731///
732/// `RcComparator` wraps a comparator function in an `Rc`, providing
733/// single-threaded shared ownership semantics. It is cloneable and uses
734/// `&self` in composition operations.
735///
736/// # Type Parameters
737///
738/// * `T` - The type of values being compared
739///
740/// # Examples
741///
742/// ```rust
743/// use qubit_function::comparator::{Comparator, RcComparator};
744/// use std::cmp::Ordering;
745///
746/// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
747/// let cloned = cmp.clone();
748/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
749/// assert_eq!(cloned.compare(&5, &3), Ordering::Greater);
750/// ```
751///
752/// # Author
753///
754/// Haixing Hu
755#[derive(Clone)]
756pub struct RcComparator<T> {
757 function: Rc<dyn Fn(&T, &T) -> Ordering>,
758}
759
760impl<T: 'static> RcComparator<T> {
761 /// Creates a new `RcComparator` from a closure.
762 ///
763 /// # Parameters
764 ///
765 /// * `f` - The closure to wrap
766 ///
767 /// # Returns
768 ///
769 /// A new `RcComparator` instance.
770 ///
771 /// # Examples
772 ///
773 /// ```rust
774 /// use qubit_function::comparator::RcComparator;
775 ///
776 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
777 /// ```
778 #[inline]
779 pub fn new<F>(f: F) -> Self
780 where
781 F: Fn(&T, &T) -> Ordering + 'static,
782 {
783 Self {
784 function: Rc::new(f),
785 }
786 }
787
788 /// Returns a comparator that imposes the reverse ordering.
789 ///
790 /// # Returns
791 ///
792 /// A new `RcComparator` that reverses the comparison order.
793 ///
794 /// # Examples
795 ///
796 /// ```rust
797 /// use qubit_function::comparator::{Comparator, RcComparator};
798 /// use std::cmp::Ordering;
799 ///
800 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
801 /// let rev = cmp.reversed();
802 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
803 /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater); // cmp still works
804 /// ```
805 #[inline]
806 pub fn reversed(&self) -> Self {
807 let self_fn = self.function.clone();
808 RcComparator::new(move |a, b| self_fn(b, a))
809 }
810
811 /// Returns a comparator that uses this comparator first, then another
812 /// comparator if this one considers the values equal.
813 ///
814 /// # Parameters
815 ///
816 /// * `other` - The comparator to use for tie-breaking
817 ///
818 /// # Returns
819 ///
820 /// A new `RcComparator` that chains this comparator with another.
821 ///
822 /// # Examples
823 ///
824 /// ```rust
825 /// use qubit_function::comparator::{Comparator, RcComparator};
826 /// use std::cmp::Ordering;
827 ///
828 /// let cmp1 = RcComparator::new(|a: &i32, b: &i32| {
829 /// (a % 2).cmp(&(b % 2))
830 /// });
831 /// let cmp2 = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
832 /// let chained = cmp1.then_comparing(&cmp2);
833 /// assert_eq!(chained.compare(&4, &2), Ordering::Greater);
834 /// ```
835 #[inline]
836 pub fn then_comparing(&self, other: &Self) -> Self {
837 let first = self.function.clone();
838 let second = other.function.clone();
839 RcComparator::new(move |a, b| match first(a, b) {
840 Ordering::Equal => second(a, b),
841 ord => ord,
842 })
843 }
844
845 /// Returns a comparator that compares values by a key extracted by the
846 /// given function.
847 ///
848 /// # Parameters
849 ///
850 /// * `key_fn` - A function that extracts a comparable key from values
851 ///
852 /// # Returns
853 ///
854 /// A new `RcComparator` that compares by the extracted key.
855 ///
856 /// # Examples
857 ///
858 /// ```rust
859 /// use qubit_function::comparator::{Comparator, RcComparator};
860 /// use std::cmp::Ordering;
861 ///
862 /// #[derive(Debug)]
863 /// struct Person {
864 /// name: String,
865 /// age: i32,
866 /// }
867 ///
868 /// let by_age = RcComparator::comparing(|p: &Person| &p.age);
869 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
870 /// let p2 = Person { name: "Bob".to_string(), age: 25 };
871 /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
872 /// ```
873 #[inline]
874 pub fn comparing<K, F>(key_fn: F) -> Self
875 where
876 K: Ord,
877 F: Fn(&T) -> &K + 'static,
878 {
879 RcComparator::new(move |a, b| key_fn(a).cmp(key_fn(b)))
880 }
881
882 /// Converts this comparator into a closure.
883 ///
884 /// # Returns
885 ///
886 /// A closure that implements `Fn(&T, &T) -> Ordering`.
887 ///
888 /// # Examples
889 ///
890 /// ```rust
891 /// use qubit_function::comparator::{Comparator, RcComparator};
892 /// use std::cmp::Ordering;
893 ///
894 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
895 /// let func = cmp.into_fn();
896 /// assert_eq!(func(&5, &3), Ordering::Greater);
897 /// ```
898 #[inline]
899 pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
900 move |a: &T, b: &T| (self.function)(a, b)
901 }
902}
903
904impl<T> Comparator<T> for RcComparator<T> {
905 #[inline]
906 fn compare(&self, a: &T, b: &T) -> Ordering {
907 (self.function)(a, b)
908 }
909}
910
911/// Extension trait providing composition methods for closures and function
912/// pointers.
913///
914/// This trait is automatically implemented for all closures and function
915/// pointers with the signature `Fn(&T, &T) -> Ordering`, allowing them to
916/// be composed directly without explicit wrapping.
917///
918/// # Examples
919///
920/// ```rust
921/// use qubit_function::comparator::{Comparator, FnComparatorOps};
922/// use std::cmp::Ordering;
923///
924/// let cmp = (|a: &i32, b: &i32| a.cmp(b))
925/// .reversed()
926/// .then_comparing(BoxComparator::new(|a, b| b.cmp(a)));
927///
928/// assert_eq!(cmp.compare(&5, &3), Ordering::Less);
929/// ```
930///
931/// # Author
932///
933/// Haixing Hu
934pub trait FnComparatorOps<T>: Fn(&T, &T) -> Ordering + Sized {
935 /// Returns a comparator that imposes the reverse ordering.
936 ///
937 /// # Returns
938 ///
939 /// A new `BoxComparator` that reverses the comparison order.
940 ///
941 /// # Examples
942 ///
943 /// ```rust
944 /// use qubit_function::comparator::{Comparator, FnComparatorOps};
945 /// use std::cmp::Ordering;
946 ///
947 /// let rev = (|a: &i32, b: &i32| a.cmp(b)).reversed();
948 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
949 /// ```
950 #[inline]
951 fn reversed(self) -> BoxComparator<T>
952 where
953 Self: 'static,
954 T: 'static,
955 {
956 BoxComparator::new(self).reversed()
957 }
958
959 /// Returns a comparator that uses this comparator first, then another
960 /// comparator if this one considers the values equal.
961 ///
962 /// # Parameters
963 ///
964 /// * `other` - The comparator to use for tie-breaking
965 ///
966 /// # Returns
967 ///
968 /// A new `BoxComparator` that chains this comparator with another.
969 ///
970 /// # Examples
971 ///
972 /// ```rust
973 /// use qubit_function::comparator::{Comparator, FnComparatorOps,
974 /// BoxComparator};
975 /// use std::cmp::Ordering;
976 ///
977 /// let cmp = (|a: &i32, b: &i32| (a % 2).cmp(&(b % 2)))
978 /// .then_comparing(BoxComparator::new(|a, b| a.cmp(b)));
979 /// assert_eq!(cmp.compare(&4, &2), Ordering::Greater);
980 /// ```
981 #[inline]
982 fn then_comparing(self, other: BoxComparator<T>) -> BoxComparator<T>
983 where
984 Self: 'static,
985 T: 'static,
986 {
987 BoxComparator::new(self).then_comparing(other)
988 }
989}
990
991impl<T, F> FnComparatorOps<T> for F where F: Fn(&T, &T) -> Ordering {}