re_span/
lib.rs

1//! An integer range that always has a non-negative length.
2//!
3//! The standard [`std::ops::Range`] can have `start > end`
4//! Taking a `Range` by argument thus means the callee must check for this eventuality and return an error.
5//!
6//! In contrast, [`Span`] always has a non-negative length, i.e. `len >= 0`.
7
8use std::ops::{Mul, Range};
9
10use num_traits::Unsigned;
11
12/// An integer range who's length is always at least zero.
13#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct Span<Idx: Unsigned + Copy> {
15    /// The index of the first element.
16    pub start: Idx,
17
18    /// The number of elements in the range.
19    pub len: Idx,
20}
21
22impl<Idx: Unsigned + Copy> Span<Idx> {
23    /// The next element, just outside the range.
24    #[inline]
25    pub fn end(&self) -> Idx {
26        self.start + self.len
27    }
28
29    /// Useful when slicing a slice
30    #[inline]
31    pub fn range(self) -> Range<Idx> {
32        let Self { start, len } = self;
33        Range {
34            start,
35            end: start + len,
36        }
37    }
38
39    pub fn try_cast<Narrow>(self) -> Option<Span<Narrow>>
40    where
41        Narrow: TryFrom<Idx> + Unsigned + Copy,
42    {
43        Some(Span {
44            start: self.start.try_into().ok()?,
45            len: self.len.try_into().ok()?,
46        })
47    }
48}
49
50impl Span<u32> {
51    /// Widening cast; useful for indexing.
52    #[inline]
53    pub fn range_usize(self) -> Range<usize> {
54        let Self { start, len } = self;
55        Range {
56            start: start as usize,
57            end: start as usize + len as usize,
58        }
59    }
60}
61
62impl<Idx: Unsigned + Copy> From<Span<Idx>> for Range<Idx> {
63    #[inline]
64    fn from(value: Span<Idx>) -> Self {
65        value.range()
66    }
67}
68
69/// span * scalar
70impl<Idx: Unsigned + Copy + Mul> Mul<Idx> for Span<Idx> {
71    type Output = Self;
72
73    fn mul(self, rhs: Idx) -> Self::Output {
74        let Self { start, len } = self;
75        Self {
76            start: rhs * start,
77            len: rhs * len,
78        }
79    }
80}