1use crate::files::SourceFileId;
2use serde::{Deserialize, Serialize};
3use std::cmp;
4use std::fmt::{Debug, Formatter};
5use std::ops::{Add, AddAssign, Range};
6
7#[derive(Serialize, Deserialize, PartialEq, Copy, Clone, Hash, Eq)]
9pub struct Span {
10 #[serde(skip_serializing)]
11 pub file_id: SourceFileId,
12 pub start: usize,
14 pub end: usize,
16}
17
18impl Span {
19 pub fn new(file_id: SourceFileId, start: usize, end: usize) -> Self {
20 Span {
21 file_id,
22 start: cmp::min(start, end),
23 end: cmp::max(start, end),
24 }
25 }
26
27 pub fn zero(file_id: SourceFileId) -> Self {
28 Span {
29 file_id,
30 start: 0,
31 end: 0,
32 }
33 }
34
35 pub fn dummy() -> Self {
36 Self {
37 file_id: SourceFileId::dummy_file(),
38 start: usize::MAX,
39 end: usize::MAX,
40 }
41 }
42
43 pub fn is_dummy(&self) -> bool {
44 self == &Self::dummy()
45 }
46
47 pub fn from_pair<S, E>(start_elem: S, end_elem: E) -> Self
48 where
49 S: Into<Span>,
50 E: Into<Span>,
51 {
52 let start_span: Span = start_elem.into();
53 let end_span: Span = end_elem.into();
54
55 let file_id = if start_span.file_id == end_span.file_id {
56 start_span.file_id
57 } else {
58 panic!("file ids are not equal")
59 };
60
61 Self {
62 file_id,
63 start: start_span.start,
64 end: end_span.end,
65 }
66 }
67}
68
69impl Debug for Span {
70 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
71 write!(f, "{:?}", Range::from(*self))
72 }
73}
74
75pub trait Spanned {
76 fn span(&self) -> Span;
77}
78
79impl Add for Span {
80 type Output = Self;
81
82 fn add(self, other: Self) -> Self {
83 use std::cmp::{max, min};
84
85 let file_id = if self.file_id == other.file_id {
86 self.file_id
87 } else {
88 panic!("file ids are not equal")
89 };
90
91 Self {
92 file_id,
93 start: min(self.start, other.start),
94 end: max(self.end, other.end),
95 }
96 }
97}
98
99impl Add<Option<Span>> for Span {
100 type Output = Self;
101
102 fn add(self, other: Option<Span>) -> Self {
103 if let Some(other) = other {
104 self + other
105 } else {
106 self
107 }
108 }
109}
110
111impl<'a, T> Add<Option<&'a T>> for Span
112where
113 Span: Add<&'a T, Output = Self>,
114{
115 type Output = Self;
116
117 fn add(self, other: Option<&'a T>) -> Self {
118 if let Some(other) = other {
119 self + other
120 } else {
121 self
122 }
123 }
124}
125
126impl<'a, T> Add<&'a T> for Span
127where
128 T: Spanned,
129{
130 type Output = Self;
131
132 fn add(self, other: &'a T) -> Self {
133 self + other.span()
134 }
135}
136
137impl<T> AddAssign<T> for Span
138where
139 Span: Add<T, Output = Self>,
140{
141 fn add_assign(&mut self, other: T) {
142 *self = *self + other
143 }
144}
145
146impl From<Span> for Range<usize> {
147 fn from(span: Span) -> Self {
148 Range {
149 start: span.start,
150 end: span.end,
151 }
152 }
153}