miden_diagnostics/
index.rs

1use std::num::NonZeroUsize;
2use std::ops::{Add, AddAssign, Sub, SubAssign};
3
4use codespan::{ByteIndex, ByteOffset, RawIndex, RawOffset};
5
6use super::SourceId;
7
8/// [SourceIndex] is a compact representation of a byte index in a specific source file.
9///
10/// It has a canonical representation for "unknown" indices, similar to that of [SourceSpan]
11#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct SourceIndex(NonZeroUsize);
13impl SourceIndex {
14    const INDEX_MASK: usize = u32::max_value() as usize;
15
16    const UNKNOWN_SRC_ID: usize = (SourceId::UNKNOWN_SOURCE_ID as usize) << 32;
17
18    /// Represents an invalid/unknown [SourceIndex]
19    pub const UNKNOWN: Self = Self(unsafe { NonZeroUsize::new_unchecked(Self::UNKNOWN_SRC_ID) });
20
21    /// Constructs a new [SourceIndex] from a [SourceId] and a [ByteIndex]
22    #[inline]
23    pub fn new(source: SourceId, index: ByteIndex) -> Self {
24        let source = (source.get() as usize) << 32;
25
26        Self(NonZeroUsize::new(source | index.0 as usize).unwrap())
27    }
28
29    /// Returns the [SourceId] corresponding to this [SourceIndex]
30    #[inline]
31    pub fn source_id(&self) -> SourceId {
32        let source_id_part = (self.0.get() >> 32) as u32;
33        if source_id_part == SourceId::UNKNOWN_SOURCE_ID {
34            SourceId::UNKNOWN
35        } else {
36            SourceId::new(source_id_part)
37        }
38    }
39
40    /// Returns the [ByteIndex] corresponding to this [SourceIndex]
41    #[inline]
42    pub fn index(&self) -> ByteIndex {
43        ByteIndex((self.0.get() & Self::INDEX_MASK) as u32)
44    }
45
46    #[doc(hidden)]
47    pub fn to_usize(&self) -> usize {
48        self.0.get()
49    }
50}
51impl Default for SourceIndex {
52    fn default() -> Self {
53        Self::UNKNOWN
54    }
55}
56
57impl Add<usize> for SourceIndex {
58    type Output = SourceIndex;
59
60    #[inline]
61    fn add(self, rhs: usize) -> Self {
62        if self == Self::UNKNOWN {
63            return Self::UNKNOWN;
64        }
65        let source = self.source_id();
66        let index = self.index();
67        let new_index = index.0 as RawOffset + rhs as RawOffset;
68        Self::new(source, ByteIndex(new_index as RawIndex))
69    }
70}
71
72impl Add<ByteOffset> for SourceIndex {
73    type Output = SourceIndex;
74
75    #[inline]
76    fn add(self, rhs: ByteOffset) -> Self {
77        if self == Self::UNKNOWN {
78            return Self::UNKNOWN;
79        }
80        let source = self.source_id();
81        let index = self.index();
82        let new_index = ByteIndex(index.0) + rhs;
83        Self::new(source, new_index)
84    }
85}
86
87impl AddAssign<usize> for SourceIndex {
88    #[inline]
89    fn add_assign(&mut self, rhs: usize) {
90        *self = *self + rhs;
91    }
92}
93
94impl AddAssign<ByteOffset> for SourceIndex {
95    #[inline]
96    fn add_assign(&mut self, rhs: ByteOffset) {
97        *self = *self + rhs;
98    }
99}
100
101impl Sub<usize> for SourceIndex {
102    type Output = SourceIndex;
103
104    #[inline]
105    fn sub(self, rhs: usize) -> Self {
106        if self == Self::UNKNOWN {
107            return Self::UNKNOWN;
108        }
109        let source = self.source_id();
110        let index = self.index();
111        let new_index = index.0 as RawOffset - rhs as RawOffset;
112        Self::new(source, ByteIndex(new_index as RawIndex))
113    }
114}
115
116impl SubAssign<usize> for SourceIndex {
117    #[inline]
118    fn sub_assign(&mut self, rhs: usize) {
119        *self = *self - rhs;
120    }
121}