batbox_range/
lib.rs

1//! Extra utilities for working with ranges
2#![warn(missing_docs)]
3
4#[doc(no_inline)]
5pub use std::ops::{
6    Bound, Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
7};
8
9/// Same as [RangeBounds] but without exclusive bounds
10pub trait FixedRangeBounds<T: ?Sized> {
11    /// Start index bound
12    fn start_bound(&self) -> FixedBound<&T>;
13    /// End index bound
14    fn end_bound(&self) -> FixedBound<&T>;
15}
16
17/// Same as [Bound] but without exclusive bounds
18pub enum FixedBound<T> {
19    /// An inclusive bound
20    Included(T),
21    /// An infinite endpoint. Indicates that there is no bound in this direction
22    Unbounded,
23}
24
25impl<T> FixedRangeBounds<T> for RangeInclusive<T> {
26    fn start_bound(&self) -> FixedBound<&T> {
27        FixedBound::Included(self.start())
28    }
29    fn end_bound(&self) -> FixedBound<&T> {
30        FixedBound::Included(self.end())
31    }
32}
33
34impl<T> FixedRangeBounds<T> for RangeFull {
35    fn start_bound(&self) -> FixedBound<&T> {
36        FixedBound::Unbounded
37    }
38    fn end_bound(&self) -> FixedBound<&T> {
39        FixedBound::Unbounded
40    }
41}
42
43impl<T> FixedRangeBounds<T> for RangeFrom<T> {
44    fn start_bound(&self) -> FixedBound<&T> {
45        FixedBound::Included(&self.start)
46    }
47    fn end_bound(&self) -> FixedBound<&T> {
48        FixedBound::Unbounded
49    }
50}
51
52impl<T> FixedRangeBounds<T> for RangeToInclusive<T> {
53    fn start_bound(&self) -> FixedBound<&T> {
54        FixedBound::Unbounded
55    }
56    fn end_bound(&self) -> FixedBound<&T> {
57        FixedBound::Included(&self.end)
58    }
59}
60
61/// Extension trait for getting index ranges
62pub trait IndexRangeExt {
63    /// Convert any range into a `start..end` [Range] as if used for slicing of a container of length equal to self
64    fn index_range<R>(self, range: R) -> Range<usize>
65    where
66        R: RangeBounds<usize>;
67}
68
69impl IndexRangeExt for usize {
70    fn index_range<R>(self, range: R) -> Range<usize>
71    where
72        R: RangeBounds<usize>,
73    {
74        Range {
75            start: match range.start_bound() {
76                Bound::Included(&i) => i,
77                Bound::Excluded(&i) => i + 1,
78                Bound::Unbounded => 0,
79            },
80            end: match range.end_bound() {
81                Bound::Included(&i) => i + 1,
82                Bound::Excluded(&i) => i,
83                Bound::Unbounded => self,
84            },
85        }
86    }
87}