1use crate::{BytePos, SessionGlobals};
2use std::{cmp, fmt, ops::Range};
3
4#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub struct Span {
11 lo: BytePos,
12 hi: BytePos,
13}
14
15impl Default for Span {
16 #[inline(always)]
17 fn default() -> Self {
18 Self::DUMMY
19 }
20}
21
22impl Default for &Span {
23 #[inline(always)]
24 fn default() -> Self {
25 &Span::DUMMY
26 }
27}
28
29impl fmt::Debug for Span {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 fn fallback(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 write!(f, "Span({lo}..{hi})", lo = span.lo().0, hi = span.hi().0)
36 }
37
38 if SessionGlobals::is_set() {
39 SessionGlobals::with(|g: &SessionGlobals| {
40 let sm = g.source_map.lock();
41 if let Some(source_map) = &*sm {
42 f.write_str(&source_map.span_to_diagnostic_string(*self))
43 } else {
44 drop(sm);
45 fallback(*self, f)
46 }
47 })
48 } else {
49 fallback(*self, f)
50 }
51 }
52}
53
54impl Span {
55 pub const DUMMY: Self = Self { lo: BytePos(0), hi: BytePos(0) };
57
58 #[inline]
60 pub fn new(mut lo: BytePos, mut hi: BytePos) -> Self {
61 if lo > hi {
62 std::mem::swap(&mut lo, &mut hi);
63 }
64 Self { lo, hi }
65 }
66
67 #[inline]
69 pub fn to_range(self) -> Range<usize> {
70 self.lo().to_usize()..self.hi().to_usize()
71 }
72
73 #[inline]
75 pub fn to_u32_range(self) -> Range<u32> {
76 self.lo().to_u32()..self.hi().to_u32()
77 }
78
79 #[inline(always)]
81 pub fn lo(self) -> BytePos {
82 self.lo
83 }
84
85 #[inline]
87 pub fn with_lo(self, lo: BytePos) -> Self {
88 Self::new(lo, self.hi())
89 }
90
91 #[inline(always)]
93 pub fn hi(self) -> BytePos {
94 self.hi
95 }
96
97 #[inline]
99 pub fn with_hi(self, hi: BytePos) -> Self {
100 Self::new(self.lo(), hi)
101 }
102
103 #[inline]
105 pub fn shrink_to_lo(self) -> Self {
106 Self::new(self.lo(), self.lo())
107 }
108
109 #[inline]
111 pub fn shrink_to_hi(self) -> Self {
112 Self::new(self.hi(), self.hi())
113 }
114
115 #[inline]
117 pub fn is_dummy(self) -> bool {
118 self == Self::DUMMY
119 }
120
121 #[inline]
123 pub fn contains(self, other: Self) -> bool {
124 self.lo() <= other.lo() && other.hi() <= self.hi()
125 }
126
127 #[inline]
129 pub fn overlaps(self, other: Self) -> bool {
130 self.lo() < other.hi() && other.lo() < self.hi()
131 }
132
133 #[inline]
135 pub fn is_empty(self, other: Self) -> bool {
136 self.lo() == other.lo() && self.hi() == other.hi()
137 }
138
139 #[inline]
141 pub fn split_at(self, pos: u32) -> (Self, Self) {
142 let len = self.hi().0 - self.lo().0;
143 debug_assert!(pos <= len);
144
145 let split_pos = BytePos(self.lo().0 + pos);
146 (Self::new(self.lo(), split_pos), Self::new(split_pos, self.hi()))
147 }
148
149 #[inline]
160 pub fn to(self, end: Self) -> Self {
161 Self::new(cmp::min(self.lo(), end.lo()), cmp::max(self.hi(), end.hi()))
162 }
163
164 #[inline]
172 pub fn between(self, end: Self) -> Self {
173 Self::new(self.hi(), end.lo())
174 }
175
176 #[inline]
184 pub fn until(self, end: Self) -> Self {
185 Self::new(self.lo(), end.lo())
186 }
187
188 #[inline]
190 pub fn join_many(spans: impl IntoIterator<Item = Self>) -> Self {
191 spans.into_iter().reduce(Self::to).unwrap_or_default()
192 }
193
194 #[inline]
196 pub fn join_first_last(
197 spans: impl IntoIterator<Item = Self, IntoIter: DoubleEndedIterator>,
198 ) -> Self {
199 let mut spans = spans.into_iter();
200 let first = spans.next().unwrap_or_default();
201 if let Some(last) = spans.next_back() {
202 first.to(last)
203 } else {
204 first
205 }
206 }
207}