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 {
249 BoxComparator::new(move |a, b| self.compare(a, b))
250 }
251
252 /// Converts this comparator into an `ArcComparator`.
253 ///
254 /// # Returns
255 ///
256 /// A new `ArcComparator` wrapping this comparator.
257 ///
258 /// # Examples
259 ///
260 /// ```rust
261 /// use qubit_function::comparator::{Comparator, ArcComparator};
262 ///
263 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
264 /// let arc = cmp.into_arc();
265 /// ```
266 #[inline]
267 fn into_arc(self) -> ArcComparator<T>
268 where
269 Self: Sized + Send + Sync + 'static,
270 {
271 ArcComparator::new(move |a, b| self.compare(a, b))
272 }
273
274 /// Converts this comparator into an `RcComparator`.
275 ///
276 /// # Returns
277 ///
278 /// A new `RcComparator` wrapping this comparator.
279 ///
280 /// # Examples
281 ///
282 /// ```rust
283 /// use qubit_function::comparator::{Comparator, RcComparator};
284 ///
285 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
286 /// let rc = cmp.into_rc();
287 /// ```
288 #[inline]
289 fn into_rc(self) -> RcComparator<T>
290 where
291 Self: Sized + 'static,
292 {
293 RcComparator::new(move |a, b| self.compare(a, b))
294 }
295
296 /// Converts this comparator into a closure that implements
297 /// `Fn(&T, &T) -> Ordering`.
298 ///
299 /// This method consumes the comparator and returns a closure that
300 /// can be used anywhere a function or closure is expected.
301 ///
302 /// # Returns
303 ///
304 /// An implementation that can be called as `Fn(&T, &T) -> Ordering`.
305 ///
306 /// # Examples
307 ///
308 /// ```rust
309 /// use qubit_function::comparator::{Comparator, BoxComparator};
310 /// use std::cmp::Ordering;
311 ///
312 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
313 /// let func = cmp.into_fn();
314 /// assert_eq!(func(&5, &3), Ordering::Greater);
315 /// ```
316 #[inline]
317 fn into_fn(self) -> impl Fn(&T, &T) -> Ordering
318 where
319 Self: Sized + 'static,
320 {
321 move |a: &T, b: &T| self.compare(a, b)
322 }
323}
324
325/// Blanket implementation of `Comparator` for all closures and function
326/// pointers.
327///
328/// This allows any closure or function with the signature
329/// `Fn(&T, &T) -> Ordering` to be used as a comparator.
330///
331/// # Examples
332///
333/// ```rust
334/// use qubit_function::comparator::Comparator;
335/// use std::cmp::Ordering;
336///
337/// let cmp = |a: &i32, b: &i32| a.cmp(b);
338/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
339/// ```
340impl<T, F> Comparator<T> for F
341where
342 F: Fn(&T, &T) -> Ordering,
343{
344 #[inline]
345 fn compare(&self, a: &T, b: &T) -> Ordering {
346 self(a, b)
347 }
348}
349
350/// A boxed comparator with single ownership.
351///
352/// `BoxComparator` wraps a comparator function in a `Box`, providing single
353/// ownership semantics. It is not cloneable and consumes `self` in
354/// composition operations.
355///
356/// # Type Parameters
357///
358/// * `T` - The type of values being compared
359///
360/// # Examples
361///
362/// ```rust
363/// use qubit_function::comparator::{Comparator, BoxComparator};
364/// use std::cmp::Ordering;
365///
366/// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
367/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
368/// ```
369///
370/// # Author
371///
372/// Haixing Hu
373pub struct BoxComparator<T> {
374 function: Box<dyn Fn(&T, &T) -> Ordering>,
375}
376
377impl<T> BoxComparator<T> {
378 /// Creates a new `BoxComparator` from a closure.
379 ///
380 /// # Parameters
381 ///
382 /// * `f` - The closure to wrap
383 ///
384 /// # Returns
385 ///
386 /// A new `BoxComparator` instance.
387 ///
388 /// # Examples
389 ///
390 /// ```rust
391 /// use qubit_function::comparator::BoxComparator;
392 ///
393 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
394 /// ```
395 #[inline]
396 pub fn new<F>(f: F) -> Self
397 where
398 F: Fn(&T, &T) -> Ordering + 'static,
399 {
400 Self {
401 function: Box::new(f),
402 }
403 }
404
405 /// Returns a comparator that imposes the reverse ordering.
406 ///
407 /// # Returns
408 ///
409 /// A new `BoxComparator` that reverses the comparison order.
410 ///
411 /// # Examples
412 ///
413 /// ```rust
414 /// use qubit_function::comparator::{Comparator, BoxComparator};
415 /// use std::cmp::Ordering;
416 ///
417 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
418 /// let rev = cmp.reversed();
419 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
420 /// ```
421 #[inline]
422 pub fn reversed(self) -> Self
423 where
424 T: 'static,
425 {
426 BoxComparator::new(move |a, b| (self.function)(b, a))
427 }
428
429 /// Returns a comparator that uses this comparator first, then another
430 /// comparator if this one considers the values equal.
431 ///
432 /// # Parameters
433 ///
434 /// * `other` - The comparator to use for tie-breaking. **Note: This
435 /// parameter is passed by value and will transfer ownership.** If you
436 /// need to preserve the original comparator, clone it first (if it
437 /// implements `Clone`). Can be:
438 /// - A `BoxComparator<T>`
439 /// - An `RcComparator<T>`
440 /// - An `ArcComparator<T>`
441 /// - Any type implementing `Comparator<T>`
442 ///
443 /// # Returns
444 ///
445 /// A new `BoxComparator` that chains this comparator with another.
446 ///
447 /// # Examples
448 ///
449 /// ```rust
450 /// use qubit_function::comparator::{Comparator, BoxComparator};
451 /// use std::cmp::Ordering;
452 ///
453 /// #[derive(Debug)]
454 /// struct Person {
455 /// name: String,
456 /// age: i32,
457 /// }
458 ///
459 /// let by_name = BoxComparator::new(|a: &Person, b: &Person| {
460 /// a.name.cmp(&b.name)
461 /// });
462 /// let by_age = BoxComparator::new(|a: &Person, b: &Person| {
463 /// a.age.cmp(&b.age)
464 /// });
465 ///
466 /// // by_age is moved here
467 /// let cmp = by_name.then_comparing(by_age);
468 ///
469 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
470 /// let p2 = Person { name: "Alice".to_string(), age: 25 };
471 /// assert_eq!(cmp.compare(&p1, &p2), Ordering::Greater);
472 /// // by_age.compare(&p1, &p2); // Would not compile - moved
473 /// ```
474 #[inline]
475 pub fn then_comparing(self, other: Self) -> Self
476 where
477 T: 'static,
478 {
479 BoxComparator::new(move |a, b| match (self.function)(a, b) {
480 Ordering::Equal => (other.function)(a, b),
481 ord => ord,
482 })
483 }
484
485 /// Returns a comparator that compares values by a key extracted by the
486 /// given function.
487 ///
488 /// # Parameters
489 ///
490 /// * `key_fn` - A function that extracts a comparable key from values
491 ///
492 /// # Returns
493 ///
494 /// A new `BoxComparator` that compares by the extracted key.
495 ///
496 /// # Examples
497 ///
498 /// ```rust
499 /// use qubit_function::comparator::{Comparator, BoxComparator};
500 /// use std::cmp::Ordering;
501 ///
502 /// #[derive(Debug)]
503 /// struct Person {
504 /// name: String,
505 /// age: i32,
506 /// }
507 ///
508 /// let by_age = BoxComparator::comparing(|p: &Person| &p.age);
509 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
510 /// let p2 = Person { name: "Bob".to_string(), age: 25 };
511 /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
512 /// ```
513 #[inline]
514 pub fn comparing<K, F>(key_fn: F) -> Self
515 where
516 K: Ord,
517 F: Fn(&T) -> &K + 'static,
518 {
519 BoxComparator::new(move |a: &T, b: &T| key_fn(a).cmp(key_fn(b)))
520 }
521
522 /// Converts this comparator into a closure.
523 ///
524 /// # Returns
525 ///
526 /// A closure that implements `Fn(&T, &T) -> Ordering`.
527 ///
528 /// # Examples
529 ///
530 /// ```rust
531 /// use qubit_function::comparator::{Comparator, BoxComparator};
532 /// use std::cmp::Ordering;
533 ///
534 /// let cmp = BoxComparator::new(|a: &i32, b: &i32| a.cmp(b));
535 /// let func = cmp.into_fn();
536 /// assert_eq!(func(&5, &3), Ordering::Greater);
537 /// ```
538 #[inline]
539 pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
540 move |a: &T, b: &T| (self.function)(a, b)
541 }
542}
543
544impl<T> Comparator<T> for BoxComparator<T> {
545 #[inline]
546 fn compare(&self, a: &T, b: &T) -> Ordering {
547 (self.function)(a, b)
548 }
549}
550
551/// An Arc-based thread-safe comparator with shared ownership.
552///
553/// `ArcComparator` wraps a comparator function in an `Arc`, providing
554/// thread-safe shared ownership semantics. It is cloneable and uses `&self`
555/// in composition operations.
556///
557/// # Type Parameters
558///
559/// * `T` - The type of values being compared
560///
561/// # Examples
562///
563/// ```rust
564/// use qubit_function::comparator::{Comparator, ArcComparator};
565/// use std::cmp::Ordering;
566///
567/// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
568/// let cloned = cmp.clone();
569/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
570/// assert_eq!(cloned.compare(&5, &3), Ordering::Greater);
571/// ```
572///
573/// # Author
574///
575/// Haixing Hu
576#[derive(Clone)]
577pub struct ArcComparator<T> {
578 function: Arc<dyn Fn(&T, &T) -> Ordering + Send + Sync>,
579}
580
581impl<T> ArcComparator<T> {
582 /// Creates a new `ArcComparator` from a closure.
583 ///
584 /// # Parameters
585 ///
586 /// * `f` - The closure to wrap
587 ///
588 /// # Returns
589 ///
590 /// A new `ArcComparator` instance.
591 ///
592 /// # Examples
593 ///
594 /// ```rust
595 /// use qubit_function::comparator::ArcComparator;
596 ///
597 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
598 /// ```
599 #[inline]
600 pub fn new<F>(f: F) -> Self
601 where
602 F: Fn(&T, &T) -> Ordering + Send + Sync + 'static,
603 {
604 Self {
605 function: Arc::new(f),
606 }
607 }
608
609 /// Returns a comparator that imposes the reverse ordering.
610 ///
611 /// # Returns
612 ///
613 /// A new `ArcComparator` that reverses the comparison order.
614 ///
615 /// # Examples
616 ///
617 /// ```rust
618 /// use qubit_function::comparator::{Comparator, ArcComparator};
619 /// use std::cmp::Ordering;
620 ///
621 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
622 /// let rev = cmp.reversed();
623 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
624 /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater); // cmp still works
625 /// ```
626 #[inline]
627 pub fn reversed(&self) -> Self
628 where
629 T: 'static,
630 {
631 let self_fn = self.function.clone();
632 ArcComparator::new(move |a, b| self_fn(b, a))
633 }
634
635 /// Returns a comparator that uses this comparator first, then another
636 /// comparator if this one considers the values equal.
637 ///
638 /// # Parameters
639 ///
640 /// * `other` - The comparator to use for tie-breaking
641 ///
642 /// # Returns
643 ///
644 /// A new `ArcComparator` that chains this comparator with another.
645 ///
646 /// # Examples
647 ///
648 /// ```rust
649 /// use qubit_function::comparator::{Comparator, ArcComparator};
650 /// use std::cmp::Ordering;
651 ///
652 /// let cmp1 = ArcComparator::new(|a: &i32, b: &i32| {
653 /// (a % 2).cmp(&(b % 2))
654 /// });
655 /// let cmp2 = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
656 /// let chained = cmp1.then_comparing(&cmp2);
657 /// assert_eq!(chained.compare(&4, &2), Ordering::Greater);
658 /// ```
659 #[inline]
660 pub fn then_comparing(&self, other: &Self) -> Self
661 where
662 T: 'static,
663 {
664 let first = self.function.clone();
665 let second = other.function.clone();
666 ArcComparator::new(move |a, b| match first(a, b) {
667 Ordering::Equal => second(a, b),
668 ord => ord,
669 })
670 }
671
672 /// Returns a comparator that compares values by a key extracted by the
673 /// given function.
674 ///
675 /// # Parameters
676 ///
677 /// * `key_fn` - A function that extracts a comparable key from values
678 ///
679 /// # Returns
680 ///
681 /// A new `ArcComparator` that compares by the extracted key.
682 ///
683 /// # Examples
684 ///
685 /// ```rust
686 /// use qubit_function::comparator::{Comparator, ArcComparator};
687 /// use std::cmp::Ordering;
688 ///
689 /// #[derive(Debug)]
690 /// struct Person {
691 /// name: String,
692 /// age: i32,
693 /// }
694 ///
695 /// let by_age = ArcComparator::comparing(|p: &Person| &p.age);
696 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
697 /// let p2 = Person { name: "Bob".to_string(), age: 25 };
698 /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
699 /// ```
700 #[inline]
701 pub fn comparing<K, F>(key_fn: F) -> Self
702 where
703 K: Ord,
704 F: Fn(&T) -> &K + Send + Sync + 'static,
705 {
706 ArcComparator::new(move |a, b| key_fn(a).cmp(key_fn(b)))
707 }
708
709 /// Converts this comparator into a closure.
710 ///
711 /// # Returns
712 ///
713 /// A closure that implements `Fn(&T, &T) -> Ordering`.
714 ///
715 /// # Examples
716 ///
717 /// ```rust
718 /// use qubit_function::comparator::{Comparator, ArcComparator};
719 /// use std::cmp::Ordering;
720 ///
721 /// let cmp = ArcComparator::new(|a: &i32, b: &i32| a.cmp(b));
722 /// let func = cmp.into_fn();
723 /// assert_eq!(func(&5, &3), Ordering::Greater);
724 /// ```
725 #[inline]
726 pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
727 move |a: &T, b: &T| (self.function)(a, b)
728 }
729}
730
731impl<T> Comparator<T> for ArcComparator<T> {
732 #[inline]
733 fn compare(&self, a: &T, b: &T) -> Ordering {
734 (self.function)(a, b)
735 }
736}
737
738/// An Rc-based single-threaded comparator with shared ownership.
739///
740/// `RcComparator` wraps a comparator function in an `Rc`, providing
741/// single-threaded shared ownership semantics. It is cloneable and uses
742/// `&self` in composition operations.
743///
744/// # Type Parameters
745///
746/// * `T` - The type of values being compared
747///
748/// # Examples
749///
750/// ```rust
751/// use qubit_function::comparator::{Comparator, RcComparator};
752/// use std::cmp::Ordering;
753///
754/// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
755/// let cloned = cmp.clone();
756/// assert_eq!(cmp.compare(&5, &3), Ordering::Greater);
757/// assert_eq!(cloned.compare(&5, &3), Ordering::Greater);
758/// ```
759///
760/// # Author
761///
762/// Haixing Hu
763#[derive(Clone)]
764pub struct RcComparator<T> {
765 function: Rc<dyn Fn(&T, &T) -> Ordering>,
766}
767
768impl<T> RcComparator<T> {
769 /// Creates a new `RcComparator` from a closure.
770 ///
771 /// # Parameters
772 ///
773 /// * `f` - The closure to wrap
774 ///
775 /// # Returns
776 ///
777 /// A new `RcComparator` instance.
778 ///
779 /// # Examples
780 ///
781 /// ```rust
782 /// use qubit_function::comparator::RcComparator;
783 ///
784 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
785 /// ```
786 #[inline]
787 pub fn new<F>(f: F) -> Self
788 where
789 F: Fn(&T, &T) -> Ordering + 'static,
790 {
791 Self {
792 function: Rc::new(f),
793 }
794 }
795
796 /// Returns a comparator that imposes the reverse ordering.
797 ///
798 /// # Returns
799 ///
800 /// A new `RcComparator` that reverses the comparison order.
801 ///
802 /// # Examples
803 ///
804 /// ```rust
805 /// use qubit_function::comparator::{Comparator, RcComparator};
806 /// use std::cmp::Ordering;
807 ///
808 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
809 /// let rev = cmp.reversed();
810 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
811 /// assert_eq!(cmp.compare(&5, &3), Ordering::Greater); // cmp still works
812 /// ```
813 #[inline]
814 pub fn reversed(&self) -> Self
815 where
816 T: 'static,
817 {
818 let self_fn = self.function.clone();
819 RcComparator::new(move |a, b| self_fn(b, a))
820 }
821
822 /// Returns a comparator that uses this comparator first, then another
823 /// comparator if this one considers the values equal.
824 ///
825 /// # Parameters
826 ///
827 /// * `other` - The comparator to use for tie-breaking
828 ///
829 /// # Returns
830 ///
831 /// A new `RcComparator` that chains this comparator with another.
832 ///
833 /// # Examples
834 ///
835 /// ```rust
836 /// use qubit_function::comparator::{Comparator, RcComparator};
837 /// use std::cmp::Ordering;
838 ///
839 /// let cmp1 = RcComparator::new(|a: &i32, b: &i32| {
840 /// (a % 2).cmp(&(b % 2))
841 /// });
842 /// let cmp2 = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
843 /// let chained = cmp1.then_comparing(&cmp2);
844 /// assert_eq!(chained.compare(&4, &2), Ordering::Greater);
845 /// ```
846 #[inline]
847 pub fn then_comparing(&self, other: &Self) -> Self
848 where
849 T: 'static,
850 {
851 let first = self.function.clone();
852 let second = other.function.clone();
853 RcComparator::new(move |a, b| match first(a, b) {
854 Ordering::Equal => second(a, b),
855 ord => ord,
856 })
857 }
858
859 /// Returns a comparator that compares values by a key extracted by the
860 /// given function.
861 ///
862 /// # Parameters
863 ///
864 /// * `key_fn` - A function that extracts a comparable key from values
865 ///
866 /// # Returns
867 ///
868 /// A new `RcComparator` that compares by the extracted key.
869 ///
870 /// # Examples
871 ///
872 /// ```rust
873 /// use qubit_function::comparator::{Comparator, RcComparator};
874 /// use std::cmp::Ordering;
875 ///
876 /// #[derive(Debug)]
877 /// struct Person {
878 /// name: String,
879 /// age: i32,
880 /// }
881 ///
882 /// let by_age = RcComparator::comparing(|p: &Person| &p.age);
883 /// let p1 = Person { name: "Alice".to_string(), age: 30 };
884 /// let p2 = Person { name: "Bob".to_string(), age: 25 };
885 /// assert_eq!(by_age.compare(&p1, &p2), Ordering::Greater);
886 /// ```
887 #[inline]
888 pub fn comparing<K, F>(key_fn: F) -> Self
889 where
890 K: Ord,
891 F: Fn(&T) -> &K + 'static,
892 {
893 RcComparator::new(move |a, b| key_fn(a).cmp(key_fn(b)))
894 }
895
896 /// Converts this comparator into a closure.
897 ///
898 /// # Returns
899 ///
900 /// A closure that implements `Fn(&T, &T) -> Ordering`.
901 ///
902 /// # Examples
903 ///
904 /// ```rust
905 /// use qubit_function::comparator::{Comparator, RcComparator};
906 /// use std::cmp::Ordering;
907 ///
908 /// let cmp = RcComparator::new(|a: &i32, b: &i32| a.cmp(b));
909 /// let func = cmp.into_fn();
910 /// assert_eq!(func(&5, &3), Ordering::Greater);
911 /// ```
912 #[inline]
913 pub fn into_fn(self) -> impl Fn(&T, &T) -> Ordering {
914 move |a: &T, b: &T| (self.function)(a, b)
915 }
916}
917
918impl<T> Comparator<T> for RcComparator<T> {
919 #[inline]
920 fn compare(&self, a: &T, b: &T) -> Ordering {
921 (self.function)(a, b)
922 }
923}
924
925/// Extension trait providing composition methods for closures and function
926/// pointers.
927///
928/// This trait is automatically implemented for all closures and function
929/// pointers with the signature `Fn(&T, &T) -> Ordering`, allowing them to
930/// be composed directly without explicit wrapping.
931///
932/// # Examples
933///
934/// ```rust
935/// use qubit_function::comparator::{Comparator, FnComparatorOps};
936/// use std::cmp::Ordering;
937///
938/// let cmp = (|a: &i32, b: &i32| a.cmp(b))
939/// .reversed()
940/// .then_comparing(BoxComparator::new(|a, b| b.cmp(a)));
941///
942/// assert_eq!(cmp.compare(&5, &3), Ordering::Less);
943/// ```
944///
945/// # Author
946///
947/// Haixing Hu
948pub trait FnComparatorOps<T>: Fn(&T, &T) -> Ordering + Sized {
949 /// Returns a comparator that imposes the reverse ordering.
950 ///
951 /// # Returns
952 ///
953 /// A new `BoxComparator` that reverses the comparison order.
954 ///
955 /// # Examples
956 ///
957 /// ```rust
958 /// use qubit_function::comparator::{Comparator, FnComparatorOps};
959 /// use std::cmp::Ordering;
960 ///
961 /// let rev = (|a: &i32, b: &i32| a.cmp(b)).reversed();
962 /// assert_eq!(rev.compare(&5, &3), Ordering::Less);
963 /// ```
964 #[inline]
965 fn reversed(self) -> BoxComparator<T>
966 where
967 Self: 'static,
968 T: 'static,
969 {
970 BoxComparator::new(self).reversed()
971 }
972
973 /// Returns a comparator that uses this comparator first, then another
974 /// comparator if this one considers the values equal.
975 ///
976 /// # Parameters
977 ///
978 /// * `other` - The comparator to use for tie-breaking
979 ///
980 /// # Returns
981 ///
982 /// A new `BoxComparator` that chains this comparator with another.
983 ///
984 /// # Examples
985 ///
986 /// ```rust
987 /// use qubit_function::comparator::{Comparator, FnComparatorOps,
988 /// BoxComparator};
989 /// use std::cmp::Ordering;
990 ///
991 /// let cmp = (|a: &i32, b: &i32| (a % 2).cmp(&(b % 2)))
992 /// .then_comparing(BoxComparator::new(|a, b| a.cmp(b)));
993 /// assert_eq!(cmp.compare(&4, &2), Ordering::Greater);
994 /// ```
995 #[inline]
996 fn then_comparing(self, other: BoxComparator<T>) -> BoxComparator<T>
997 where
998 Self: 'static,
999 T: 'static,
1000 {
1001 BoxComparator::new(self).then_comparing(other)
1002 }
1003}
1004
1005impl<T, F> FnComparatorOps<T> for F where F: Fn(&T, &T) -> Ordering {}