1use std::ops::{Mul, Range};
9
10use num_traits::Unsigned;
11
12#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct Span<Idx: Unsigned + Copy> {
15 pub start: Idx,
17
18 pub len: Idx,
20}
21
22impl<Idx: Unsigned + Copy> Span<Idx> {
23 #[inline]
25 pub fn from_start_len(start: Idx, len: Idx) -> Self {
26 Self { start, len }
27 }
28
29 #[inline]
33 pub fn from_start_end(start: Idx, end: Idx) -> Self
34 where
35 Idx: PartialOrd,
36 {
37 #![expect(
38 clippy::disallowed_macros,
39 reason = "We don't want to depend on re_log for re_log::debug_assert"
40 )]
41 debug_assert!(
42 start <= end,
43 "DEBUG ASSERT: start must be less than or equal to end"
44 );
45
46 Self {
47 start,
48 len: end - start,
49 }
50 }
51
52 #[inline]
54 pub fn end(&self) -> Idx {
55 self.start + self.len
56 }
57
58 #[inline]
60 pub fn range(self) -> Range<Idx> {
61 let Self { start, len } = self;
62 Range {
63 start,
64 end: start + len,
65 }
66 }
67
68 pub fn try_cast<Narrow>(self) -> Option<Span<Narrow>>
69 where
70 Narrow: TryFrom<Idx> + Unsigned + Copy,
71 {
72 Some(Span {
73 start: self.start.try_into().ok()?,
74 len: self.len.try_into().ok()?,
75 })
76 }
77}
78
79impl Span<u32> {
80 #[inline]
82 pub fn range_usize(self) -> Range<usize> {
83 let Self { start, len } = self;
84 Range {
85 start: start as usize,
86 end: start as usize + len as usize,
87 }
88 }
89}
90
91impl<Idx: Unsigned + Copy> From<Span<Idx>> for Range<Idx> {
92 #[inline]
93 fn from(value: Span<Idx>) -> Self {
94 value.range()
95 }
96}
97
98impl<Idx: Unsigned + Copy + Mul> Mul<Idx> for Span<Idx> {
100 type Output = Self;
101
102 fn mul(self, rhs: Idx) -> Self::Output {
103 let Self { start, len } = self;
104 Self {
105 start: rhs * start,
106 len: rhs * len,
107 }
108 }
109}