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