| //! nom_locate, a special input type to locate tokens |
| //! |
| //! The source code is available on [Github](https://github.com/fflorent/nom_locate) |
| //! |
| //! ## Features |
| //! |
| //! This crate exposes two cargo feature flags, `generic-simd` and `runtime-dispatch-simd`. |
| //! These correspond to the features exposed by [bytecount](https://github.com/llogiq/bytecount). |
| //! |
| //! ## How to use it |
| //! 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). |
| //! |
| //! ``` |
| //! use nom::bytes::complete::{tag, take_until}; |
| //! use nom::IResult; |
| //! use nom_locate::{position, LocatedSpan}; |
| //! |
| //! type Span<'a> = LocatedSpan<&'a str>; |
| //! |
| //! struct Token<'a> { |
| //! pub position: Span<'a>, |
| //! pub foo: &'a str, |
| //! pub bar: &'a str, |
| //! } |
| //! |
| //! fn parse_foobar(s: Span) -> IResult<Span, Token> { |
| //! let (s, _) = take_until("foo")(s)?; |
| //! let (s, pos) = position(s)?; |
| //! let (s, foo) = tag("foo")(s)?; |
| //! let (s, bar) = tag("bar")(s)?; |
| //! |
| //! Ok(( |
| //! s, |
| //! Token { |
| //! position: pos, |
| //! foo: foo.fragment(), |
| //! bar: bar.fragment(), |
| //! }, |
| //! )) |
| //! } |
| //! |
| //! fn main () { |
| //! let input = Span::new("Lorem ipsum \n foobar"); |
| //! let output = parse_foobar(input); |
| //! let position = output.unwrap().1.position; |
| //! assert_eq!(position.location_offset(), 14); |
| //! assert_eq!(position.location_line(), 2); |
| //! assert_eq!(position.fragment(), &""); |
| //! assert_eq!(position.get_column(), 2); |
| //! } |
| //! ``` |
| //! |
| //! ## Extra information |
| //! |
| //! You can also add arbitrary extra information using the extra property of `LocatedSpan`. |
| //! This property is not used when comparing two `LocatedSpan`s. |
| //! |
| //! ```ignore |
| //! use nom_locate::LocatedSpan; |
| //! type Span<'a> = LocatedSpan<&'a str, String>; |
| //! |
| //! let input = Span::new_extra("Lorem ipsum \n foobar", "filename"); |
| //! let output = parse_foobar(input); |
| //! let extra = output.unwrap().1.extra; |
| //! ``` |
| |
| #![cfg_attr(not(feature = "std"), no_std)] |
| |
| #[cfg(all(not(feature = "std"), feature = "alloc"))] |
| #[cfg_attr(test, macro_use)] |
| extern crate alloc; |
| |
| #[cfg(test)] |
| mod tests; |
| |
| mod lib { |
| #[cfg(feature = "std")] |
| pub mod std { |
| pub use std::fmt::{Display, Formatter, Result as FmtResult}; |
| pub use std::hash::{Hash, Hasher}; |
| pub use std::slice; |
| pub use std::str::FromStr; |
| pub use std::string::ToString; |
| } |
| |
| #[cfg(not(feature = "std"))] |
| pub mod std { |
| #[cfg(feature = "alloc")] |
| pub use alloc::fmt::{Display, Formatter, Result as FmtResult}; |
| #[cfg(feature = "alloc")] |
| pub use alloc::string::ToString; |
| pub use core::hash::{Hash, Hasher}; |
| pub use core::slice; |
| pub use core::str::FromStr; |
| } |
| } |
| |
| use lib::std::*; |
| |
| use bytecount::{naive_num_chars, num_chars}; |
| use memchr::Memchr; |
| #[cfg(feature = "alloc")] |
| use nom::ExtendInto; |
| use nom::{ |
| error::ParseError, AsBytes, Compare, CompareResult, FindSubstring, FindToken, IResult, Input, |
| Offset, ParseTo, |
| }; |
| #[cfg(feature = "stable-deref-trait")] |
| use stable_deref_trait::StableDeref; |
| |
| /// A LocatedSpan is a set of meta information about the location of a token, including extra |
| /// information. |
| /// |
| /// The `LocatedSpan` structure can be used as an input of the nom parsers. |
| /// It implements all the necessary traits for `LocatedSpan<&str,X>` and `LocatedSpan<&[u8],X>` |
| #[derive(Debug, Clone, Copy)] |
| pub struct LocatedSpan<T, X = ()> { |
| /// The offset represents the position of the fragment relatively to |
| /// the input of the parser. It starts at offset 0. |
| offset: usize, |
| |
| /// The line number of the fragment relatively to the input of the |
| /// parser. It starts at line 1. |
| line: u32, |
| |
| /// The fragment that is spanned. |
| /// The fragment represents a part of the input of the parser. |
| fragment: T, |
| |
| /// Extra information that can be embedded by the user. |
| /// Example: the parsed file name |
| pub extra: X, |
| } |
| |
| impl<T, X> core::ops::Deref for LocatedSpan<T, X> { |
| type Target = T; |
| fn deref(&self) -> &Self::Target { |
| &self.fragment |
| } |
| } |
| |
| impl<T, U, X> core::convert::AsRef<U> for LocatedSpan<&T, X> |
| where |
| T: ?Sized + core::convert::AsRef<U>, |
| U: ?Sized, |
| { |
| fn as_ref(&self) -> &U { |
| self.fragment.as_ref() |
| } |
| } |
| |
| #[cfg(feature = "stable-deref-trait")] |
| /// Optionally impl StableDeref so that this type works harmoniously with other |
| /// crates that rely on this marker trait, such as `rental` and `lazy_static`. |
| /// LocatedSpan is largely just a wrapper around the contained type `T`, so |
| /// this marker trait is safe to implement whenever T already implements |
| /// StableDeref. |
| unsafe impl<T: StableDeref, X> StableDeref for LocatedSpan<T, X> {} |
| |
| impl<T> LocatedSpan<T, ()> { |
| /// Create a span for a particular input with default `offset` and |
| /// `line` values and empty extra data. |
| /// You can compute the column through the `get_column` or `get_utf8_column` |
| /// methods. |
| /// |
| /// `offset` starts at 0, `line` starts at 1, and `column` starts at 1. |
| /// |
| /// Do not use this constructor in parser functions; `nom` and |
| /// `nom_locate` assume span offsets are relative to the beginning of the |
| /// same input. In these cases, you probably want to use the |
| /// `nom::traits::Slice` trait instead. |
| /// |
| /// # Example of use |
| /// |
| /// ``` |
| /// # extern crate nom_locate; |
| /// use nom_locate::LocatedSpan; |
| /// |
| /// # fn main() { |
| /// let span = LocatedSpan::new(b"foobar"); |
| /// |
| /// assert_eq!(span.location_offset(), 0); |
| /// assert_eq!(span.location_line(), 1); |
| /// assert_eq!(span.get_column(), 1); |
| /// assert_eq!(span.fragment(), &&b"foobar"[..]); |
| /// # } |
| /// ``` |
| pub fn new(program: T) -> LocatedSpan<T, ()> { |
| LocatedSpan { |
| offset: 0, |
| line: 1, |
| fragment: program, |
| extra: (), |
| } |
| } |
| } |
| |
| impl<T, X> LocatedSpan<T, X> { |
| /// Create a span for a particular input with default `offset` and |
| /// `line` values. You can compute the column through the `get_column` or `get_utf8_column` |
| /// methods. |
| /// |
| /// `offset` starts at 0, `line` starts at 1, and `column` starts at 1. |
| /// |
| /// Do not use this constructor in parser functions; `nom` and |
| /// `nom_locate` assume span offsets are relative to the beginning of the |
| /// same input. In these cases, you probably want to use the |
| /// `nom::traits::Slice` trait instead. |
| /// |
| /// # Example of use |
| /// |
| /// ``` |
| /// # extern crate nom_locate; |
| /// use nom_locate::LocatedSpan; |
| /// |
| /// # fn main() { |
| /// let span = LocatedSpan::new_extra(b"foobar", "extra"); |
| /// |
| /// assert_eq!(span.location_offset(), 0); |
| /// assert_eq!(span.location_line(), 1); |
| /// assert_eq!(span.get_column(), 1); |
| /// assert_eq!(span.fragment(), &&b"foobar"[..]); |
| /// assert_eq!(span.extra, "extra"); |
| /// # } |
| /// ``` |
| pub fn new_extra(program: T, extra: X) -> LocatedSpan<T, X> { |
| LocatedSpan { |
| offset: 0, |
| line: 1, |
| fragment: program, |
| extra: extra, |
| } |
| } |
| |
| /// Similar to `new_extra`, but allows overriding offset and line. |
| /// This is unsafe, because giving an offset too large may result in |
| /// undefined behavior, as some methods move back along the fragment |
| /// assuming any negative index within the offset is valid. |
| pub unsafe fn new_from_raw_offset( |
| offset: usize, |
| line: u32, |
| fragment: T, |
| extra: X, |
| ) -> LocatedSpan<T, X> { |
| LocatedSpan { |
| offset, |
| line, |
| fragment, |
| extra, |
| } |
| } |
| |
| /// The offset represents the position of the fragment relatively to |
| /// the input of the parser. It starts at offset 0. |
| pub fn location_offset(&self) -> usize { |
| self.offset |
| } |
| |
| /// The line number of the fragment relatively to the input of the |
| /// parser. It starts at line 1. |
| pub fn location_line(&self) -> u32 { |
| self.line |
| } |
| |
| /// The fragment that is spanned. |
| /// The fragment represents a part of the input of the parser. |
| pub fn fragment(&self) -> &T { |
| &self.fragment |
| } |
| |
| /// Transform the extra inside into another type |
| /// |
| /// # Example of use |
| /// ``` |
| /// # extern crate nom_locate; |
| /// # extern crate nom; |
| /// # use nom_locate::LocatedSpan; |
| /// use nom::{ |
| /// IResult, AsChar, Parser, |
| /// combinator::{recognize, map_res}, |
| /// sequence::terminated, |
| /// character::complete::{char, one_of}, |
| /// bytes::complete::{tag, take_while1}, |
| /// }; |
| /// |
| /// fn decimal(input: LocatedSpan<&str>) -> IResult<LocatedSpan<&str>, LocatedSpan<&str>> { |
| /// recognize( |
| /// take_while1(|c: char| c.is_dec_digit() || c == '_') |
| /// ).parse(input) |
| /// } |
| /// |
| /// fn main() { |
| /// use nom::Parser; |
| /// let span = LocatedSpan::new("$10"); |
| /// // matches the $ and then matches the decimal number afterwards, |
| /// // converting it into a `u8` and putting that value in the span |
| /// let (_, (_, n)) = ( |
| /// tag("$"), |
| /// map_res( |
| /// decimal, |
| /// |x| x.fragment().parse::<u8>().map(|n| x.map_extra(|_| n)) |
| /// ) |
| /// ).parse(span).unwrap(); |
| /// assert_eq!(n.extra, 10); |
| /// } |
| /// ``` |
| pub fn map_extra<U, F: FnOnce(X) -> U>(self, f: F) -> LocatedSpan<T, U> { |
| LocatedSpan { |
| offset: self.offset, |
| line: self.line, |
| fragment: self.fragment, |
| extra: f(self.extra), |
| } |
| } |
| |
| /// Takes ownership of the fragment without (re)borrowing it. |
| /// |
| /// # Example of use |
| /// ``` |
| /// # extern crate nom_locate; |
| /// # extern crate nom; |
| /// # use nom_locate::LocatedSpan; |
| /// use nom::{ |
| /// IResult, |
| /// bytes::complete::{take_till, tag}, |
| /// combinator::rest, |
| /// }; |
| /// |
| /// fn parse_pair<'a>(input: LocatedSpan<&'a str>) -> IResult<LocatedSpan<&'a str>, (&'a str, &'a str)> { |
| /// let (input, key) = take_till(|c| c == '=')(input)?; |
| /// let (input, _) = tag("=")(input)?; |
| /// let (input, value) = rest(input)?; |
| /// |
| /// Ok((input, (key.into_fragment(), value.into_fragment()))) |
| /// } |
| /// |
| /// fn main() { |
| /// let span = LocatedSpan::new("key=value"); |
| /// let (_, pair) = parse_pair(span).unwrap(); |
| /// assert_eq!(pair, ("key", "value")); |
| /// } |
| /// ``` |
| pub fn into_fragment(self) -> T { |
| self.fragment |
| } |
| |
| /// Takes ownership of the fragment and extra data without (re)borrowing them. |
| pub fn into_fragment_and_extra(self) -> (T, X) { |
| (self.fragment, self.extra) |
| } |
| } |
| |
| impl<T: AsBytes, X> LocatedSpan<T, X> { |
| // Attempt to get the "original" data slice back, by extending |
| // self.fragment backwards by self.offset. |
| // Note that any bytes truncated from after self.fragment will not |
| // be recovered. |
| fn get_unoffsetted_slice(&self) -> &[u8] { |
| let self_bytes = self.fragment.as_bytes(); |
| let self_ptr = self_bytes.as_ptr(); |
| unsafe { |
| assert!( |
| self.offset <= isize::max_value() as usize, |
| "offset is too big" |
| ); |
| let orig_input_ptr = self_ptr.offset(-(self.offset as isize)); |
| slice::from_raw_parts(orig_input_ptr, self.offset + self_bytes.len()) |
| } |
| } |
| |
| fn get_columns_and_bytes_before(&self) -> (usize, &[u8]) { |
| let before_self = &self.get_unoffsetted_slice()[..self.offset]; |
| |
| let column = match memchr::memrchr(b'\n', before_self) { |
| None => self.offset + 1, |
| Some(pos) => self.offset - pos, |
| }; |
| |
| (column, &before_self[self.offset - (column - 1)..]) |
| } |
| |
| /// Return the line that contains this LocatedSpan. |
| /// |
| /// The `get_column` and `get_utf8_column` functions returns |
| /// indexes that corresponds to the line returned by this function. |
| /// |
| /// Note that if this LocatedSpan ends before the end of the |
| /// original data, the result of calling `get_line_beginning()` |
| /// will not include any data from after the LocatedSpan. |
| /// |
| /// ``` |
| /// # extern crate nom_locate; |
| /// # extern crate nom; |
| /// # use nom_locate::LocatedSpan; |
| /// # use nom::{Input, FindSubstring}; |
| /// # |
| /// # fn main() { |
| /// let program = LocatedSpan::new( |
| /// "Hello World!\ |
| /// \nThis is a multi-line input\ |
| /// \nthat ends after this line.\n"); |
| /// let multi = program.find_substring("multi").unwrap(); |
| /// |
| /// assert_eq!( |
| /// program.take_from(multi).get_line_beginning(), |
| /// "This is a multi-line input".as_bytes(), |
| /// ); |
| /// # } |
| /// ``` |
| pub fn get_line_beginning(&self) -> &[u8] { |
| let column0 = self.get_column() - 1; |
| let the_line = &self.get_unoffsetted_slice()[self.offset - column0..]; |
| match memchr::memchr(b'\n', &the_line[column0..]) { |
| None => the_line, |
| Some(pos) => &the_line[..column0 + pos], |
| } |
| } |
| |
| /// Return the column index, assuming 1 byte = 1 column. |
| /// |
| /// Use it for ascii text, or use get_utf8_column for UTF8. |
| /// |
| /// # Example of use |
| /// ``` |
| /// |
| /// # extern crate nom_locate; |
| /// # extern crate nom; |
| /// # use nom_locate::LocatedSpan; |
| /// # use nom::Input; |
| /// # |
| /// # fn main() { |
| /// use nom::Input; |
| /// let span = LocatedSpan::new("foobar"); |
| /// |
| /// assert_eq!(span.take_from(3).get_column(), 4); |
| /// # } |
| /// ``` |
| pub fn get_column(&self) -> usize { |
| self.get_columns_and_bytes_before().0 |
| } |
| |
| /// Return the column index for UTF8 text. Return value is unspecified for non-utf8 text. |
| /// |
| /// This version uses bytecount's hyper algorithm to count characters. This is much faster |
| /// for long lines, but is non-negligibly slower for short slices (below around 100 bytes). |
| /// This is also sped up significantly more depending on architecture and enabling the simd |
| /// feature gates. If you expect primarily short lines, you may get a noticeable speedup in |
| /// parsing by using `naive_get_utf8_column` instead. Benchmark your specific use case! |
| /// |
| /// # Example of use |
| /// ``` |
| /// |
| /// # extern crate nom_locate; |
| /// # extern crate nom; |
| /// # use nom_locate::LocatedSpan; |
| /// # use nom::{Input, FindSubstring}; |
| /// # |
| /// # fn main() { |
| /// use nom::Input; |
| /// let span = LocatedSpan::new("メカジã‚"); |
| /// let indexOf3dKanji = span.find_substring("ジ").unwrap(); |
| /// |
| /// assert_eq!(span.take_from(indexOf3dKanji).get_column(), 7); |
| /// assert_eq!(span.take_from(indexOf3dKanji).get_utf8_column(), 3); |
| /// # } |
| /// ``` |
| pub fn get_utf8_column(&self) -> usize { |
| let before_self = self.get_columns_and_bytes_before().1; |
| num_chars(before_self) + 1 |
| } |
| |
| /// Return the column index for UTF8 text. Return value is unspecified for non-utf8 text. |
| /// |
| /// A simpler implementation of `get_utf8_column` that may be faster on shorter lines. |
| /// If benchmarking shows that this is faster, you can use it instead of `get_utf8_column`. |
| /// Prefer defaulting to `get_utf8_column` unless this legitimately is a performance bottleneck. |
| /// |
| /// # Example of use |
| /// ``` |
| /// |
| /// # extern crate nom_locate; |
| /// # extern crate nom; |
| /// # use nom_locate::LocatedSpan; |
| /// # use nom::{Input, FindSubstring}; |
| /// # |
| /// # fn main() { |
| /// let span = LocatedSpan::new("メカジã‚"); |
| /// let indexOf3dKanji = span.find_substring("ジ").unwrap(); |
| /// |
| /// assert_eq!(span.take_from(indexOf3dKanji).get_column(), 7); |
| /// assert_eq!(span.take_from(indexOf3dKanji).naive_get_utf8_column(), 3); |
| /// # } |
| /// ``` |
| pub fn naive_get_utf8_column(&self) -> usize { |
| let before_self = self.get_columns_and_bytes_before().1; |
| naive_num_chars(before_self) + 1 |
| } |
| |
| // Helper for `Input::take()` and `Input::take_from()` implementations. |
| fn slice_by(&self, next_fragment: T) -> Self |
| where |
| T: AsBytes + Input + Offset, |
| X: Clone, |
| { |
| let consumed_len = self.fragment.offset(&next_fragment); |
| if consumed_len == 0 { |
| return Self { |
| line: self.line, |
| offset: self.offset, |
| fragment: next_fragment, |
| extra: self.extra.clone(), |
| }; |
| } |
| |
| let consumed = self.fragment.take(consumed_len); |
| |
| let next_offset = self.offset + consumed_len; |
| |
| let consumed_as_bytes = consumed.as_bytes(); |
| let iter = Memchr::new(b'\n', consumed_as_bytes); |
| let number_of_lines = iter.count() as u32; |
| let next_line = self.line + number_of_lines; |
| |
| Self { |
| line: next_line, |
| offset: next_offset, |
| fragment: next_fragment, |
| extra: self.extra.clone(), |
| } |
| } |
| } |
| |
| impl<T: Hash, X> Hash for LocatedSpan<T, X> { |
| fn hash<H: Hasher>(&self, state: &mut H) { |
| self.offset.hash(state); |
| self.line.hash(state); |
| self.fragment.hash(state); |
| } |
| } |
| |
| impl<T: AsBytes, X: Default> From<T> for LocatedSpan<T, X> { |
| fn from(i: T) -> Self { |
| Self::new_extra(i, X::default()) |
| } |
| } |
| |
| impl<T: AsBytes + PartialEq, X> PartialEq for LocatedSpan<T, X> { |
| fn eq(&self, other: &Self) -> bool { |
| self.line == other.line && self.offset == other.offset && self.fragment == other.fragment |
| } |
| } |
| |
| impl<T: AsBytes + Eq, X> Eq for LocatedSpan<T, X> {} |
| |
| impl<T: AsBytes, X> AsBytes for LocatedSpan<T, X> { |
| fn as_bytes(&self) -> &[u8] { |
| self.fragment.as_bytes() |
| } |
| } |
| |
| impl<T, X> Input for LocatedSpan<T, X> |
| where |
| T: AsBytes + Input + Offset, |
| X: Clone, |
| { |
| type Item = <T as Input>::Item; |
| type Iter = <T as Input>::Iter; |
| type IterIndices = <T as Input>::IterIndices; |
| |
| #[inline] |
| fn input_len(&self) -> usize { |
| self.fragment.input_len() |
| } |
| |
| #[inline] |
| fn take(&self, index: usize) -> Self { |
| self.slice_by(self.fragment.take(index)) |
| } |
| |
| #[inline] |
| fn take_from(&self, index: usize) -> Self { |
| self.slice_by(self.fragment.take_from(index)) |
| } |
| |
| #[inline] |
| fn take_split(&self, index: usize) -> (Self, Self) { |
| (self.take_from(index), self.take(index)) |
| } |
| |
| #[inline] |
| fn position<P>(&self, predicate: P) -> Option<usize> |
| where |
| P: Fn(Self::Item) -> bool, |
| { |
| self.fragment.position(predicate) |
| } |
| |
| #[inline] |
| fn iter_elements(&self) -> Self::Iter { |
| self.fragment.iter_elements() |
| } |
| |
| #[inline] |
| fn iter_indices(&self) -> Self::IterIndices { |
| self.fragment.iter_indices() |
| } |
| |
| #[inline] |
| fn slice_index(&self, count: usize) -> Result<usize, nom::Needed> { |
| self.fragment.slice_index(count) |
| } |
| } |
| |
| #[macro_export] |
| #[deprecated( |
| since = "3.1.0", |
| note = "this implementation has been generalized and no longer requires a macro" |
| )] |
| macro_rules! impl_input_iter { |
| () => {}; |
| } |
| |
| impl<A: Compare<B>, B: Into<LocatedSpan<B>>, X> Compare<B> for LocatedSpan<A, X> { |
| #[inline(always)] |
| fn compare(&self, t: B) -> CompareResult { |
| self.fragment.compare(t.into().fragment) |
| } |
| |
| #[inline(always)] |
| fn compare_no_case(&self, t: B) -> CompareResult { |
| self.fragment.compare_no_case(t.into().fragment) |
| } |
| } |
| |
| #[macro_export] |
| #[deprecated( |
| since = "2.1.0", |
| note = "this implementation has been generalized and no longer requires a macro" |
| )] |
| macro_rules! impl_compare { |
| ( $fragment_type:ty, $compare_to_type:ty ) => {}; |
| } |
| |
| #[macro_export] |
| #[deprecated( |
| since = "3.1.0", |
| note = "this implementation has been generalized and no longer requires a macro" |
| )] |
| macro_rules! impl_slice_range { |
| ( $fragment_type:ty, $range_type:ty, $can_return_self:expr ) => {}; |
| } |
| |
| #[macro_export] |
| #[deprecated( |
| since = "3.1.0", |
| note = "this implementation has been generalized and no longer requires a macro" |
| )] |
| macro_rules! impl_slice_ranges { |
| ( $fragment_type:ty ) => {}; |
| } |
| |
| impl<Fragment: FindToken<Token>, Token, X> FindToken<Token> for LocatedSpan<Fragment, X> { |
| fn find_token(&self, token: Token) -> bool { |
| self.fragment.find_token(token) |
| } |
| } |
| |
| impl<T, U, X> FindSubstring<U> for LocatedSpan<T, X> |
| where |
| T: FindSubstring<U>, |
| { |
| #[inline] |
| fn find_substring(&self, substr: U) -> Option<usize> { |
| self.fragment.find_substring(substr) |
| } |
| } |
| |
| impl<R: FromStr, T, X> ParseTo<R> for LocatedSpan<T, X> |
| where |
| T: ParseTo<R>, |
| { |
| #[inline] |
| fn parse_to(&self) -> Option<R> { |
| self.fragment.parse_to() |
| } |
| } |
| |
| impl<T, X> Offset for LocatedSpan<T, X> { |
| fn offset(&self, second: &Self) -> usize { |
| let fst = self.offset; |
| let snd = second.offset; |
| |
| snd - fst |
| } |
| } |
| |
| #[cfg(feature = "alloc")] |
| impl<T: ToString, X> Display for LocatedSpan<T, X> { |
| fn fmt(&self, fmt: &mut Formatter) -> FmtResult { |
| fmt.write_str(&self.fragment.to_string()) |
| } |
| } |
| |
| #[macro_export] |
| #[deprecated( |
| since = "3.1.0", |
| note = "this implementation has been generalized and no longer requires a macro" |
| )] |
| macro_rules! impl_extend_into { |
| ($fragment_type:ty, $item:ty, $extender:ty) => { |
| impl<'a, X> ExtendInto for LocatedSpan<$fragment_type, X> { |
| type Item = $item; |
| type Extender = $extender; |
| |
| #[inline] |
| fn new_builder(&self) -> Self::Extender { |
| self.fragment.new_builder() |
| } |
| |
| #[inline] |
| fn extend_into(&self, acc: &mut Self::Extender) { |
| self.fragment.extend_into(acc) |
| } |
| } |
| }; |
| } |
| |
| #[cfg(feature = "alloc")] |
| impl<'a, T, X> ExtendInto for LocatedSpan<T, X> |
| where |
| T: ExtendInto, |
| { |
| type Item = T::Item; |
| type Extender = T::Extender; |
| |
| #[inline] |
| fn new_builder(&self) -> Self::Extender { |
| self.fragment.new_builder() |
| } |
| |
| #[inline] |
| fn extend_into(&self, acc: &mut Self::Extender) { |
| self.fragment.extend_into(acc) |
| } |
| } |
| |
| #[cfg(feature = "std")] |
| #[macro_export] |
| #[deprecated( |
| since = "2.1.0", |
| note = "this implementation has been generalized and no longer requires a macro" |
| )] |
| macro_rules! impl_hex_display { |
| ($fragment_type:ty) => {}; |
| } |
| |
| /// Capture the position of the current fragment |
| #[macro_export] |
| macro_rules! position { |
| ($input:expr,) => { |
| tag!($input, "") |
| }; |
| } |
| |
| /// Capture the position of the current fragment |
| pub fn position<T, E>(s: T) -> IResult<T, T, E> |
| where |
| E: ParseError<T>, |
| T: Input, |
| { |
| nom::bytes::complete::take(0usize)(s) |
| } |