1use std::ops::{self, Add, Sub};
5use std::cmp::{min, max};
6use std::fmt;
7
8macro_rules! impl_math {
10 ($ty_name:ident, $trait_name:ident, $fun_name:ident) => {
11 impl $trait_name for $ty_name {
12 type Output = $ty_name;
13
14 fn $fun_name(self, rhs: $ty_name) -> $ty_name {
15 $ty_name($trait_name::$fun_name(self.0, rhs.0))
16 }
17 }
18 }
19}
20
21pub type SrcOffset = u32;
25
26#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
30pub struct BytePos(pub SrcOffset);
31
32impl_math!(BytePos, Add, add);
33impl_math!(BytePos, Sub, sub);
34
35
36#[derive(Clone, Copy, PartialEq, Eq)]
40pub struct Span {
41 pub lo: BytePos,
43 pub hi: BytePos,
45}
46
47impl Span {
48 pub fn single(pos: BytePos) -> Span {
50 Span { lo: pos, hi: pos + BytePos(1) }
51 }
52
53 pub fn empty_at(pos: BytePos) -> Span {
55 Span { lo: pos, hi: pos }
56 }
57
58 pub fn new(lo: BytePos, hi: BytePos) -> Span {
61 Span { lo: lo, hi: hi }
62 }
63
64 pub fn from_pair((lo, hi): (BytePos, BytePos)) -> Span {
66 Span { lo: lo, hi: hi }
67 }
68
69 pub fn dummy() -> Span {
71 Span { lo: BytePos(1), hi: BytePos(0) }
72 }
73
74 pub fn is_dummy(&self) -> bool {
76 self.lo.0 == 1 && self.hi.0 == 0
77 }
78
79 pub fn is_empty(&self) -> bool {
81 self.lo == self.hi
82 }
83
84 pub fn len(&self) -> SrcOffset {
87 if self.is_dummy() {
88 0
89 } else {
90 (self.hi - self.lo).0
91 }
92 }
93
94 pub fn hull(&self, other: &Self) -> Span {
99 if self.is_dummy() {
100 *other
101 } else if other.is_dummy() {
102 *self
103 } else {
104 Span {
105 lo: min(self.lo, other.lo),
106 hi: max(self.hi, other.hi),
107 }
108 }
109 }
110
111 pub fn contains(&self, other: Self) -> bool {
114 !self.is_dummy()
115 && !other.is_dummy()
116 && self.lo <= other.lo
117 && self.hi >= other.hi
118 }
119
120 pub fn into_range(self) -> ops::Range<usize> {
122 ops::Range {
123 start: self.lo.0 as usize,
124 end: self.hi.0 as usize,
125 }
126 }
127}
128
129impl fmt::Debug for Span {
131 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132 write!(f, "@({}, {})", self.lo.0, self.hi.0)
133 }
134}
135
136
137#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
140pub struct LineIdx(pub SrcOffset);
141
142impl fmt::Display for LineIdx {
143 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144 (self.0 + 1).fmt(f)
145 }
146}
147
148#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
150pub struct ColIdx(pub SrcOffset);
151
152impl_math!(LineIdx, Add, add);
153impl_math!(LineIdx, Sub, sub);
154impl_math!(ColIdx, Add, add);
155impl_math!(ColIdx, Sub, sub);
156
157
158#[derive(Clone, Copy, PartialEq, Eq, Debug)]
160pub struct Loc {
161 pub line: LineIdx,
162 pub col: ColIdx,
163}
164
165#[test]
167fn basic_spans() {
168 use super::Span;
169
170 let s = Span::new(BytePos(3), BytePos(10));
171 assert_eq!(s, Span { lo: BytePos(3), hi: BytePos(10) });
172 assert_eq!(s, Span::from_pair((BytePos(3), BytePos(10))));
173 assert_eq!(s.len(), 7);
174 assert!(!s.is_dummy());
175
176 assert!(s.contains(Span::new(BytePos(4), BytePos(9))));
177 assert!(s.contains(Span::new(BytePos(3), BytePos(10))));
178 assert!(s.contains(Span::new(BytePos(5), BytePos(10))));
179 assert!(s.contains(Span::new(BytePos(3), BytePos(8))));
180 assert!(!s.contains(Span::new(BytePos(2), BytePos(8))));
181 assert!(!s.contains(Span::new(BytePos(3), BytePos(11))));
182 assert!(!s.contains(Span::new(BytePos(1), BytePos(12))));
183 assert!(!s.contains(Span::dummy()));
184
185 assert_eq!(Span::single(BytePos(15)), Span::new(BytePos(15), BytePos(16)));
186}
187
188#[test]
189fn dummy_spans() {
190 use super::Span;
191
192 let d = Span::dummy();
193 assert_eq!(d, Span::dummy());
194 assert_eq!(d.len(), 0);
195 assert!(d.is_dummy());
196
197 assert!(!d.contains(Span::new(BytePos(4), BytePos(9))));
198 assert!(!d.contains(Span::new(BytePos(3), BytePos(0))));
199 assert!(!d.contains(Span::dummy()));
200}
201
202#[test]
203fn span_hulls() {
204 use super::Span;
205
206 let d = Span::dummy();
207 let a = Span::new(BytePos(1), BytePos(5));
208 let b = Span::new(BytePos(3), BytePos(7));
209 let c = Span::new(BytePos(7), BytePos(9));
210
211 assert_eq!(a.hull(&d), a);
212 assert_eq!(d.hull(&a), a);
213 assert_eq!(d.hull(&d), d);
214
215 assert_eq!(a.hull(&b), Span::new(BytePos(1), BytePos(7)));
216 assert_eq!(a.hull(&c), Span::new(BytePos(1), BytePos(9)));
217 assert_eq!(b.hull(&c), Span::new(BytePos(3), BytePos(9)));
218}