#![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;
#[derive(Debug, Clone, Copy)]
pub struct LocatedSpan<T, X = ()> {
offset: usize,
line: u32,
fragment: T,
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")]
unsafe impl<T: StableDeref, X> StableDeref for LocatedSpan<T, X> {}
impl<T> LocatedSpan<T, ()> {
pub fn new(program: T) -> LocatedSpan<T, ()> {
LocatedSpan {
offset: 0,
line: 1,
fragment: program,
extra: (),
}
}
}
impl<T, X> LocatedSpan<T, X> {
pub fn new_extra(program: T, extra: X) -> LocatedSpan<T, X> {
LocatedSpan {
offset: 0,
line: 1,
fragment: program,
extra: extra,
}
}
pub unsafe fn new_from_raw_offset(
offset: usize,
line: u32,
fragment: T,
extra: X,
) -> LocatedSpan<T, X> {
LocatedSpan {
offset,
line,
fragment,
extra,
}
}
pub fn location_offset(&self) -> usize {
self.offset
}
pub fn location_line(&self) -> u32 {
self.line
}
pub fn fragment(&self) -> &T {
&self.fragment
}
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),
}
}
pub fn into_fragment(self) -> T {
self.fragment
}
pub fn into_fragment_and_extra(self) -> (T, X) {
(self.fragment, self.extra)
}
}
impl<T: AsBytes, X> LocatedSpan<T, X> {
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)..])
}
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],
}
}
pub fn get_column(&self) -> usize {
self.get_columns_and_bytes_before().0
}
pub fn get_utf8_column(&self) -> usize {
let before_self = self.get_columns_and_bytes_before().1;
num_chars(before_self) + 1
}
pub fn naive_get_utf8_column(&self) -> usize {
let before_self = self.get_columns_and_bytes_before().1;
naive_num_chars(before_self) + 1
}
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) => {};
}
#[macro_export]
macro_rules! position {
($input:expr,) => {
tag!($input, "")
};
}
pub fn position<T, E>(s: T) -> IResult<T, T, E>
where
E: ParseError<T>,
T: Input,
{
nom::bytes::complete::take(0usize)(s)
}