1use std::ops::Range;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct GlobalSpan {
9 pub start: usize,
10 pub end: usize,
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct FileSpan {
22 pub start: usize,
23 pub end: usize,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum LintSpan {
32 Global(GlobalSpan),
33 File(FileSpan),
34}
35
36impl GlobalSpan {
37 #[must_use]
38 pub const fn new(start: usize, end: usize) -> Self {
39 Self { start, end }
40 }
41
42 #[must_use]
44 pub const fn to_file_span(self, file_offset: usize) -> FileSpan {
45 FileSpan {
46 start: self.start.saturating_sub(file_offset),
47 end: self.end.saturating_sub(file_offset),
48 }
49 }
50
51 #[must_use]
53 pub fn merge(self, other: Self) -> Self {
54 Self {
55 start: self.start.min(other.start),
56 end: self.end.max(other.end),
57 }
58 }
59
60 #[must_use]
61 pub const fn len(&self) -> usize {
62 self.end.saturating_sub(self.start)
63 }
64
65 #[must_use]
66 pub const fn is_empty(&self) -> bool {
67 self.start >= self.end
68 }
69}
70
71impl FileSpan {
72 #[must_use]
73 pub const fn new(start: usize, end: usize) -> Self {
74 Self { start, end }
75 }
76
77 #[must_use]
79 pub const fn to_global_span(self, file_offset: usize) -> GlobalSpan {
80 GlobalSpan {
81 start: self.start + file_offset,
82 end: self.end + file_offset,
83 }
84 }
85
86 #[must_use]
88 pub fn merge(self, other: Self) -> Self {
89 Self {
90 start: self.start.min(other.start),
91 end: self.end.max(other.end),
92 }
93 }
94
95 #[must_use]
96 pub const fn len(&self) -> usize {
97 self.end.saturating_sub(self.start)
98 }
99
100 #[must_use]
101 pub const fn is_empty(&self) -> bool {
102 self.start >= self.end
103 }
104
105 #[must_use]
106 pub const fn as_range(&self) -> Range<usize> {
107 self.start..self.end
108 }
109}
110
111impl LintSpan {
112 #[must_use]
114 pub const fn to_file_span(self, file_offset: usize) -> FileSpan {
115 match self {
116 Self::Global(g) => g.to_file_span(file_offset),
117 Self::File(f) => f,
118 }
119 }
120
121 #[must_use]
125 pub fn file_span(&self) -> FileSpan {
126 match self {
127 Self::File(f) => *f,
128 Self::Global(_) => panic!("Span not normalized - call normalize_spans first"),
129 }
130 }
131}
132
133impl From<nu_protocol::Span> for GlobalSpan {
134 fn from(span: nu_protocol::Span) -> Self {
135 Self {
136 start: span.start,
137 end: span.end,
138 }
139 }
140}
141
142impl From<GlobalSpan> for nu_protocol::Span {
143 fn from(span: GlobalSpan) -> Self {
144 Self::new(span.start, span.end)
145 }
146}
147
148impl From<FileSpan> for nu_protocol::Span {
149 fn from(span: FileSpan) -> Self {
150 Self::new(span.start, span.end)
151 }
152}
153
154impl From<LintSpan> for nu_protocol::Span {
155 fn from(span: LintSpan) -> Self {
156 match span {
157 LintSpan::Global(g) => Self::new(g.start, g.end),
158 LintSpan::File(f) => Self::new(f.start, f.end),
159 }
160 }
161}
162
163impl From<nu_protocol::Span> for LintSpan {
164 fn from(span: nu_protocol::Span) -> Self {
165 Self::Global(GlobalSpan::from(span))
166 }
167}
168
169impl From<GlobalSpan> for LintSpan {
170 fn from(span: GlobalSpan) -> Self {
171 Self::Global(span)
172 }
173}
174
175impl From<FileSpan> for LintSpan {
176 fn from(span: FileSpan) -> Self {
177 Self::File(span)
178 }
179}