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
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use crate::Key;
use std::ops::Bound;

/// Trait similar to [`std::ops::RangeBounds`] that requires an inclusive start to the range.
///
/// This means this trait is only usable for ranges like
/// [`1..`](std::ops::RangeFrom),
/// [`1..5`](std::ops::Range),
/// and [`1..=5`](std::ops::RangeInclusive).
///
/// Ranges like
/// [`..`](std::ops::RangeFull),
/// [`..5`](std::ops::RangeTo), and
/// [`..=5`](std::ops::RangeToInclusive) are not supported.
///
/// This trait is used for looking up slices in a [`ContiguousMap`](crate::ContiguousMap).
/// The semantics of the non-supported ranges are odd and not yet (and maybe never) implemented.
/// For example, with [`..`](std::ops::RangeFull) you'd expect a slice that contains all of the
/// values in the map, however only elements with adjacent keys can be in the same slice.
pub trait InclusiveStartRangeBounds<K: Key> {
    /// The inclusive starting bound of this range.
    fn start_bound(&self) -> &K;

    /// The end bound of this range.
    fn end_bound(&self) -> Bound<&K>;
}

impl<K: Key> InclusiveStartRangeBounds<K> for std::ops::Range<K> {
    fn start_bound(&self) -> &K {
        &self.start
    }

    fn end_bound(&self) -> Bound<&K> {
        Bound::Excluded(&self.end)
    }
}

impl<K: Key> InclusiveStartRangeBounds<K> for std::ops::Range<&K> {
    fn start_bound(&self) -> &K {
        self.start
    }

    fn end_bound(&self) -> Bound<&K> {
        Bound::Excluded(self.end)
    }
}

impl<K: Key> InclusiveStartRangeBounds<K> for std::ops::RangeFrom<K> {
    fn start_bound(&self) -> &K {
        &self.start
    }

    fn end_bound(&self) -> Bound<&K> {
        Bound::Unbounded
    }
}

impl<K: Key> InclusiveStartRangeBounds<K> for std::ops::RangeFrom<&K> {
    fn start_bound(&self) -> &K {
        self.start
    }

    fn end_bound(&self) -> Bound<&K> {
        Bound::Unbounded
    }
}

impl<K: Key> InclusiveStartRangeBounds<K> for std::ops::RangeInclusive<K> {
    fn start_bound(&self) -> &K {
        self.start()
    }

    fn end_bound(&self) -> Bound<&K> {
        Bound::Included(self.end())
    }
}

impl<K: Key> InclusiveStartRangeBounds<K> for std::ops::RangeInclusive<&K> {
    fn start_bound(&self) -> &K {
        self.start()
    }

    fn end_bound(&self) -> Bound<&K> {
        Bound::Included(self.end())
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn range() {
        let range = 2u8..7;
        assert_eq!(&2, range.start_bound());
        assert_eq!(Bound::Excluded(&7), range.end_bound());
    }

    #[test]
    fn range_ref() {
        let range = &2u8..&7;
        assert_eq!(&2, range.start_bound());
        assert_eq!(Bound::Excluded(&7), range.end_bound());
    }

    #[test]
    fn range_from() {
        let range = 2u8..;
        assert_eq!(&2, range.start_bound());
        assert_eq!(Bound::Unbounded, range.end_bound());
    }

    #[test]
    fn range_from_ref() {
        let range = &2u8..;
        assert_eq!(&2, range.start_bound());
        assert_eq!(Bound::Unbounded, range.end_bound());
    }

    #[test]
    fn range_inclusive() {
        let range = 2u8..=7;
        assert_eq!(&2, range.start_bound());
        assert_eq!(Bound::Included(&7), range.end_bound());
    }

    #[test]
    fn range_inclusive_ref() {
        let range = &2u8..=&7;
        assert_eq!(&2, range.start_bound());
        assert_eq!(Bound::Included(&7), range.end_bound());
    }
}