equivalent_flipped/
lib.rs

1// These traits are based on `equivalent` crate, but `K` and `Q` are flipped to avoid type inference issues:
2// https://github.com/indexmap-rs/equivalent/issues/5
3
4#![doc = include_str!("../README.md")]
5#![no_std]
6#![cfg_attr(docsrs, feature(doc_cfg))]
7#![cfg_attr(docsrs, allow(unused_attributes))]
8#![allow(rustdoc::bare_urls)]
9#![deny(missing_docs)]
10
11#[cfg(test)]
12extern crate std;
13
14use core::{borrow::Borrow, cmp::Ordering};
15
16/// Key equivalence trait.
17///
18/// This trait allows hash table lookup to be customized. It has one blanket
19/// implementation that uses the regular solution with `Borrow` and `Eq`, just
20/// like `HashMap` does, so that you can pass `&str` to lookup into a map with
21/// `String` keys and so on.
22///
23/// # Contract
24///
25/// The implementor **must** hash like `Q`, if it is hashable.
26pub trait Equivalent<Q: ?Sized> {
27  /// Compare self to `key` and return `true` if they are equal.
28  fn equivalent(&self, key: &Q) -> bool;
29}
30
31impl<K: ?Sized, Q: ?Sized> Equivalent<Q> for K
32where
33  K: Borrow<Q>,
34  Q: Eq,
35{
36  #[inline]
37  fn equivalent(&self, key: &Q) -> bool {
38    PartialEq::eq(self.borrow(), key)
39  }
40}
41
42/// Key ordering trait.
43///
44/// This trait allows ordered map lookup to be customized. It has one blanket
45/// implementation that uses the regular solution with `Borrow` and `Ord`, just
46/// like `BTreeMap` does, so that you can pass `&str` to lookup into a map with
47/// `String` keys and so on.
48pub trait Comparable<Q: ?Sized>: Equivalent<Q> {
49  /// Compare self to `key` and return their ordering.
50  fn compare(&self, key: &Q) -> Ordering;
51}
52
53impl<K: ?Sized, Q: ?Sized> Comparable<Q> for K
54where
55  K: Borrow<Q>,
56  Q: Ord,
57{
58  #[inline]
59  fn compare(&self, key: &Q) -> Ordering {
60    Ord::cmp(self.borrow(), key)
61  }
62}
63
64/// `ComparableRangeBounds` is implemented as an extention to `RangeBounds` to
65/// allow for comparison of items with range bounds.
66pub trait ComparableRangeBounds<Q: ?Sized>: core::ops::RangeBounds<Q> {
67  /// Returns `true` if `item` is contained in the range.
68  fn compare_contains<K>(&self, item: &K) -> bool
69  where
70    K: ?Sized + Comparable<Q>,
71  {
72    use core::ops::Bound;
73
74    (match self.start_bound() {
75      Bound::Included(start) => item.compare(start) != Ordering::Less,
76      Bound::Excluded(start) => item.compare(start) == Ordering::Greater,
77      Bound::Unbounded => true,
78    }) && (match self.end_bound() {
79      Bound::Included(end) => item.compare(end) != Ordering::Greater,
80      Bound::Excluded(end) => item.compare(end) == Ordering::Less,
81      Bound::Unbounded => true,
82    })
83  }
84}
85
86impl<R, Q> ComparableRangeBounds<Q> for R
87where
88  R: ?Sized + core::ops::RangeBounds<Q>,
89  Q: ?Sized,
90{
91}