use memchr::{memchr2_iter, memchr_iter, memrchr};
use nom::{
error::{ErrorKind, ParseError},
AsBytes, Compare, CompareResult, Err, ExtendInto, FindSubstring, FindToken,
IResult, InputIter, InputLength, InputTake, InputTakeAtPosition, Offset,
ParseTo, Slice,
};
use std::{
borrow::Cow,
convert::TryFrom,
fmt::{Display, Formatter, Result as FmtResult},
iter::Enumerate,
ops::{Range, RangeFrom, RangeFull, RangeTo},
path::Path,
str::FromStr,
};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Span<'a> {
inner: &'a [u8],
start: usize,
end: usize,
depth: u16,
}
impl<'a> Span<'a> {
pub fn new(inner: &'a [u8], start: usize, end: usize, depth: u16) -> Self {
Self {
inner,
start,
end,
depth,
}
}
pub fn starting_at(&self, start: usize) -> Self {
let start = self.start + start;
let end = self.end;
Self::new(
self.inner,
if start > end { end } else { start },
end,
self.depth,
)
}
pub fn ending_at(&self, end: usize) -> Self {
Self::new(self.inner, self.start, self.start + end, self.depth)
}
pub fn at_end(&self) -> Self {
self.starting_at(if self.end > 0 { self.end - 1 } else { 0 })
}
pub fn with_length(&self, len: usize) -> Self {
if len < self.remaining_len() {
Self::new(self.inner, self.start, self.start + len, self.depth)
} else {
*self
}
}
pub fn depth(&self) -> u16 {
self.depth
}
pub fn with_depth(&self, depth: u16) -> Self {
Self::new(self.inner, self.start, self.end, depth)
}
pub fn with_deeper_depth(&self) -> Self {
self.with_depth(self.depth() + 1)
}
pub fn with_shallower_depth(&self) -> Self {
let depth = if self.depth() > 0 {
self.depth() - 1
} else {
0
};
self.with_depth(depth)
}
pub fn trim_start(&self) -> Self {
let mut start = self.start;
let end = self.end;
while start < end && self.inner[start].is_ascii_whitespace() {
start += 1;
}
self.starting_at(start - self.start)
}
pub fn as_inner(&self) -> &[u8] {
self.inner
}
pub fn as_unsafe_inner_str(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(self.as_inner()) }
}
pub fn start_offset(&self) -> usize {
self.start
}
pub fn end_offset(&self) -> usize {
self.end
}
pub fn as_consumed(&self) -> &[u8] {
&self.inner[..self.start]
}
pub fn as_unsafe_consumed_str(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(self.as_consumed()) }
}
pub fn consumed_len(&self) -> usize {
self.start
}
pub fn as_remaining(&self) -> &[u8] {
&self.inner[self.start..self.end]
}
pub fn as_unsafe_remaining_str(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(self.as_remaining()) }
}
pub fn map_remaining_into<F: FnOnce(&'a [u8]) -> R, R>(self, f: F) -> R {
f(&self.inner[self.start..self.end])
}
pub fn map_remaining_unsafe_str_into<F: FnOnce(&'a str) -> R, R>(
self,
f: F,
) -> R {
f(unsafe {
std::str::from_utf8_unchecked(&self.inner[self.start..self.end])
})
}
pub fn remaining_len(&self) -> usize {
if self.start <= self.end {
self.end - self.start
} else {
0
}
}
pub fn is_empty(&self) -> bool {
self.remaining_len() == 0
}
pub fn is_only_whitespace(&self) -> bool {
let len = self.remaining_len();
if len == 0 {
return true;
}
let mut last_pos = 0;
for pos in memchr2_iter(b' ', b'\t', self.as_remaining()) {
if pos - last_pos > 1 {
return false;
}
last_pos = pos;
}
last_pos == (len - 1)
}
pub fn line_and_column(&self) -> (usize, usize) {
(self.line(), self.column())
}
pub fn end_line_and_column(&self) -> (usize, usize) {
(self.end_line(), self.end_column())
}
pub fn line(&self) -> usize {
memchr_iter(b'\n', self.inner)
.take_while(|pos| pos < &self.start)
.count()
+ 1
}
pub fn end_line(&self) -> usize {
self.at_end().line()
}
pub fn column(&self) -> usize {
let start_of_line = memrchr(b'\n', self.as_consumed())
.map(|pos| pos + 1)
.unwrap_or_default();
let line_up_to_offset = &self.inner[start_of_line..self.start];
bytecount::num_chars(line_up_to_offset) + 1
}
pub fn end_column(&self) -> usize {
self.at_end().column()
}
}
impl<'a> Display for Span<'a> {
fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
if let Ok(s) = std::str::from_utf8(self.as_remaining()) {
fmt.write_str(s)?;
}
Ok(())
}
}
impl Default for Span<'_> {
fn default() -> Self {
Self::from(b"")
}
}
impl<'a> PartialEq<&'a str> for Span<'a> {
fn eq(&self, other: &&'a str) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl<'a> PartialEq<&'a [u8]> for Span<'a> {
fn eq(&self, other: &&'a [u8]) -> bool {
self.as_bytes() == *other
}
}
pub struct SpanIterator<'a> {
span: Span<'a>,
}
impl<'a> IntoIterator for Span<'a> {
type Item = &'a u8;
type IntoIter = SpanIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
SpanIterator { span: self }
}
}
impl<'a> Iterator for SpanIterator<'a> {
type Item = &'a u8;
fn next(&mut self) -> Option<Self::Item> {
let span = &mut self.span;
if span.start < span.end && span.start < span.inner.len() {
let item = &span.inner[span.start];
span.start += 1;
Some(item)
} else {
None
}
}
}
impl<'a> DoubleEndedIterator for SpanIterator<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
let span = &mut self.span;
if span.start < span.end && span.end < span.inner.len() {
let item = &span.inner[span.end];
span.end -= 1;
Some(item)
} else {
None
}
}
}
impl<'a> From<Span<'a>> for Cow<'a, [u8]> {
fn from(span: Span<'a>) -> Cow<'a, [u8]> {
Cow::from(&span.inner[span.start..span.end])
}
}
impl<'a> From<Span<'a>> for Cow<'a, str> {
fn from(span: Span<'a>) -> Cow<'a, str> {
span.map_remaining_unsafe_str_into(Cow::from)
}
}
impl<'a> From<Span<'a>> for Cow<'a, Path> {
fn from(span: Span<'a>) -> Cow<'a, Path> {
Cow::from(span.map_remaining_unsafe_str_into(Path::new))
}
}
impl<'a> TryFrom<Span<'a>> for uriparse::URIReference<'a> {
type Error = uriparse::URIReferenceError;
fn try_from(span: Span<'a>) -> Result<Self, Self::Error> {
span.map_remaining_into(uriparse::URIReference::try_from)
}
}
impl<'a> TryFrom<Span<'a>> for uriparse::URI<'a> {
type Error = uriparse::URIError;
fn try_from(span: Span<'a>) -> Result<Self, Self::Error> {
span.map_remaining_into(uriparse::URI::try_from)
}
}
impl<'a> From<&'a [u8]> for Span<'a> {
fn from(inner: &'a [u8]) -> Self {
Self::new(inner, 0, inner.len(), 0)
}
}
impl<'a> From<&'a str> for Span<'a> {
fn from(inner: &'a str) -> Self {
Self::from(inner.as_bytes())
}
}
macro_rules! impl_from_fixed_size_byte_array {
($len:expr) => {
impl<'a> From<&'a [u8; $len]> for Span<'a> {
fn from(inner: &'a [u8; $len]) -> Self {
let inner_slice: &[u8] = inner;
Self::from(inner_slice)
}
}
};
}
impl_from_fixed_size_byte_array!(0);
impl_from_fixed_size_byte_array!(1);
impl_from_fixed_size_byte_array!(2);
impl_from_fixed_size_byte_array!(3);
impl_from_fixed_size_byte_array!(4);
impl_from_fixed_size_byte_array!(5);
impl_from_fixed_size_byte_array!(6);
impl_from_fixed_size_byte_array!(7);
impl_from_fixed_size_byte_array!(8);
impl_from_fixed_size_byte_array!(9);
impl_from_fixed_size_byte_array!(10);
impl_from_fixed_size_byte_array!(11);
impl_from_fixed_size_byte_array!(12);
impl_from_fixed_size_byte_array!(13);
impl_from_fixed_size_byte_array!(14);
impl_from_fixed_size_byte_array!(15);
impl_from_fixed_size_byte_array!(16);
impl_from_fixed_size_byte_array!(17);
impl_from_fixed_size_byte_array!(18);
impl_from_fixed_size_byte_array!(19);
impl_from_fixed_size_byte_array!(20);
impl_from_fixed_size_byte_array!(21);
impl_from_fixed_size_byte_array!(22);
impl_from_fixed_size_byte_array!(23);
impl_from_fixed_size_byte_array!(24);
impl_from_fixed_size_byte_array!(25);
impl_from_fixed_size_byte_array!(26);
impl<'a> AsBytes for Span<'a> {
fn as_bytes(&self) -> &[u8] {
self.as_remaining()
}
}
impl<'a, 'b> Compare<Span<'b>> for Span<'a> {
fn compare(&self, other: Span<'b>) -> CompareResult {
self.as_bytes().compare(other.as_bytes())
}
fn compare_no_case(&self, other: Span<'b>) -> CompareResult {
self.as_bytes().compare_no_case(other.as_bytes())
}
}
impl<'a, 'b> Compare<&'b str> for Span<'a> {
fn compare(&self, other: &'b str) -> CompareResult {
self.as_bytes().compare(other.as_bytes())
}
fn compare_no_case(&self, other: &'b str) -> CompareResult {
self.as_bytes().compare_no_case(other.as_bytes())
}
}
impl<'a, 'b> Compare<&'b [u8]> for Span<'a> {
fn compare(&self, other: &'b [u8]) -> CompareResult {
self.as_bytes().compare(other)
}
fn compare_no_case(&self, other: &'b [u8]) -> CompareResult {
self.as_bytes().compare_no_case(other)
}
}
impl<'a> ExtendInto for Span<'a> {
type Item = u8;
type Extender = Vec<u8>;
#[inline]
fn new_builder(&self) -> Self::Extender {
self.as_bytes().new_builder()
}
#[inline]
fn extend_into(&self, acc: &mut Self::Extender) {
self.as_bytes().extend_into(acc)
}
}
impl<'a, 'b> FindSubstring<&'b [u8]> for Span<'a> {
#[inline]
fn find_substring(&self, substr: &'b [u8]) -> Option<usize> {
self.as_bytes().find_substring(substr)
}
}
impl<'a, 'b> FindSubstring<&'b str> for Span<'a> {
#[inline]
fn find_substring(&self, substr: &'b str) -> Option<usize> {
self.as_bytes().find_substring(substr)
}
}
impl<'a> FindToken<u8> for Span<'a> {
fn find_token(&self, token: u8) -> bool {
self.as_bytes().find_token(token)
}
}
impl<'a, 'b> FindToken<&'b u8> for Span<'a> {
fn find_token(&self, token: &'b u8) -> bool {
self.as_bytes().find_token(token)
}
}
impl<'a> FindToken<char> for Span<'a> {
fn find_token(&self, token: char) -> bool {
self.as_bytes().find_token(token)
}
}
impl<'a> InputIter for Span<'a> {
type Item = u8;
type Iter = Enumerate<Self::IterElem>;
type IterElem = std::iter::Copied<SpanIterator<'a>>;
#[inline]
fn iter_indices(&self) -> Self::Iter {
self.iter_elements().enumerate()
}
#[inline]
fn iter_elements(&self) -> Self::IterElem {
self.clone().into_iter().copied()
}
#[inline]
fn position<P>(&self, predicate: P) -> Option<usize>
where
P: Fn(Self::Item) -> bool,
{
self.as_bytes().position(predicate)
}
#[inline]
fn slice_index(&self, count: usize) -> Result<usize, nom::Needed> {
self.as_bytes().slice_index(count)
}
}
impl<'a> InputLength for Span<'a> {
fn input_len(&self) -> usize {
self.as_bytes().input_len()
}
}
impl<'a> InputTake for Span<'a>
where
Self: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
{
fn take(&self, count: usize) -> Self {
self.slice(..count)
}
fn take_split(&self, count: usize) -> (Self, Self) {
(self.slice(count..), self.slice(..count))
}
}
impl<'a> InputTakeAtPosition for Span<'a>
where
Self: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Clone,
{
type Item = <Self as InputIter>::Item;
fn split_at_position_complete<P, E: ParseError<Self>>(
&self,
predicate: P,
) -> IResult<Self, Self, E>
where
P: Fn(Self::Item) -> bool,
{
match self.split_at_position(predicate) {
Err(Err::Incomplete(_)) => Ok(self.take_split(self.input_len())),
res => res,
}
}
fn split_at_position<P, E: ParseError<Self>>(
&self,
predicate: P,
) -> IResult<Self, Self, E>
where
P: Fn(Self::Item) -> bool,
{
match self.as_bytes().position(predicate) {
Some(n) => Ok(self.take_split(n)),
None => Err(Err::Incomplete(nom::Needed::new(1))),
}
}
fn split_at_position1<P, E: ParseError<Self>>(
&self,
predicate: P,
e: ErrorKind,
) -> IResult<Self, Self, E>
where
P: Fn(Self::Item) -> bool,
{
match self.as_bytes().position(predicate) {
Some(0) => Err(Err::Error(E::from_error_kind(*self, e))),
Some(n) => Ok(self.take_split(n)),
None => Err(Err::Incomplete(nom::Needed::new(1))),
}
}
fn split_at_position1_complete<P, E: ParseError<Self>>(
&self,
predicate: P,
e: ErrorKind,
) -> IResult<Self, Self, E>
where
P: Fn(Self::Item) -> bool,
{
match self.as_bytes().position(predicate) {
Some(0) => Err(Err::Error(E::from_error_kind(*self, e))),
Some(n) => Ok(self.take_split(n)),
None => {
if self.as_bytes().input_len() == 0 {
Err(Err::Error(E::from_error_kind(*self, e)))
} else {
Ok(self.take_split(self.input_len()))
}
}
}
}
}
impl<'a, R> ParseTo<R> for Span<'a>
where
R: FromStr,
{
#[inline]
fn parse_to(&self) -> Option<R> {
self.as_bytes().parse_to()
}
}
impl<'a> Offset for Span<'a> {
fn offset(&self, second: &Self) -> usize {
let fst = self.start;
let snd = second.start;
snd - fst
}
}
impl<'a> Slice<Range<usize>> for Span<'a> {
fn slice(&self, range: Range<usize>) -> Self {
self.ending_at(range.end).starting_at(range.start)
}
}
impl<'a> Slice<RangeTo<usize>> for Span<'a> {
fn slice(&self, range: RangeTo<usize>) -> Self {
self.ending_at(range.end)
}
}
impl<'a> Slice<RangeFrom<usize>> for Span<'a> {
fn slice(&self, range: RangeFrom<usize>) -> Self {
self.starting_at(range.start)
}
}
impl<'a> Slice<RangeFull> for Span<'a> {
fn slice(&self, _range: RangeFull) -> Self {
*self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn trim_start_should_return_exact_copy_if_no_leading_whitespace() {
let span = Span::from("some text");
assert_eq!(span.trim_start(), span);
}
#[test]
fn trim_start_should_return_exact_copy_if_empty_span() {
let span = Span::from("");
assert_eq!(span.trim_start(), span);
}
#[test]
fn trim_start_should_return_empty_span_if_all_whitespace() {
let span = Span::from(" \t\n\r");
assert_eq!(span.trim_start(), "");
}
#[test]
fn trim_start_should_return_span_with_leading_whitespace_trimmed() {
let span = Span::from(" \t\n\rsome text");
assert_eq!(span.trim_start(), "some text");
}
mod nom_traits {
use super::*;
#[test]
fn as_bytes_should_return_remaining_bytes_as_slice() {
let span = Span::from(b"all bytes").starting_at(4);
assert_eq!(span.as_bytes(), b"bytes");
}
#[test]
fn compare_should_yield_ok_if_remaining_bytes_are_equal() {
let span1 = Span::from(b"abcdef").starting_at(4);
let span2 = Span::from(b"abcdef").starting_at(4);
assert_eq!(span1.compare(span2), CompareResult::Ok);
assert_eq!(span1.compare("ef"), CompareResult::Ok);
assert_eq!(span1.compare(&b"ef"[..]), CompareResult::Ok);
}
#[test]
fn compare_should_yield_error_if_remaining_bytes_are_not_equal() {
let span1 = Span::from(b"abcdef").starting_at(4);
let span2 = Span::from(b"defabc").starting_at(4);
assert_eq!(span1.compare(span2), CompareResult::Error);
assert_eq!(span1.compare("defabc"), CompareResult::Error);
assert_eq!(span1.compare(&b"defabc"[..]), CompareResult::Error);
}
#[test]
fn compare_should_yield_incomplete_if_remaining_bytes_length_is_smaller_than_other(
) {
let span1 = Span::from(b"abcdef").with_length(2);
let span2 = Span::from(b"abcdef").with_length(4);
assert_eq!(span1.compare(span2), CompareResult::Incomplete);
assert_eq!(span1.compare("abcdef"), CompareResult::Incomplete);
assert_eq!(
span1.compare(&b"abcdef"[..]),
CompareResult::Incomplete
);
}
#[test]
fn compare_no_case_should_yield_ok_if_remaining_bytes_are_equal() {
let span1 = Span::from("abcdef").starting_at(4);
let span2 = Span::from("AbCdEf").starting_at(4);
assert_eq!(span1.compare_no_case(span2), CompareResult::Ok);
assert_eq!(span1.compare_no_case("Ef"), CompareResult::Ok);
assert_eq!(span1.compare_no_case(&b"Ef"[..]), CompareResult::Ok);
}
#[test]
fn compare_no_case_should_yield_error_if_remaining_bytes_are_not_equal()
{
let span1 = Span::from("abcdef").starting_at(4);
let span2 = Span::from("DeFaBc").starting_at(4);
assert_eq!(span1.compare_no_case(span2), CompareResult::Error);
assert_eq!(span1.compare_no_case("Bc"), CompareResult::Error);
assert_eq!(span1.compare_no_case(&b"Bc"[..]), CompareResult::Error);
}
#[test]
fn compare_no_case_should_yield_incomplete_if_remaining_bytes_length_is_smaller_than_other(
) {
let span1 = Span::from("abcdef").with_length(2);
let span2 = Span::from("AbCdEf").with_length(4);
assert_eq!(span1.compare_no_case(span2), CompareResult::Incomplete);
assert_eq!(
span1.compare_no_case("AbCdEf"),
CompareResult::Incomplete
);
assert_eq!(
span1.compare_no_case(&b"AbCdEf"[..]),
CompareResult::Incomplete
);
}
#[test]
fn new_builder_should_create_an_empty_byte_vec() {
let span1 = Span::from("abc");
assert_eq!(span1.new_builder(), Vec::<u8>::new());
}
#[test]
fn extend_into_should_copy_remaining_bytes_to_end_of_provided_byte_vec()
{
let span = Span::from(b"abcdef").starting_at(3);
let mut acc = b"123".to_vec();
span.extend_into(&mut acc);
assert_eq!(acc, b"123def");
assert_eq!(span.as_bytes(), b"def");
}
#[test]
fn find_substring_should_yield_none_if_unable_to_find_byte_string_in_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(4);
assert_eq!(span.find_substring(&b"c1"[..]), None);
}
#[test]
fn find_substring_should_yield_position_of_first_byte_string_match_in_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(span.find_substring(&b"c1"[..]), Some(0));
}
#[test]
fn find_substring_should_yield_none_if_unable_to_find_string_in_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(4);
assert_eq!(span.find_substring("c1"), None);
}
#[test]
fn find_substring_should_yield_some_position_of_first_string_match() {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(span.find_substring("c1"), Some(0));
}
#[test]
fn find_token_should_yield_true_if_byte_exists_in_remaining_bytes() {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(span.find_token(b'c'), true);
}
#[test]
fn find_token_should_yield_false_if_byte_missing_in_remaining_bytes() {
let span = Span::from(b"abc123").starting_at(4);
assert_eq!(span.find_token(b'c'), false);
}
#[test]
fn find_token_should_yield_true_if_byte_ref_exists_in_remaining_bytes()
{
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(span.find_token(&b'c'), true);
}
#[test]
fn find_token_should_yield_false_if_byte_ref_missing_in_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(4);
assert_eq!(span.find_token(&b'c'), false);
}
#[test]
fn find_token_should_yield_true_if_char_exists_in_remaining_bytes() {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(span.find_token('c'), true);
}
#[test]
fn find_token_should_yield_false_if_char_missing_in_remaining_bytes() {
let span = Span::from(b"abc123").starting_at(4);
assert_eq!(span.find_token('c'), false);
}
#[test]
fn iter_indicies_should_yield_an_iterator_of_remaining_index_and_byte_tuples(
) {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(
span.iter_indices().collect::<Vec<_>>(),
vec![(0, b'c'), (1, b'1'), (2, b'2'), (3, b'3')]
);
}
#[test]
fn iter_elements_should_yield_an_iterator_of_remaining_bytes() {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(
span.iter_elements().collect::<Vec<_>>(),
vec![b'c', b'1', b'2', b'3']
);
}
#[test]
fn position_should_yield_an_none_if_the_predicate_does_not_match_a_remaining_byte(
) {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(span.position(|_| false), None);
}
#[test]
fn position_should_yield_an_index_if_the_predicate_matches_a_remaining_byte(
) {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(span.position(|b| b == b'c'), Some(0));
}
#[test]
fn slice_index_should_yield_the_index_if_available_in_remaining_bytes()
{
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(span.slice_index(3), Ok(3));
}
#[test]
fn slice_index_should_yield_none_if_unavailable_in_remaining_bytes() {
let span = Span::from(b"abc123").starting_at(3);
assert_eq!(span.slice_index(4), Err(nom::Needed::new(1)));
}
#[test]
fn input_len_should_yield_the_byte_length_of_remaining_bytes() {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(span.input_len(), 4);
}
#[test]
fn take_should_yield_a_span_that_has_the_first_n_remaining_bytes() {
let span = Span::from(b"abc123").starting_at(2);
let span = span.take(3);
assert_eq!(span.as_bytes(), b"c12");
}
#[test]
fn take_split_should_yield_two_spans_the_first_is_remaining_bytes_after_n_and_second_is_remaining_bytes_up_to_n(
) {
let span = Span::from(b"abc123").starting_at(2);
let (suffix, prefix) = span.take_split(2);
assert_eq!(prefix.as_bytes(), b"c1");
assert_eq!(suffix.as_bytes(), b"23");
}
#[test]
fn take_split_should_support_producing_an_empty_prefix_span() {
let span = Span::from(b"abc123").starting_at(2);
let (suffix, prefix) = span.take_split(0);
assert_eq!(prefix.as_bytes(), b"");
assert_eq!(suffix.as_bytes(), b"c123");
}
#[test]
fn take_split_should_support_producing_an_empty_suffix_span() {
let span = Span::from(b"abc123").starting_at(2);
let (suffix, prefix) = span.take_split(4);
assert_eq!(prefix.as_bytes(), b"c123");
assert_eq!(suffix.as_bytes(), b"");
}
#[test]
fn split_at_position_should_yield_incomplete_if_no_match_found_in_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(
span.split_at_position::<_, ()>(|_| false),
Err(nom::Err::Incomplete(nom::Needed::new(1)))
);
}
#[test]
fn split_at_position_should_yield_remaining_bytes_up_to_the_first_match_in_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(2);
let (suffix, prefix) =
span.split_at_position::<_, ()>(|b| b == b'2').unwrap();
assert_eq!(prefix.as_bytes(), b"c1");
assert_eq!(suffix.as_bytes(), b"23");
}
#[test]
fn split_at_position_should_support_an_empty_span_being_produced_from_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(2);
let (suffix, prefix) =
span.split_at_position::<_, ()>(|b| b == b'c').unwrap();
assert_eq!(prefix.as_bytes(), b"");
assert_eq!(suffix.as_bytes(), b"c123");
}
#[test]
fn split_at_position1_should_yield_incomplete_if_no_match_found_in_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(
span.split_at_position1::<_, ()>(|_| false, ErrorKind::Alpha),
Err(nom::Err::Incomplete(nom::Needed::new(1)))
);
}
#[test]
fn split_at_position1_should_yield_remaining_bytes_up_to_the_first_match_in_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(2);
let (suffix, prefix) = span
.split_at_position1::<_, ()>(|b| b == b'2', ErrorKind::Alpha)
.unwrap();
assert_eq!(prefix.as_bytes(), b"c1");
assert_eq!(suffix.as_bytes(), b"23");
}
#[test]
fn split_at_position1_fail_if_an_empty_span_would_be_produced_from_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(
span.split_at_position1::<_, (Span, ErrorKind)>(
|b| b == b'c',
ErrorKind::Alpha,
),
Err(nom::Err::Error((span, ErrorKind::Alpha)))
);
}
#[test]
fn split_at_position_complete_should_yield_all_input_if_no_match_found_in_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(
span.split_at_position_complete::<_, ()>(|_| false),
Ok((Span::from(b"abc123").starting_at(6), span))
);
}
#[test]
fn split_at_position_complete_should_yield_remaining_bytes_up_to_the_first_match_in_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(2);
let (suffix, prefix) = span
.split_at_position_complete::<_, ()>(|b| b == b'2')
.unwrap();
assert_eq!(prefix.as_bytes(), b"c1");
assert_eq!(suffix.as_bytes(), b"23");
}
#[test]
fn split_at_position_complete_should_support_an_empty_span_being_produced_from_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(2);
let (suffix, prefix) = span
.split_at_position_complete::<_, ()>(|b| b == b'c')
.unwrap();
assert_eq!(prefix.as_bytes(), b"");
assert_eq!(suffix.as_bytes(), b"c123");
}
#[test]
fn split_at_position1_complete_should_yield_all_input_if_no_match_found_in_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(
span.split_at_position1_complete::<_, ()>(
|_| false,
ErrorKind::Alpha
),
Ok((Span::from(b"abc123").starting_at(6), span))
);
}
#[test]
fn split_at_position1_complete_should_yield_remaining_bytes_up_to_the_first_match_in_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(2);
let (suffix, prefix) = span
.split_at_position1_complete::<_, ()>(
|b| b == b'2',
ErrorKind::Alpha,
)
.unwrap();
assert_eq!(prefix.as_bytes(), b"c1");
assert_eq!(suffix.as_bytes(), b"23");
}
#[test]
fn split_at_position1_complete_fail_if_an_empty_span_would_be_produced_from_remaining_bytes(
) {
let span = Span::from(b"abc123").starting_at(2);
assert_eq!(
span.split_at_position1_complete::<_, (Span, ErrorKind)>(
|b| b == b'c',
ErrorKind::Alpha,
),
Err(nom::Err::Error((span, ErrorKind::Alpha)))
);
}
#[test]
fn offset_should_yield_offset_between_first_remaining_byte_of_self_with_remaining_byte_of_other(
) {
let span1 = Span::from(b"abc123").starting_at(2);
let span2 = Span::from(b"abc123").starting_at(3);
assert_eq!(span1.offset(&span2), 1);
}
#[test]
fn offset_should_yield_zero_if_at_same_offset() {
let span1 = Span::from("abc123").starting_at(2);
let span2 = Span::from("abc123").starting_at(2);
assert_eq!(span1.offset(&span2), 0);
}
#[test]
#[should_panic]
fn offset_should_panic_if_would_yield_negative_value() {
let span1 = Span::from("abc123").starting_at(2);
let span2 = Span::from(b"abc123").starting_at(3);
span2.offset(&span1);
}
#[test]
fn parse_to_should_convert_remaining_bytes_to_str_and_then_apply_parse()
{
let span = Span::from(b"abc123").starting_at(3);
let result: u32 = span.parse_to().unwrap();
assert_eq!(result, 123);
}
#[test]
fn parse_to_should_yield_none_if_failing_to_parse() {
let span = Span::from(b"abc123").starting_at(2);
let result: Option<u32> = span.parse_to();
assert_eq!(result, None);
}
#[test]
fn slice_should_yield_a_clone_of_span_if_given_full_range() {
let span1 = Span::from(b"abc123").starting_at(2);
let span2 = span1.slice(..);
assert_eq!(span1, span2);
}
#[test]
fn slice_should_support_yielding_an_empty_span() {
let span1 = Span::from(b"abc123").starting_at(2);
let span2 = span1.slice(0..0);
assert_eq!(span2.start_offset(), 2);
assert_eq!(span2.end_offset(), 2);
assert_eq!(span2.as_bytes(), b"");
let span2 = span1.slice(11..);
assert_eq!(span2.start_offset(), 6);
assert_eq!(span2.end_offset(), 6);
assert_eq!(span2.as_bytes(), b"");
let span2 = span1.slice(..0);
assert_eq!(span2.start_offset(), 2);
assert_eq!(span2.end_offset(), 2);
assert_eq!(span2.as_bytes(), b"");
}
#[test]
fn slice_should_adjust_start_and_end_offsets_accordingly() {
let span1 = Span::from(b"abc123");
let span2 = span1.slice(0..2);
assert_eq!(span2.start_offset(), 0);
assert_eq!(span2.end_offset(), 2);
assert_eq!(span2.as_bytes(), b"ab");
let span2 = span1.slice(2..);
assert_eq!(span2.start_offset(), 2);
assert_eq!(span2.end_offset(), 6);
assert_eq!(span2.as_bytes(), b"c123");
let span2 = span1.slice(..2);
assert_eq!(span2.start_offset(), 0);
assert_eq!(span2.end_offset(), 2);
assert_eq!(span2.as_bytes(), b"ab");
}
}
}