1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub struct Span {
7 pub start: usize,
8 pub end: usize,
9}
10
11impl Span {
12 #[inline]
14 pub fn new(start: usize, end: usize) -> Self {
15 debug_assert!(start <= end, "Span start ({start}) > end ({end})");
16 Self { start, end }
17 }
18
19 #[inline]
21 pub fn empty(offset: usize) -> Self {
22 Self {
23 start: offset,
24 end: offset,
25 }
26 }
27
28 #[inline]
30 pub fn len(&self) -> usize {
31 self.end - self.start
32 }
33
34 #[inline]
36 pub fn is_empty(&self) -> bool {
37 self.start == self.end
38 }
39
40 #[inline]
42 pub fn contains(&self, other: &Span) -> bool {
43 self.start <= other.start && other.end <= self.end
44 }
45
46 #[inline]
48 pub fn merge(&self, other: &Span) -> Span {
49 Span {
50 start: self.start.min(other.start),
51 end: self.end.max(other.end),
52 }
53 }
54
55 #[inline]
57 pub fn slice<'a>(&self, source: &'a str) -> &'a str {
58 &source[self.start..self.end]
59 }
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
64pub struct NodeId(pub usize);
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn span_basics() {
72 let s = Span::new(2, 7);
73 assert_eq!(s.len(), 5);
74 assert!(!s.is_empty());
75
76 let e = Span::empty(3);
77 assert_eq!(e.len(), 0);
78 assert!(e.is_empty());
79 }
80
81 #[test]
82 fn span_contains() {
83 let outer = Span::new(0, 10);
84 let inner = Span::new(2, 5);
85 assert!(outer.contains(&inner));
86 assert!(!inner.contains(&outer));
87 }
88
89 #[test]
90 fn span_merge() {
91 let a = Span::new(0, 5);
92 let b = Span::new(3, 10);
93 let m = a.merge(&b);
94 assert_eq!(m, Span::new(0, 10));
95 }
96
97 #[test]
98 fn span_slice() {
99 let src = "hello world";
100 let s = Span::new(6, 11);
101 assert_eq!(s.slice(src), "world");
102 }
103}