nom_locate/lib.rs
1//! nom_locate, a special input type to locate tokens
2//!
3//! The source code is available on [Github](https://github.com/fflorent/nom_locate)
4//!
5//! ## Features
6//!
7//! This crate exposes two cargo feature flags, `generic-simd` and `runtime-dispatch-simd`.
8//! These correspond to the features exposed by [bytecount](https://github.com/llogiq/bytecount).
9//!
10//! ## How to use it
11//! The explanations are given in the [README](https://github.com/fflorent/nom_locate/blob/master/README.md) of the Github repository. You may also consult the [FAQ](https://github.com/fflorent/nom_locate/blob/master/FAQ.md).
12//!
13//! ```
14//! use nom::bytes::complete::{tag, take_until};
15//! use nom::IResult;
16//! use nom_locate::{position, LocatedSpan};
17//!
18//! type Span<'a> = LocatedSpan<&'a str>;
19//!
20//! struct Token<'a> {
21//! pub position: Span<'a>,
22//! pub foo: &'a str,
23//! pub bar: &'a str,
24//! }
25//!
26//! fn parse_foobar(s: Span) -> IResult<Span, Token> {
27//! let (s, _) = take_until("foo")(s)?;
28//! let (s, pos) = position(s)?;
29//! let (s, foo) = tag("foo")(s)?;
30//! let (s, bar) = tag("bar")(s)?;
31//!
32//! Ok((
33//! s,
34//! Token {
35//! position: pos,
36//! foo: foo.fragment(),
37//! bar: bar.fragment(),
38//! },
39//! ))
40//! }
41//!
42//! fn main () {
43//! let input = Span::new("Lorem ipsum \n foobar");
44//! let output = parse_foobar(input);
45//! let position = output.unwrap().1.position;
46//! assert_eq!(position.location_offset(), 14);
47//! assert_eq!(position.location_line(), 2);
48//! assert_eq!(position.fragment(), &"");
49//! assert_eq!(position.get_column(), 2);
50//! }
51//! ```
52//!
53//! ## Extra information
54//!
55//! You can also add arbitrary extra information using the extra property of `LocatedSpan`.
56//! This property is not used when comparing two `LocatedSpan`s.
57//!
58//! ```ignore
59//! use nom_locate::LocatedSpan;
60//! type Span<'a> = LocatedSpan<&'a str, String>;
61//!
62//! let input = Span::new_extra("Lorem ipsum \n foobar", "filename");
63//! let output = parse_foobar(input);
64//! let extra = output.unwrap().1.extra;
65//! ```
66
67#![cfg_attr(not(feature = "std"), no_std)]
68
69#[cfg(all(not(feature = "std"), feature = "alloc"))]
70#[cfg_attr(test, macro_use)]
71extern crate alloc;
72
73#[cfg(test)]
74mod tests;
75
76mod lib {
77 #[cfg(feature = "std")]
78 pub mod std {
79 pub use std::fmt::{Display, Formatter, Result as FmtResult};
80 pub use std::hash::{Hash, Hasher};
81 pub use std::iter::{Copied, Enumerate};
82 pub use std::ops::{Range, RangeFrom, RangeFull, RangeTo};
83 pub use std::slice;
84 pub use std::slice::Iter;
85 pub use std::str::{CharIndices, Chars, FromStr};
86 pub use std::string::{String, ToString};
87 pub use std::vec::Vec;
88 }
89
90 #[cfg(not(feature = "std"))]
91 pub mod std {
92 #[cfg(feature = "alloc")]
93 pub use alloc::fmt::{Display, Formatter, Result as FmtResult};
94 #[cfg(feature = "alloc")]
95 pub use alloc::string::{String, ToString};
96 #[cfg(feature = "alloc")]
97 pub use alloc::vec::Vec;
98 pub use core::hash::{Hash, Hasher};
99 pub use core::iter::{Copied, Enumerate};
100 pub use core::ops::{Range, RangeFrom, RangeFull, RangeTo};
101 pub use core::slice;
102 pub use core::slice::Iter;
103 pub use core::str::{CharIndices, Chars, FromStr};
104 }
105}
106
107use lib::std::*;
108
109use bytecount::{naive_num_chars, num_chars};
110use memchr::Memchr;
111#[cfg(feature = "alloc")]
112use nom::ExtendInto;
113use nom::{
114 error::{ErrorKind, ParseError},
115 AsBytes, Compare, CompareResult, Err, FindSubstring, FindToken, IResult, InputIter,
116 InputLength, InputTake, InputTakeAtPosition, Offset, ParseTo, Slice,
117};
118#[cfg(feature = "stable-deref-trait")]
119use stable_deref_trait::StableDeref;
120
121/// A LocatedSpan is a set of meta information about the location of a token, including extra
122/// information.
123///
124/// The `LocatedSpan` structure can be used as an input of the nom parsers.
125/// It implements all the necessary traits for `LocatedSpan<&str,X>` and `LocatedSpan<&[u8],X>`
126#[derive(Debug, Clone, Copy)]
127pub struct LocatedSpan<T, X = ()> {
128 /// The offset represents the position of the fragment relatively to
129 /// the input of the parser. It starts at offset 0.
130 offset: usize,
131
132 /// The line number of the fragment relatively to the input of the
133 /// parser. It starts at line 1.
134 line: u32,
135
136 /// The fragment that is spanned.
137 /// The fragment represents a part of the input of the parser.
138 fragment: T,
139
140 /// Extra information that can be embedded by the user.
141 /// Example: the parsed file name
142 pub extra: X,
143}
144
145impl<T, X> core::ops::Deref for LocatedSpan<T, X> {
146 type Target = T;
147 fn deref(&self) -> &Self::Target {
148 &self.fragment
149 }
150}
151
152impl<T, U, X> core::convert::AsRef<U> for LocatedSpan<&T, X>
153where
154 T: ?Sized + core::convert::AsRef<U>,
155 U: ?Sized,
156{
157 fn as_ref(&self) -> &U {
158 self.fragment.as_ref()
159 }
160}
161
162#[cfg(feature = "stable-deref-trait")]
163/// Optionally impl StableDeref so that this type works harmoniously with other
164/// crates that rely on this marker trait, such as `rental` and `lazy_static`.
165/// LocatedSpan is largely just a wrapper around the contained type `T`, so
166/// this marker trait is safe to implement whenever T already implements
167/// StableDeref.
168unsafe impl<T: StableDeref, X> StableDeref for LocatedSpan<T, X> {}
169
170impl<T> LocatedSpan<T, ()> {
171 /// Create a span for a particular input with default `offset` and
172 /// `line` values and empty extra data.
173 /// You can compute the column through the `get_column` or `get_utf8_column`
174 /// methods.
175 ///
176 /// `offset` starts at 0, `line` starts at 1, and `column` starts at 1.
177 ///
178 /// Do not use this constructor in parser functions; `nom` and
179 /// `nom_locate` assume span offsets are relative to the beginning of the
180 /// same input. In these cases, you probably want to use the
181 /// `nom::traits::Slice` trait instead.
182 ///
183 /// # Example of use
184 ///
185 /// ```
186 /// # extern crate nom_locate;
187 /// use nom_locate::LocatedSpan;
188 ///
189 /// # fn main() {
190 /// let span = LocatedSpan::new(b"foobar");
191 ///
192 /// assert_eq!(span.location_offset(), 0);
193 /// assert_eq!(span.location_line(), 1);
194 /// assert_eq!(span.get_column(), 1);
195 /// assert_eq!(span.fragment(), &&b"foobar"[..]);
196 /// # }
197 /// ```
198 pub fn new(program: T) -> LocatedSpan<T, ()> {
199 LocatedSpan {
200 offset: 0,
201 line: 1,
202 fragment: program,
203 extra: (),
204 }
205 }
206}
207
208impl<T, X> LocatedSpan<T, X> {
209 /// Create a span for a particular input with default `offset` and
210 /// `line` values. You can compute the column through the `get_column` or `get_utf8_column`
211 /// methods.
212 ///
213 /// `offset` starts at 0, `line` starts at 1, and `column` starts at 1.
214 ///
215 /// Do not use this constructor in parser functions; `nom` and
216 /// `nom_locate` assume span offsets are relative to the beginning of the
217 /// same input. In these cases, you probably want to use the
218 /// `nom::traits::Slice` trait instead.
219 ///
220 /// # Example of use
221 ///
222 /// ```
223 /// # extern crate nom_locate;
224 /// use nom_locate::LocatedSpan;
225 ///
226 /// # fn main() {
227 /// let span = LocatedSpan::new_extra(b"foobar", "extra");
228 ///
229 /// assert_eq!(span.location_offset(), 0);
230 /// assert_eq!(span.location_line(), 1);
231 /// assert_eq!(span.get_column(), 1);
232 /// assert_eq!(span.fragment(), &&b"foobar"[..]);
233 /// assert_eq!(span.extra, "extra");
234 /// # }
235 /// ```
236 pub fn new_extra(program: T, extra: X) -> LocatedSpan<T, X> {
237 LocatedSpan {
238 offset: 0,
239 line: 1,
240 fragment: program,
241 extra: extra,
242 }
243 }
244
245 /// Similar to `new_extra`, but allows overriding offset and line.
246 /// This is unsafe, because giving an offset too large may result in
247 /// undefined behavior, as some methods move back along the fragment
248 /// assuming any negative index within the offset is valid.
249 pub unsafe fn new_from_raw_offset(
250 offset: usize,
251 line: u32,
252 fragment: T,
253 extra: X,
254 ) -> LocatedSpan<T, X> {
255 LocatedSpan {
256 offset,
257 line,
258 fragment,
259 extra,
260 }
261 }
262
263 /// The offset represents the position of the fragment relatively to
264 /// the input of the parser. It starts at offset 0.
265 pub fn location_offset(&self) -> usize {
266 self.offset
267 }
268
269 /// The line number of the fragment relatively to the input of the
270 /// parser. It starts at line 1.
271 pub fn location_line(&self) -> u32 {
272 self.line
273 }
274
275 /// The fragment that is spanned.
276 /// The fragment represents a part of the input of the parser.
277 pub fn fragment(&self) -> &T {
278 &self.fragment
279 }
280
281 /// Transform the extra inside into another type
282 ///
283 /// # Example of use
284 /// ```
285 /// # extern crate nom_locate;
286 /// # extern crate nom;
287 /// # use nom_locate::LocatedSpan;
288 /// use nom::{
289 /// IResult,
290 /// combinator::{recognize, map_res},
291 /// sequence::{terminated, tuple},
292 /// character::{complete::{char, one_of}, is_digit},
293 /// bytes::complete::{tag, take_while1}
294 /// };
295 ///
296 /// fn decimal(input: LocatedSpan<&str>) -> IResult<LocatedSpan<&str>, LocatedSpan<&str>> {
297 /// recognize(
298 /// take_while1(|c| is_digit(c as u8) || c == '_')
299 /// )(input)
300 /// }
301 ///
302 /// fn main() {
303 /// let span = LocatedSpan::new("$10");
304 /// // matches the $ and then matches the decimal number afterwards,
305 /// // converting it into a `u8` and putting that value in the span
306 /// let (_, (_, n)) = tuple((
307 /// tag("$"),
308 /// map_res(
309 /// decimal,
310 /// |x| x.fragment().parse::<u8>().map(|n| x.map_extra(|_| n))
311 /// )
312 /// ))(span).unwrap();
313 /// assert_eq!(n.extra, 10);
314 /// }
315 /// ```
316 pub fn map_extra<U, F: FnOnce(X) -> U>(self, f: F) -> LocatedSpan<T, U> {
317 LocatedSpan {
318 offset: self.offset,
319 line: self.line,
320 fragment: self.fragment,
321 extra: f(self.extra),
322 }
323 }
324
325 /// Takes ownership of the fragment without (re)borrowing it.
326 ///
327 /// # Example of use
328 /// ```
329 /// # extern crate nom_locate;
330 /// # extern crate nom;
331 /// # use nom_locate::LocatedSpan;
332 /// use nom::{
333 /// IResult,
334 /// bytes::complete::{take_till, tag},
335 /// combinator::rest,
336 /// };
337 ///
338 /// fn parse_pair<'a>(input: LocatedSpan<&'a str>) -> IResult<LocatedSpan<&'a str>, (&'a str, &'a str)> {
339 /// let (input, key) = take_till(|c| c == '=')(input)?;
340 /// let (input, _) = tag("=")(input)?;
341 /// let (input, value) = rest(input)?;
342 ///
343 /// Ok((input, (key.into_fragment(), value.into_fragment())))
344 /// }
345 ///
346 /// fn main() {
347 /// let span = LocatedSpan::new("key=value");
348 /// let (_, pair) = parse_pair(span).unwrap();
349 /// assert_eq!(pair, ("key", "value"));
350 /// }
351 /// ```
352 pub fn into_fragment(self) -> T {
353 self.fragment
354 }
355
356 /// Takes ownership of the fragment and extra data without (re)borrowing them.
357 pub fn into_fragment_and_extra(self) -> (T, X) {
358 (self.fragment, self.extra)
359 }
360}
361
362impl<T: AsBytes, X> LocatedSpan<T, X> {
363 // Attempt to get the "original" data slice back, by extending
364 // self.fragment backwards by self.offset.
365 // Note that any bytes truncated from after self.fragment will not
366 // be recovered.
367 fn get_unoffsetted_slice(&self) -> &[u8] {
368 let self_bytes = self.fragment.as_bytes();
369 let self_ptr = self_bytes.as_ptr();
370 unsafe {
371 assert!(
372 self.offset <= isize::max_value() as usize,
373 "offset is too big"
374 );
375 let orig_input_ptr = self_ptr.offset(-(self.offset as isize));
376 slice::from_raw_parts(orig_input_ptr, self.offset + self_bytes.len())
377 }
378 }
379
380 fn get_columns_and_bytes_before(&self) -> (usize, &[u8]) {
381 let before_self = &self.get_unoffsetted_slice()[..self.offset];
382
383 let column = match memchr::memrchr(b'\n', before_self) {
384 None => self.offset + 1,
385 Some(pos) => self.offset - pos,
386 };
387
388 (column, &before_self[self.offset - (column - 1)..])
389 }
390
391 /// Return the line that contains this LocatedSpan.
392 ///
393 /// The `get_column` and `get_utf8_column` functions returns
394 /// indexes that corresponds to the line returned by this function.
395 ///
396 /// Note that if this LocatedSpan ends before the end of the
397 /// original data, the result of calling `get_line_beginning()`
398 /// will not include any data from after the LocatedSpan.
399 ///
400 /// ```
401 /// # extern crate nom_locate;
402 /// # extern crate nom;
403 /// # use nom_locate::LocatedSpan;
404 /// # use nom::{Slice, FindSubstring};
405 /// #
406 /// # fn main() {
407 /// let program = LocatedSpan::new(
408 /// "Hello World!\
409 /// \nThis is a multi-line input\
410 /// \nthat ends after this line.\n");
411 /// let multi = program.find_substring("multi").unwrap();
412 ///
413 /// assert_eq!(
414 /// program.slice(multi..).get_line_beginning(),
415 /// "This is a multi-line input".as_bytes(),
416 /// );
417 /// # }
418 /// ```
419 pub fn get_line_beginning(&self) -> &[u8] {
420 let column0 = self.get_column() - 1;
421 let the_line = &self.get_unoffsetted_slice()[self.offset - column0..];
422 match memchr::memchr(b'\n', &the_line[column0..]) {
423 None => the_line,
424 Some(pos) => &the_line[..column0 + pos],
425 }
426 }
427
428 /// Return the column index, assuming 1 byte = 1 column.
429 ///
430 /// Use it for ascii text, or use get_utf8_column for UTF8.
431 ///
432 /// # Example of use
433 /// ```
434 ///
435 /// # extern crate nom_locate;
436 /// # extern crate nom;
437 /// # use nom_locate::LocatedSpan;
438 /// # use nom::Slice;
439 /// #
440 /// # fn main() {
441 /// let span = LocatedSpan::new("foobar");
442 ///
443 /// assert_eq!(span.slice(3..).get_column(), 4);
444 /// # }
445 /// ```
446 pub fn get_column(&self) -> usize {
447 self.get_columns_and_bytes_before().0
448 }
449
450 /// Return the column index for UTF8 text. Return value is unspecified for non-utf8 text.
451 ///
452 /// This version uses bytecount's hyper algorithm to count characters. This is much faster
453 /// for long lines, but is non-negligibly slower for short slices (below around 100 bytes).
454 /// This is also sped up significantly more depending on architecture and enabling the simd
455 /// feature gates. If you expect primarily short lines, you may get a noticeable speedup in
456 /// parsing by using `naive_get_utf8_column` instead. Benchmark your specific use case!
457 ///
458 /// # Example of use
459 /// ```
460 ///
461 /// # extern crate nom_locate;
462 /// # extern crate nom;
463 /// # use nom_locate::LocatedSpan;
464 /// # use nom::{Slice, FindSubstring};
465 /// #
466 /// # fn main() {
467 /// let span = LocatedSpan::new("メカジキ");
468 /// let indexOf3dKanji = span.find_substring("ジ").unwrap();
469 ///
470 /// assert_eq!(span.slice(indexOf3dKanji..).get_column(), 7);
471 /// assert_eq!(span.slice(indexOf3dKanji..).get_utf8_column(), 3);
472 /// # }
473 /// ```
474 pub fn get_utf8_column(&self) -> usize {
475 let before_self = self.get_columns_and_bytes_before().1;
476 num_chars(before_self) + 1
477 }
478
479 /// Return the column index for UTF8 text. Return value is unspecified for non-utf8 text.
480 ///
481 /// A simpler implementation of `get_utf8_column` that may be faster on shorter lines.
482 /// If benchmarking shows that this is faster, you can use it instead of `get_utf8_column`.
483 /// Prefer defaulting to `get_utf8_column` unless this legitimately is a performance bottleneck.
484 ///
485 /// # Example of use
486 /// ```
487 ///
488 /// # extern crate nom_locate;
489 /// # extern crate nom;
490 /// # use nom_locate::LocatedSpan;
491 /// # use nom::{Slice, FindSubstring};
492 /// #
493 /// # fn main() {
494 /// let span = LocatedSpan::new("メカジキ");
495 /// let indexOf3dKanji = span.find_substring("ジ").unwrap();
496 ///
497 /// assert_eq!(span.slice(indexOf3dKanji..).get_column(), 7);
498 /// assert_eq!(span.slice(indexOf3dKanji..).naive_get_utf8_column(), 3);
499 /// # }
500 /// ```
501 pub fn naive_get_utf8_column(&self) -> usize {
502 let before_self = self.get_columns_and_bytes_before().1;
503 naive_num_chars(before_self) + 1
504 }
505}
506
507impl<T: Hash, X> Hash for LocatedSpan<T, X> {
508 fn hash<H: Hasher>(&self, state: &mut H) {
509 self.offset.hash(state);
510 self.line.hash(state);
511 self.fragment.hash(state);
512 }
513}
514
515impl<T: AsBytes, X: Default> From<T> for LocatedSpan<T, X> {
516 fn from(i: T) -> Self {
517 Self::new_extra(i, X::default())
518 }
519}
520
521impl<T: AsBytes + PartialEq, X> PartialEq for LocatedSpan<T, X> {
522 fn eq(&self, other: &Self) -> bool {
523 self.line == other.line && self.offset == other.offset && self.fragment == other.fragment
524 }
525}
526
527impl<T: AsBytes + Eq, X> Eq for LocatedSpan<T, X> {}
528
529impl<T: AsBytes, X> AsBytes for LocatedSpan<T, X> {
530 fn as_bytes(&self) -> &[u8] {
531 self.fragment.as_bytes()
532 }
533}
534
535impl<T: InputLength, X> InputLength for LocatedSpan<T, X> {
536 fn input_len(&self) -> usize {
537 self.fragment.input_len()
538 }
539}
540
541impl<T, X> InputTake for LocatedSpan<T, X>
542where
543 Self: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
544{
545 fn take(&self, count: usize) -> Self {
546 self.slice(..count)
547 }
548
549 fn take_split(&self, count: usize) -> (Self, Self) {
550 (self.slice(count..), self.slice(..count))
551 }
552}
553
554impl<T, X> InputTakeAtPosition for LocatedSpan<T, X>
555where
556 T: InputTakeAtPosition + InputLength + InputIter,
557 Self: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Clone,
558{
559 type Item = <T as InputIter>::Item;
560
561 fn split_at_position_complete<P, E: ParseError<Self>>(
562 &self,
563 predicate: P,
564 ) -> IResult<Self, Self, E>
565 where
566 P: Fn(Self::Item) -> bool,
567 {
568 match self.split_at_position(predicate) {
569 Err(Err::Incomplete(_)) => Ok(self.take_split(self.input_len())),
570 res => res,
571 }
572 }
573
574 fn split_at_position<P, E: ParseError<Self>>(&self, predicate: P) -> IResult<Self, Self, E>
575 where
576 P: Fn(Self::Item) -> bool,
577 {
578 match self.fragment.position(predicate) {
579 Some(n) => Ok(self.take_split(n)),
580 None => Err(Err::Incomplete(nom::Needed::new(1))),
581 }
582 }
583
584 fn split_at_position1<P, E: ParseError<Self>>(
585 &self,
586 predicate: P,
587 e: ErrorKind,
588 ) -> IResult<Self, Self, E>
589 where
590 P: Fn(Self::Item) -> bool,
591 {
592 match self.fragment.position(predicate) {
593 Some(0) => Err(Err::Error(E::from_error_kind(self.clone(), e))),
594 Some(n) => Ok(self.take_split(n)),
595 None => Err(Err::Incomplete(nom::Needed::new(1))),
596 }
597 }
598
599 fn split_at_position1_complete<P, E: ParseError<Self>>(
600 &self,
601 predicate: P,
602 e: ErrorKind,
603 ) -> IResult<Self, Self, E>
604 where
605 P: Fn(Self::Item) -> bool,
606 {
607 match self.fragment.position(predicate) {
608 Some(0) => Err(Err::Error(E::from_error_kind(self.clone(), e))),
609 Some(n) => Ok(self.take_split(n)),
610 None => {
611 if self.fragment.input_len() == 0 {
612 Err(Err::Error(E::from_error_kind(self.clone(), e)))
613 } else {
614 Ok(self.take_split(self.input_len()))
615 }
616 }
617 }
618 }
619}
620
621#[macro_export]
622#[deprecated(
623 since = "3.1.0",
624 note = "this implementation has been generalized and no longer requires a macro"
625)]
626macro_rules! impl_input_iter {
627 () => {};
628}
629
630impl<'a, T, X> InputIter for LocatedSpan<T, X>
631where
632 T: InputIter,
633{
634 type Item = T::Item;
635 type Iter = T::Iter;
636 type IterElem = T::IterElem;
637 #[inline]
638 fn iter_indices(&self) -> Self::Iter {
639 self.fragment.iter_indices()
640 }
641 #[inline]
642 fn iter_elements(&self) -> Self::IterElem {
643 self.fragment.iter_elements()
644 }
645 #[inline]
646 fn position<P>(&self, predicate: P) -> Option<usize>
647 where
648 P: Fn(Self::Item) -> bool,
649 {
650 self.fragment.position(predicate)
651 }
652 #[inline]
653 fn slice_index(&self, count: usize) -> Result<usize, nom::Needed> {
654 self.fragment.slice_index(count)
655 }
656}
657
658impl<A: Compare<B>, B: Into<LocatedSpan<B>>, X> Compare<B> for LocatedSpan<A, X> {
659 #[inline(always)]
660 fn compare(&self, t: B) -> CompareResult {
661 self.fragment.compare(t.into().fragment)
662 }
663
664 #[inline(always)]
665 fn compare_no_case(&self, t: B) -> CompareResult {
666 self.fragment.compare_no_case(t.into().fragment)
667 }
668}
669
670#[macro_export]
671#[deprecated(
672 since = "2.1.0",
673 note = "this implementation has been generalized and no longer requires a macro"
674)]
675macro_rules! impl_compare {
676 ( $fragment_type:ty, $compare_to_type:ty ) => {};
677}
678
679#[macro_export]
680#[deprecated(
681 since = "3.1.0",
682 note = "this implementation has been generalized and no longer requires a macro"
683)]
684macro_rules! impl_slice_range {
685 ( $fragment_type:ty, $range_type:ty, $can_return_self:expr ) => {};
686}
687
688#[macro_export]
689#[deprecated(
690 since = "3.1.0",
691 note = "this implementation has been generalized and no longer requires a macro"
692)]
693macro_rules! impl_slice_ranges {
694 ( $fragment_type:ty ) => {};
695}
696
697impl<'a, T, R, X: Clone> Slice<R> for LocatedSpan<T, X>
698where
699 T: Slice<R> + Offset + AsBytes + Slice<RangeTo<usize>>,
700{
701 fn slice(&self, range: R) -> Self {
702 let next_fragment = self.fragment.slice(range);
703 let consumed_len = self.fragment.offset(&next_fragment);
704 if consumed_len == 0 {
705 return LocatedSpan {
706 line: self.line,
707 offset: self.offset,
708 fragment: next_fragment,
709 extra: self.extra.clone(),
710 };
711 }
712
713 let consumed = self.fragment.slice(..consumed_len);
714
715 let next_offset = self.offset + consumed_len;
716
717 let consumed_as_bytes = consumed.as_bytes();
718 let iter = Memchr::new(b'\n', consumed_as_bytes);
719 let number_of_lines = iter.count() as u32;
720 let next_line = self.line + number_of_lines;
721
722 LocatedSpan {
723 line: next_line,
724 offset: next_offset,
725 fragment: next_fragment,
726 extra: self.extra.clone(),
727 }
728 }
729}
730
731impl<Fragment: FindToken<Token>, Token, X> FindToken<Token> for LocatedSpan<Fragment, X> {
732 fn find_token(&self, token: Token) -> bool {
733 self.fragment.find_token(token)
734 }
735}
736
737impl<T, U, X> FindSubstring<U> for LocatedSpan<T, X>
738where
739 T: FindSubstring<U>,
740{
741 #[inline]
742 fn find_substring(&self, substr: U) -> Option<usize> {
743 self.fragment.find_substring(substr)
744 }
745}
746
747impl<R: FromStr, T, X> ParseTo<R> for LocatedSpan<T, X>
748where
749 T: ParseTo<R>,
750{
751 #[inline]
752 fn parse_to(&self) -> Option<R> {
753 self.fragment.parse_to()
754 }
755}
756
757impl<T, X> Offset for LocatedSpan<T, X> {
758 fn offset(&self, second: &Self) -> usize {
759 let fst = self.offset;
760 let snd = second.offset;
761
762 snd - fst
763 }
764}
765
766#[cfg(feature = "alloc")]
767impl<T: ToString, X> Display for LocatedSpan<T, X> {
768 fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
769 fmt.write_str(&self.fragment.to_string())
770 }
771}
772
773#[macro_export]
774#[deprecated(
775 since = "3.1.0",
776 note = "this implementation has been generalized and no longer requires a macro"
777)]
778macro_rules! impl_extend_into {
779 ($fragment_type:ty, $item:ty, $extender:ty) => {
780 impl<'a, X> ExtendInto for LocatedSpan<$fragment_type, X> {
781 type Item = $item;
782 type Extender = $extender;
783
784 #[inline]
785 fn new_builder(&self) -> Self::Extender {
786 self.fragment.new_builder()
787 }
788
789 #[inline]
790 fn extend_into(&self, acc: &mut Self::Extender) {
791 self.fragment.extend_into(acc)
792 }
793 }
794 };
795}
796
797#[cfg(feature = "alloc")]
798impl<'a, T, X> ExtendInto for LocatedSpan<T, X>
799where
800 T: ExtendInto,
801{
802 type Item = T::Item;
803 type Extender = T::Extender;
804
805 #[inline]
806 fn new_builder(&self) -> Self::Extender {
807 self.fragment.new_builder()
808 }
809
810 #[inline]
811 fn extend_into(&self, acc: &mut Self::Extender) {
812 self.fragment.extend_into(acc)
813 }
814}
815
816#[cfg(feature = "std")]
817#[macro_export]
818#[deprecated(
819 since = "2.1.0",
820 note = "this implementation has been generalized and no longer requires a macro"
821)]
822macro_rules! impl_hex_display {
823 ($fragment_type:ty) => {};
824}
825
826/// Capture the position of the current fragment
827#[macro_export]
828macro_rules! position {
829 ($input:expr,) => {
830 tag!($input, "")
831 };
832}
833
834/// Capture the position of the current fragment
835pub fn position<T, E>(s: T) -> IResult<T, T, E>
836where
837 E: ParseError<T>,
838 T: InputIter + InputTake,
839{
840 nom::bytes::complete::take(0usize)(s)
841}