1use serde::{Deserialize, Serialize};
7use std::fmt;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
11pub struct Span {
12 pub start: u32,
14 pub end: u32,
16 pub file_id: u32,
18}
19
20impl Span {
21 pub const fn new(start: u32, end: u32, file_id: u32) -> Self {
23 Self {
24 start,
25 end,
26 file_id,
27 }
28 }
29
30 pub const fn dummy() -> Self {
32 Self {
33 start: 0,
34 end: 0,
35 file_id: 0,
36 }
37 }
38
39 pub fn merge(self, other: Self) -> Self {
41 assert_eq!(
42 self.file_id, other.file_id,
43 "Cannot merge spans from different files"
44 );
45 Self {
46 start: self.start.min(other.start),
47 end: self.end.max(other.end),
48 file_id: self.file_id,
49 }
50 }
51
52 pub fn to(self, other: Self) -> Self {
54 assert_eq!(
55 self.file_id, other.file_id,
56 "Cannot combine spans from different files"
57 );
58 Self {
59 start: self.start,
60 end: other.end,
61 file_id: self.file_id,
62 }
63 }
64
65 pub const fn contains(&self, offset: u32) -> bool {
67 offset >= self.start && offset < self.end
68 }
69
70 pub const fn len(&self) -> u32 {
72 self.end - self.start
73 }
74
75 pub const fn is_empty(&self) -> bool {
77 self.start == self.end
78 }
79}
80
81impl Default for Span {
82 fn default() -> Self {
83 Self::dummy()
84 }
85}
86
87impl fmt::Display for Span {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 write!(f, "{}:{}-{}", self.file_id, self.start, self.end)
90 }
91}
92
93#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
95pub struct Spanned<T> {
96 pub node: T,
97 pub span: Span,
98}
99
100impl<T> Spanned<T> {
101 pub const fn new(node: T, span: Span) -> Self {
102 Self { node, span }
103 }
104
105 pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Spanned<U> {
106 Spanned {
107 node: f(self.node),
108 span: self.span,
109 }
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn test_span_merge() {
119 let span1 = Span::new(10, 20, 0);
120 let span2 = Span::new(15, 30, 0);
121 let merged = span1.merge(span2);
122 assert_eq!(merged.start, 10);
123 assert_eq!(merged.end, 30);
124 }
125
126 #[test]
127 fn test_span_contains() {
128 let span = Span::new(10, 20, 0);
129 assert!(span.contains(15));
130 assert!(!span.contains(5));
131 assert!(!span.contains(25));
132 }
133
134 #[test]
135 fn test_span_len() {
136 let span = Span::new(10, 25, 0);
137 assert_eq!(span.len(), 15);
138 }
139}