1#[cfg(test)]
4#[path = "./span_tests.rs"]
5mod tests;
6
7#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
12pub struct Span {
13 pub start: u32,
15 pub end: u32,
17}
18
19impl Span {
20 #[inline]
22 pub fn new(start: u32, end: u32) -> Self {
23 Self { start, end }
24 }
25 pub fn range(self) -> std::ops::Range<usize> {
27 self.start as usize..self.end as usize
28 }
29
30 #[inline]
32 pub fn is_empty(&self) -> bool {
33 self.start == 0 && self.end == 0
34 }
35
36 pub fn grow_key_to_header(&mut self, text: &[u8]) {
41 let mut start = self.start as usize;
42 while start > 0 && text[start - 1] != b'\n' {
43 start -= 1;
44 }
45 while text[start] != b'[' {
47 start += 1;
48 }
49 let end = find_header_end(text, start);
50 self.start = start as u32;
51 self.end = end as u32;
52 }
53
54 pub fn extract_header_span(&self, text: &[u8]) -> Span {
59 let start = self.start as usize;
60 let end = find_header_end(text, start);
61 Span::new(self.start, end as u32)
62 }
63}
64
65fn find_header_end(text: &[u8], start: usize) -> usize {
68 let mut pos = start;
69 debug_assert!(text[pos] == b'[');
70 pos += 1;
71 let is_aot = text[pos] == b'[';
72 if is_aot {
73 pos += 1;
74 }
75 loop {
76 match text[pos] {
77 b']' => {
78 pos += 1;
79 if is_aot {
80 pos += 1;
81 }
82 return pos;
83 }
84 b'"' => {
85 pos += 1;
86 while text[pos] != b'"' {
87 if text[pos] == b'\\' {
88 pos += 1;
89 }
90 pos += 1;
91 }
92 pos += 1;
93 }
94 b'\'' => {
95 pos += 1;
96 while text[pos] != b'\'' {
97 pos += 1;
98 }
99 pos += 1;
100 }
101 _ => pos += 1,
102 }
103 }
104}
105
106impl From<Span> for (u32, u32) {
107 fn from(s: Span) -> (u32, u32) {
108 (s.start, s.end)
109 }
110}
111
112impl From<Span> for (usize, usize) {
113 fn from(s: Span) -> (usize, usize) {
114 (s.start as usize, s.end as usize)
115 }
116}
117
118impl From<std::ops::Range<u32>> for Span {
119 fn from(s: std::ops::Range<u32>) -> Self {
120 Self::new(s.start, s.end)
121 }
122}
123
124impl From<Span> for std::ops::Range<u32> {
125 fn from(s: Span) -> Self {
126 s.start..s.end
127 }
128}
129
130impl From<Span> for std::ops::Range<usize> {
131 fn from(s: Span) -> Self {
132 s.start as usize..s.end as usize
133 }
134}
135
136pub struct Spanned<T> {
157 pub value: T,
159 pub span: Span,
161}
162
163impl<T> Spanned<T> {
164 #[inline]
166 pub const fn new(value: T) -> Self {
167 Self {
168 value,
169 span: Span { start: 0, end: 0 },
170 }
171 }
172
173 #[inline]
175 pub const fn with_span(value: T, span: Span) -> Self {
176 Self { value, span }
177 }
178
179 #[inline]
181 pub fn take(self) -> T {
182 self.value
183 }
184
185 #[inline]
187 pub fn map<V>(self) -> Spanned<V>
188 where
189 V: From<T>,
190 {
191 Spanned {
192 value: self.value.into(),
193 span: self.span,
194 }
195 }
196}
197
198impl<T> Default for Spanned<T>
199where
200 T: Default,
201{
202 fn default() -> Self {
203 Self {
204 value: Default::default(),
205 span: Span::default(),
206 }
207 }
208}
209
210impl<T> AsRef<T> for Spanned<T> {
211 fn as_ref(&self) -> &T {
212 &self.value
213 }
214}
215
216impl<T> std::fmt::Debug for Spanned<T>
217where
218 T: std::fmt::Debug,
219{
220 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
221 self.value.fmt(f)
222 }
223}
224
225impl<T> Clone for Spanned<T>
226where
227 T: Clone,
228{
229 fn clone(&self) -> Self {
230 Self {
231 value: self.value.clone(),
232 span: self.span,
233 }
234 }
235}
236
237impl<T> PartialOrd for Spanned<T>
238where
239 T: PartialOrd,
240{
241 fn partial_cmp(&self, o: &Spanned<T>) -> Option<std::cmp::Ordering> {
242 self.value.partial_cmp(&o.value)
243 }
244}
245
246impl<T> Ord for Spanned<T>
247where
248 T: Ord,
249{
250 fn cmp(&self, o: &Spanned<T>) -> std::cmp::Ordering {
251 self.value.cmp(&o.value)
252 }
253}
254
255impl<T> PartialEq for Spanned<T>
256where
257 T: PartialEq,
258{
259 fn eq(&self, o: &Spanned<T>) -> bool {
260 self.value == o.value
261 }
262}
263
264impl<T> Eq for Spanned<T> where T: Eq {}
265
266impl<T> PartialEq<T> for Spanned<T>
267where
268 T: PartialEq,
269{
270 fn eq(&self, o: &T) -> bool {
271 &self.value == o
272 }
273}
274
275#[cfg(feature = "to-toml")]
276impl<T: crate::ser::ToToml> crate::ser::ToToml for Spanned<T> {
277 fn to_toml<'a>(
278 &'a self,
279 arena: &'a crate::Arena,
280 ) -> Result<crate::Item<'a>, crate::ser::ToTomlError> {
281 self.value.to_toml(arena)
282 }
283}
284
285#[cfg(feature = "from-toml")]
286impl<'de, T> crate::de::FromToml<'de> for Spanned<T>
287where
288 T: crate::de::FromToml<'de>,
289{
290 #[inline]
291 fn from_toml(
292 ctx: &mut crate::de::Context<'de>,
293 value: &crate::item::Item<'de>,
294 ) -> Result<Self, crate::de::Failed> {
295 let span = value.span_unchecked();
296 let inner = T::from_toml(ctx, value)?;
297 Ok(Self { span, value: inner })
298 }
299}