1 | use std::num::NonZeroUsize; |
2 | |
3 | use bstr::{ByteSlice, Utf8Error}; |
4 | |
5 | use crate::rustc_stderr::Span; |
6 | |
7 | #[derive (Default, Debug, Clone, Copy)] |
8 | pub struct MaybeSpanned<T> { |
9 | data: T, |
10 | span: Option<Span>, |
11 | } |
12 | |
13 | impl<T> std::ops::Deref for MaybeSpanned<T> { |
14 | type Target = T; |
15 | |
16 | fn deref(&self) -> &Self::Target { |
17 | &self.data |
18 | } |
19 | } |
20 | |
21 | impl<T> MaybeSpanned<T> { |
22 | /// Values from the `Config` struct don't have lines. |
23 | pub fn new_config(data: T) -> Self { |
24 | Self { data, span: None } |
25 | } |
26 | |
27 | pub fn span(&self) -> Option<Span> { |
28 | self.span |
29 | } |
30 | |
31 | pub fn into_inner(self) -> T { |
32 | self.data |
33 | } |
34 | } |
35 | |
36 | impl<T> From<Spanned<T>> for MaybeSpanned<T> { |
37 | fn from(value: Spanned<T>) -> Self { |
38 | Self { |
39 | data: value.data, |
40 | span: Some(value.span), |
41 | } |
42 | } |
43 | } |
44 | |
45 | #[derive (Debug, Clone, Copy)] |
46 | pub struct Spanned<T> { |
47 | data: T, |
48 | span: Span, |
49 | } |
50 | |
51 | impl<T> std::ops::Deref for Spanned<T> { |
52 | type Target = T; |
53 | |
54 | fn deref(&self) -> &Self::Target { |
55 | &self.data |
56 | } |
57 | } |
58 | |
59 | impl<'a> Spanned<&'a str> { |
60 | pub fn strip_prefix(&self, prefix: &str) -> Option<Self> { |
61 | let data = self.data.strip_prefix(prefix)?; |
62 | let mut span = self.span; |
63 | span.column_start = |
64 | NonZeroUsize::new(span.column_start.get() + prefix.chars().count()).unwrap(); |
65 | Some(Self { span, data }) |
66 | } |
67 | |
68 | pub fn strip_suffix(&self, suffix: &str) -> Option<Self> { |
69 | let data = self.data.strip_suffix(suffix)?; |
70 | let mut span = self.span; |
71 | span.column_end = |
72 | NonZeroUsize::new(span.column_end.get() - suffix.chars().count()).unwrap(); |
73 | Some(Self { span, data }) |
74 | } |
75 | |
76 | pub fn trim_start(&self) -> Self { |
77 | let data = self.data.trim_start(); |
78 | let mut span = self.span; |
79 | span.column_start = NonZeroUsize::new( |
80 | span.column_start.get() + self.data.chars().count() - data.chars().count(), |
81 | ) |
82 | .unwrap(); |
83 | Self { data, span } |
84 | } |
85 | |
86 | pub fn trim_end(&self) -> Self { |
87 | let data = self.data.trim_end(); |
88 | let mut span = self.span; |
89 | span.column_end = NonZeroUsize::new( |
90 | span.column_end.get() - (self.data.chars().count() - data.chars().count()), |
91 | ) |
92 | .unwrap(); |
93 | Self { data, span } |
94 | } |
95 | |
96 | pub fn trim(&self) -> Self { |
97 | self.trim_start().trim_end() |
98 | } |
99 | |
100 | pub fn split_at(&self, i: usize) -> (Self, Self) { |
101 | let (a, b) = self.data.split_at(i); |
102 | ( |
103 | Self { |
104 | data: a, |
105 | span: Span { |
106 | column_end: NonZeroUsize::new(self.span.column_start.get() + a.chars().count()) |
107 | .unwrap(), |
108 | ..self.span |
109 | }, |
110 | }, |
111 | Self { |
112 | data: b, |
113 | span: Span { |
114 | column_start: NonZeroUsize::new( |
115 | self.span.column_start.get() + a.chars().count(), |
116 | ) |
117 | .unwrap(), |
118 | ..self.span |
119 | }, |
120 | }, |
121 | ) |
122 | } |
123 | |
124 | pub fn split_once(&self, splitter: &str) -> Option<(Self, Self)> { |
125 | let (a, b) = self.data.split_once(splitter)?; |
126 | Some(( |
127 | Self { |
128 | data: a, |
129 | span: Span { |
130 | column_end: NonZeroUsize::new(self.span.column_start.get() + a.chars().count()) |
131 | .unwrap(), |
132 | ..self.span |
133 | }, |
134 | }, |
135 | Self { |
136 | data: b, |
137 | span: Span { |
138 | column_start: NonZeroUsize::new( |
139 | self.span.column_start.get() + a.chars().count() + splitter.chars().count(), |
140 | ) |
141 | .unwrap(), |
142 | ..self.span |
143 | }, |
144 | }, |
145 | )) |
146 | } |
147 | } |
148 | |
149 | impl<'a> Spanned<&'a [u8]> { |
150 | pub fn strip_prefix(&self, prefix: &[u8]) -> Option<Self> { |
151 | let data = self.data.strip_prefix(prefix)?; |
152 | let mut span = self.span; |
153 | span.column_start = NonZeroUsize::new(span.column_start.get() + prefix.len()).unwrap(); |
154 | Some(Self { span, data }) |
155 | } |
156 | |
157 | pub fn split_once_str(&self, splitter: &str) -> Option<(Self, Self)> { |
158 | let (a, b) = self.data.split_once_str(splitter)?; |
159 | Some(( |
160 | Self { |
161 | data: a, |
162 | span: Span { |
163 | column_end: NonZeroUsize::new(self.span.column_start.get() + a.len()).unwrap(), |
164 | ..self.span |
165 | }, |
166 | }, |
167 | Self { |
168 | data: b, |
169 | span: Span { |
170 | column_start: NonZeroUsize::new( |
171 | self.span.column_start.get() + a.len() + splitter.len(), |
172 | ) |
173 | .unwrap(), |
174 | ..self.span |
175 | }, |
176 | }, |
177 | )) |
178 | } |
179 | |
180 | pub fn to_str(self) -> Result<Spanned<&'a str>, Utf8Error> { |
181 | Ok(Spanned { |
182 | data: self.data.to_str()?, |
183 | span: self.span, |
184 | }) |
185 | } |
186 | } |
187 | |
188 | impl<T> Spanned<T> { |
189 | pub fn new(data: T, span: Span) -> Self { |
190 | Self { data, span } |
191 | } |
192 | |
193 | pub fn line(&self) -> NonZeroUsize { |
194 | self.span.line_start |
195 | } |
196 | |
197 | pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Spanned<U> { |
198 | Spanned { |
199 | data: f(self.data), |
200 | span: self.span, |
201 | } |
202 | } |
203 | |
204 | pub fn into_inner(self) -> T { |
205 | self.data |
206 | } |
207 | |
208 | pub fn span(&self) -> Span { |
209 | self.span |
210 | } |
211 | } |
212 | |
213 | #[derive (Debug, Clone, Copy)] |
214 | pub struct OptWithLine<T>(Option<Spanned<T>>); |
215 | |
216 | impl<T> std::ops::Deref for OptWithLine<T> { |
217 | type Target = Option<Spanned<T>>; |
218 | |
219 | fn deref(&self) -> &Self::Target { |
220 | &self.0 |
221 | } |
222 | } |
223 | |
224 | impl<T> From<Option<Spanned<T>>> for OptWithLine<T> { |
225 | fn from(value: Option<Spanned<T>>) -> Self { |
226 | Self(value) |
227 | } |
228 | } |
229 | |
230 | impl<T> From<Spanned<T>> for OptWithLine<T> { |
231 | fn from(value: Spanned<T>) -> Self { |
232 | Self(Some(value)) |
233 | } |
234 | } |
235 | |
236 | impl<T> Default for OptWithLine<T> { |
237 | fn default() -> Self { |
238 | Self(Default::default()) |
239 | } |
240 | } |
241 | |
242 | impl<T> OptWithLine<T> { |
243 | pub fn new(data: T, span: Span) -> Self { |
244 | Self(Some(Spanned::new(data, span))) |
245 | } |
246 | |
247 | /// Tries to set the value if not already set. Returns newly passed |
248 | /// value in case there was already a value there. |
249 | #[must_use ] |
250 | pub fn set(&mut self, data: T, span: Span) -> Option<Spanned<T>> { |
251 | let new: Spanned = Spanned::new(data, span); |
252 | if self.0.is_some() { |
253 | Some(new) |
254 | } else { |
255 | self.0 = Some(new); |
256 | None |
257 | } |
258 | } |
259 | |
260 | #[must_use ] |
261 | pub fn into_inner(self) -> Option<Spanned<T>> { |
262 | self.0 |
263 | } |
264 | } |
265 | |