1use crate::files::FileId;
7use codespan::{self, ByteIndex};
8use std::{
9 cmp::{Ordering, max, min},
10 ops::Range,
11};
12
13pub trait Max {
16 const MAX: Self;
17}
18
19impl Max for u32 {
20 const MAX: Self = Self::MAX;
21}
22
23impl Max for usize {
24 const MAX: Self = Self::MAX;
25}
26
27#[derive(Debug, Clone, Copy, Eq, PartialEq)]
29pub struct RawPos {
30 pub src_id: FileId,
31 pub index: ByteIndex,
32}
33
34impl RawPos {
35 pub fn new(src_id: FileId, index: ByteIndex) -> Self {
36 Self { src_id, index }
37 }
38}
39
40#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
44pub struct RawSpan {
45 pub src_id: FileId,
46 pub start: ByteIndex,
47 pub end: ByteIndex,
48}
49
50impl RawSpan {
51 pub fn fuse(self, other: RawSpan) -> Option<RawSpan> {
54 if self.src_id == other.src_id {
55 Some(RawSpan {
56 src_id: self.src_id,
57 start: min(self.start, other.start),
58 end: max(self.end, other.end),
59 })
60 } else {
61 None
62 }
63 }
64
65 pub fn from_codespan(src_id: FileId, span: codespan::Span) -> Self {
67 RawSpan {
68 src_id,
69 start: span.start(),
70 end: span.end(),
71 }
72 }
73
74 pub fn from_range<T>(src_id: FileId, range: Range<T>) -> Self
77 where
78 u32: TryFrom<T>,
79 {
80 RawSpan {
81 src_id,
82 start: ByteIndex(u32::try_from(range.start).unwrap_or(u32::MAX)),
83 end: ByteIndex(u32::try_from(range.end).unwrap_or(u32::MAX)),
84 }
85 }
86
87 pub fn to_range<T>(self) -> Range<T>
90 where
91 T: TryFrom<u32> + Max,
92 {
93 T::try_from(self.start.0).unwrap_or(T::MAX)..T::try_from(self.end.0).unwrap_or(T::MAX)
94 }
95
96 pub fn start_pos(&self) -> RawPos {
98 RawPos {
99 src_id: self.src_id,
100 index: self.start,
101 }
102 }
103
104 pub fn contains(&self, pos: RawPos) -> bool {
106 self.src_id == pos.src_id && (self.start..self.end).contains(&pos.index)
107 }
108
109 pub fn contains_span(&self, other: RawSpan) -> bool {
111 self.src_id == other.src_id && self.start <= other.start && self.end >= other.end
112 }
113}
114
115impl From<RawSpan> for codespan::Span {
116 fn from(span: RawSpan) -> Self {
117 codespan::Span::new(span.start, span.end)
118 }
119}
120
121#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default)]
123pub enum TermPos {
124 Original(RawSpan),
127 Inherited(RawSpan),
129 #[default]
132 None,
133}
134
135impl TermPos {
136 pub fn map<F: FnOnce(RawSpan) -> RawSpan>(self, f: F) -> Self {
138 match self {
139 TermPos::Original(x) => TermPos::Original(f(x)),
140 TermPos::Inherited(x) => TermPos::Inherited(f(x)),
141 TermPos::None => TermPos::None,
142 }
143 }
144
145 pub fn as_opt_ref(&self) -> Option<&RawSpan> {
146 match self {
147 TermPos::Original(pos) | TermPos::Inherited(pos) => Some(pos),
148 TermPos::None => None,
149 }
150 }
151
152 pub fn into_opt(self) -> Option<RawSpan> {
155 match self {
156 TermPos::Original(pos) | TermPos::Inherited(pos) => Some(pos),
157 TermPos::None => None,
158 }
159 }
160
161 pub fn src_id(&self) -> Option<FileId> {
164 match self {
165 TermPos::Original(raw_span) | TermPos::Inherited(raw_span) => Some(raw_span.src_id),
166 TermPos::None => None,
167 }
168 }
169
170 pub fn or(self, other: Self) -> Self {
172 if let TermPos::None = self {
173 other
174 } else {
175 self
176 }
177 }
178
179 pub fn xor(self, other: Self) -> Self {
182 match (self, other) {
183 (defn, TermPos::None) | (TermPos::None, defn) => defn,
184 _ => TermPos::None,
185 }
186 }
187
188 pub fn is_def(&self) -> bool {
190 matches!(self, TermPos::Original(_) | TermPos::Inherited(_))
191 }
192
193 #[track_caller]
195 pub fn unwrap(self) -> RawSpan {
196 match self {
197 TermPos::Original(x) | TermPos::Inherited(x) => x,
198 TermPos::None => panic!("TermPos::unwrap"),
199 }
200 }
201
202 pub fn into_inherited(self) -> Self {
205 match self {
206 TermPos::Original(pos) => TermPos::Inherited(pos),
207 p => p,
208 }
209 }
210
211 pub fn contains(&self, pos: RawPos) -> bool {
213 self.as_opt_ref().is_some_and(|sp| sp.contains(pos))
214 }
215
216 pub fn fuse(self, other: Self) -> Self {
223 match (self, other) {
224 (TermPos::Original(sp1), TermPos::Original(sp2)) => {
225 if let Some(span) = sp1.fuse(sp2) {
226 TermPos::Original(span)
227 } else {
228 TermPos::None
229 }
230 }
231 (TermPos::Inherited(sp1), TermPos::Inherited(sp2))
232 | (TermPos::Original(sp1), TermPos::Inherited(sp2))
233 | (TermPos::Inherited(sp1), TermPos::Original(sp2)) => {
234 if let Some(span) = sp1.fuse(sp2) {
235 TermPos::Inherited(span)
236 } else {
237 TermPos::None
238 }
239 }
240 (TermPos::None, maybe_def) | (maybe_def, TermPos::None) => maybe_def,
241 }
242 }
243}
244
245impl PartialOrd for RawPos {
248 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
249 if self.src_id == other.src_id {
250 Some(self.index.cmp(&other.index))
251 } else {
252 None
253 }
254 }
255}
256
257impl PartialOrd for RawSpan {
260 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
261 if self.src_id != other.src_id {
262 None
263 } else if self.start == other.start && self.end == other.end {
264 Some(Ordering::Equal)
265 } else if self.start >= other.start && self.end <= other.end {
266 Some(Ordering::Less)
267 } else if self.start <= other.start && self.end >= other.end {
268 Some(Ordering::Greater)
269 } else {
270 None
271 }
272 }
273}
274
275impl From<RawSpan> for TermPos {
276 fn from(span: RawSpan) -> Self {
277 TermPos::Original(span)
278 }
279}
280
281impl From<Option<RawSpan>> for TermPos {
282 fn from(value: Option<RawSpan>) -> Self {
283 match value {
284 Some(span) => TermPos::Original(span),
285 None => TermPos::None,
286 }
287 }
288}