#[cfg(feature = "std")]
use std::borrow::Cow;
#[cfg(feature = "std")]
use std::ffi::OsStr;
#[cfg(feature = "std")]
use std::path::Path;
use core::cmp;
use core::ops;
use core::ptr;
use core::slice;
use core::str;
use memchr::{memchr, memrchr};
use ascii;
use bstr::BStr;
#[cfg(feature = "std")]
use ext_vec::ByteVec;
use search::{PrefilterState, TwoWay};
#[cfg(feature = "unicode")]
use unicode::{
whitespace_len_fwd, whitespace_len_rev, GraphemeIndices, Graphemes,
SentenceIndices, Sentences, WordIndices, Words, WordsWithBreakIndices,
WordsWithBreaks,
};
use utf8::{self, CharIndices, Chars, Utf8Error};
#[allow(non_snake_case)]
#[inline]
pub fn B<'a, B: ?Sized + AsRef<[u8]>>(bytes: &'a B) -> &'a [u8] {
bytes.as_ref()
}
impl ByteSlice for [u8] {
fn as_bytes(&self) -> &[u8] {
self
}
fn as_bytes_mut(&mut self) -> &mut [u8] {
self
}
}
pub trait Sealed {}
impl Sealed for [u8] {}
pub trait ByteSlice: Sealed {
#[doc(hidden)]
fn as_bytes(&self) -> &[u8];
#[doc(hidden)]
fn as_bytes_mut(&mut self) -> &mut [u8];
fn as_bstr(&self) -> &BStr {
BStr::new(self.as_bytes())
}
fn as_bstr_mut(&mut self) -> &mut BStr {
BStr::new_mut(self.as_bytes_mut())
}
#[cfg(feature = "std")]
#[inline]
fn from_os_str(os_str: &OsStr) -> Option<&[u8]> {
#[cfg(unix)]
#[inline]
fn imp(os_str: &OsStr) -> Option<&[u8]> {
use std::os::unix::ffi::OsStrExt;
Some(os_str.as_bytes())
}
#[cfg(not(unix))]
#[inline]
fn imp(os_str: &OsStr) -> Option<&[u8]> {
os_str.to_str().map(|s| s.as_bytes())
}
imp(os_str)
}
#[cfg(feature = "std")]
#[inline]
fn from_path(path: &Path) -> Option<&[u8]> {
Self::from_os_str(path.as_os_str())
}
#[inline]
fn to_str(&self) -> Result<&str, Utf8Error> {
utf8::validate(self.as_bytes()).map(|_| {
unsafe { str::from_utf8_unchecked(self.as_bytes()) }
})
}
unsafe fn to_str_unchecked(&self) -> &str {
str::from_utf8_unchecked(self.as_bytes())
}
#[cfg(feature = "std")]
#[inline]
fn to_str_lossy(&self) -> Cow<str> {
match utf8::validate(self.as_bytes()) {
Ok(()) => {
unsafe {
Cow::Borrowed(str::from_utf8_unchecked(self.as_bytes()))
}
}
Err(err) => {
let mut lossy = String::with_capacity(self.as_bytes().len());
let (valid, after) =
self.as_bytes().split_at(err.valid_up_to());
lossy.push_str(unsafe { str::from_utf8_unchecked(valid) });
lossy.push_str("\u{FFFD}");
if let Some(len) = err.error_len() {
after[len..].to_str_lossy_into(&mut lossy);
}
Cow::Owned(lossy)
}
}
}
#[cfg(feature = "std")]
#[inline]
fn to_str_lossy_into(&self, dest: &mut String) {
let mut bytes = self.as_bytes();
dest.reserve(bytes.len());
loop {
match utf8::validate(bytes) {
Ok(()) => {
dest.push_str(unsafe { str::from_utf8_unchecked(bytes) });
break;
}
Err(err) => {
let (valid, after) = bytes.split_at(err.valid_up_to());
dest.push_str(unsafe { str::from_utf8_unchecked(valid) });
dest.push_str("\u{FFFD}");
match err.error_len() {
None => break,
Some(len) => bytes = &after[len..],
}
}
}
}
}
#[cfg(feature = "std")]
#[inline]
fn to_os_str(&self) -> Result<&OsStr, Utf8Error> {
#[cfg(unix)]
#[inline]
fn imp(bytes: &[u8]) -> Result<&OsStr, Utf8Error> {
use std::os::unix::ffi::OsStrExt;
Ok(OsStr::from_bytes(bytes))
}
#[cfg(not(unix))]
#[inline]
fn imp(bytes: &[u8]) -> Result<&OsStr, Utf8Error> {
bytes.to_str().map(OsStr::new)
}
imp(self.as_bytes())
}
#[cfg(feature = "std")]
#[inline]
fn to_os_str_lossy(&self) -> Cow<OsStr> {
#[cfg(unix)]
#[inline]
fn imp(bytes: &[u8]) -> Cow<OsStr> {
use std::os::unix::ffi::OsStrExt;
Cow::Borrowed(OsStr::from_bytes(bytes))
}
#[cfg(not(unix))]
#[inline]
fn imp(bytes: &[u8]) -> Cow<OsStr> {
use std::ffi::OsString;
match bytes.to_str_lossy() {
Cow::Borrowed(x) => Cow::Borrowed(OsStr::new(x)),
Cow::Owned(x) => Cow::Owned(OsString::from(x)),
}
}
imp(self.as_bytes())
}
#[cfg(feature = "std")]
#[inline]
fn to_path(&self) -> Result<&Path, Utf8Error> {
self.to_os_str().map(Path::new)
}
#[cfg(feature = "std")]
#[inline]
fn to_path_lossy(&self) -> Cow<Path> {
use std::path::PathBuf;
match self.to_os_str_lossy() {
Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)),
Cow::Owned(x) => Cow::Owned(PathBuf::from(x)),
}
}
#[cfg(feature = "std")]
#[inline]
fn repeatn(&self, n: usize) -> Vec<u8> {
let bs = self.as_bytes();
let mut dst = vec![0; bs.len() * n];
for i in 0..n {
dst[i * bs.len()..(i + 1) * bs.len()].copy_from_slice(bs);
}
dst
}
#[inline]
fn contains_str<B: AsRef<[u8]>>(&self, needle: B) -> bool {
self.find(needle).is_some()
}
#[inline]
fn starts_with_str<B: AsRef<[u8]>>(&self, prefix: B) -> bool {
self.as_bytes().starts_with(prefix.as_ref())
}
#[inline]
fn ends_with_str<B: AsRef<[u8]>>(&self, suffix: B) -> bool {
self.as_bytes().ends_with(suffix.as_ref())
}
#[inline]
fn find<B: AsRef<[u8]>>(&self, needle: B) -> Option<usize> {
Finder::new(needle.as_ref()).find(self.as_bytes())
}
#[inline]
fn rfind<B: AsRef<[u8]>>(&self, needle: B) -> Option<usize> {
FinderReverse::new(needle.as_ref()).rfind(self.as_bytes())
}
#[inline]
fn find_iter<'a, B: ?Sized + AsRef<[u8]>>(
&'a self,
needle: &'a B,
) -> Find<'a> {
Find::new(self.as_bytes(), needle.as_ref())
}
#[inline]
fn rfind_iter<'a, B: ?Sized + AsRef<[u8]>>(
&'a self,
needle: &'a B,
) -> FindReverse<'a> {
FindReverse::new(self.as_bytes(), needle.as_ref())
}
#[inline]
fn find_byte(&self, byte: u8) -> Option<usize> {
memchr(byte, self.as_bytes())
}
#[inline]
fn rfind_byte(&self, byte: u8) -> Option<usize> {
memrchr(byte, self.as_bytes())
}
#[inline]
fn find_char(&self, ch: char) -> Option<usize> {
self.find(ch.encode_utf8(&mut [0; 4]))
}
#[inline]
fn rfind_char(&self, ch: char) -> Option<usize> {
self.rfind(ch.encode_utf8(&mut [0; 4]))
}
#[inline]
fn fields(&self) -> Fields {
Fields::new(self.as_bytes())
}
#[inline]
fn fields_with<F: FnMut(char) -> bool>(&self, f: F) -> FieldsWith<F> {
FieldsWith::new(self.as_bytes(), f)
}
#[inline]
fn split_str<'a, B: ?Sized + AsRef<[u8]>>(
&'a self,
splitter: &'a B,
) -> Split<'a> {
Split::new(self.as_bytes(), splitter.as_ref())
}
#[inline]
fn rsplit_str<'a, B: ?Sized + AsRef<[u8]>>(
&'a self,
splitter: &'a B,
) -> SplitReverse<'a> {
SplitReverse::new(self.as_bytes(), splitter.as_ref())
}
#[inline]
fn splitn_str<'a, B: ?Sized + AsRef<[u8]>>(
&'a self,
limit: usize,
splitter: &'a B,
) -> SplitN<'a> {
SplitN::new(self.as_bytes(), splitter.as_ref(), limit)
}
#[inline]
fn rsplitn_str<'a, B: ?Sized + AsRef<[u8]>>(
&'a self,
limit: usize,
splitter: &'a B,
) -> SplitNReverse<'a> {
SplitNReverse::new(self.as_bytes(), splitter.as_ref(), limit)
}
#[cfg(feature = "std")]
#[inline]
fn replace<N: AsRef<[u8]>, R: AsRef<[u8]>>(
&self,
needle: N,
replacement: R,
) -> Vec<u8> {
let mut dest = Vec::with_capacity(self.as_bytes().len());
self.replace_into(needle, replacement, &mut dest);
dest
}
#[cfg(feature = "std")]
#[inline]
fn replacen<N: AsRef<[u8]>, R: AsRef<[u8]>>(
&self,
needle: N,
replacement: R,
limit: usize,
) -> Vec<u8> {
let mut dest = Vec::with_capacity(self.as_bytes().len());
self.replacen_into(needle, replacement, limit, &mut dest);
dest
}
#[cfg(feature = "std")]
#[inline]
fn replace_into<N: AsRef<[u8]>, R: AsRef<[u8]>>(
&self,
needle: N,
replacement: R,
dest: &mut Vec<u8>,
) {
let (needle, replacement) = (needle.as_ref(), replacement.as_ref());
let mut last = 0;
for start in self.find_iter(needle) {
dest.push_str(&self.as_bytes()[last..start]);
dest.push_str(replacement);
last = start + needle.len();
}
dest.push_str(&self.as_bytes()[last..]);
}
#[cfg(feature = "std")]
#[inline]
fn replacen_into<N: AsRef<[u8]>, R: AsRef<[u8]>>(
&self,
needle: N,
replacement: R,
limit: usize,
dest: &mut Vec<u8>,
) {
let (needle, replacement) = (needle.as_ref(), replacement.as_ref());
let mut last = 0;
for start in self.find_iter(needle).take(limit) {
dest.push_str(&self.as_bytes()[last..start]);
dest.push_str(replacement);
last = start + needle.len();
}
dest.push_str(&self.as_bytes()[last..]);
}
#[inline]
fn bytes(&self) -> Bytes {
Bytes { it: self.as_bytes().iter() }
}
#[inline]
fn chars(&self) -> Chars {
Chars::new(self.as_bytes())
}
#[inline]
fn char_indices(&self) -> CharIndices {
CharIndices::new(self.as_bytes())
}
#[cfg(feature = "unicode")]
#[inline]
fn graphemes(&self) -> Graphemes {
Graphemes::new(self.as_bytes())
}
#[cfg(feature = "unicode")]
#[inline]
fn grapheme_indices(&self) -> GraphemeIndices {
GraphemeIndices::new(self.as_bytes())
}
#[cfg(feature = "unicode")]
#[inline]
fn words(&self) -> Words {
Words::new(self.as_bytes())
}
#[cfg(feature = "unicode")]
#[inline]
fn word_indices(&self) -> WordIndices {
WordIndices::new(self.as_bytes())
}
#[cfg(feature = "unicode")]
#[inline]
fn words_with_breaks(&self) -> WordsWithBreaks {
WordsWithBreaks::new(self.as_bytes())
}
#[cfg(feature = "unicode")]
#[inline]
fn words_with_break_indices(&self) -> WordsWithBreakIndices {
WordsWithBreakIndices::new(self.as_bytes())
}
#[cfg(feature = "unicode")]
#[inline]
fn sentences(&self) -> Sentences {
Sentences::new(self.as_bytes())
}
#[cfg(feature = "unicode")]
#[inline]
fn sentence_indices(&self) -> SentenceIndices {
SentenceIndices::new(self.as_bytes())
}
#[inline]
fn lines(&self) -> Lines {
Lines::new(self.as_bytes())
}
#[inline]
fn lines_with_terminator(&self) -> LinesWithTerminator {
LinesWithTerminator::new(self.as_bytes())
}
#[cfg(feature = "unicode")]
#[inline]
fn trim(&self) -> &[u8] {
self.trim_start().trim_end()
}
#[cfg(feature = "unicode")]
#[inline]
fn trim_start(&self) -> &[u8] {
let start = whitespace_len_fwd(self.as_bytes());
&self.as_bytes()[start..]
}
#[cfg(feature = "unicode")]
#[inline]
fn trim_end(&self) -> &[u8] {
let end = whitespace_len_rev(self.as_bytes());
&self.as_bytes()[..end]
}
#[inline]
fn trim_with<F: FnMut(char) -> bool>(&self, mut trim: F) -> &[u8] {
self.trim_start_with(&mut trim).trim_end_with(&mut trim)
}
#[inline]
fn trim_start_with<F: FnMut(char) -> bool>(&self, mut trim: F) -> &[u8] {
for (s, _, ch) in self.char_indices() {
if !trim(ch) {
return &self.as_bytes()[s..];
}
}
b""
}
#[inline]
fn trim_end_with<F: FnMut(char) -> bool>(&self, mut trim: F) -> &[u8] {
for (_, e, ch) in self.char_indices().rev() {
if !trim(ch) {
return &self.as_bytes()[..e];
}
}
b""
}
#[cfg(all(feature = "std", feature = "unicode"))]
#[inline]
fn to_lowercase(&self) -> Vec<u8> {
let mut buf = vec![];
self.to_lowercase_into(&mut buf);
buf
}
#[cfg(all(feature = "std", feature = "unicode"))]
#[inline]
fn to_lowercase_into(&self, buf: &mut Vec<u8>) {
buf.reserve(self.as_bytes().len());
for (s, e, ch) in self.char_indices() {
if ch == '\u{FFFD}' {
buf.push_str(&self.as_bytes()[s..e]);
} else if ch.is_ascii() {
buf.push_char(ch.to_ascii_lowercase());
} else {
for upper in ch.to_lowercase() {
buf.push_char(upper);
}
}
}
}
#[cfg(feature = "std")]
#[inline]
fn to_ascii_lowercase(&self) -> Vec<u8> {
self.as_bytes().to_ascii_lowercase()
}
#[inline]
fn make_ascii_lowercase(&mut self) {
self.as_bytes_mut().make_ascii_lowercase();
}
#[cfg(all(feature = "std", feature = "unicode"))]
#[inline]
fn to_uppercase(&self) -> Vec<u8> {
let mut buf = vec![];
self.to_uppercase_into(&mut buf);
buf
}
#[cfg(all(feature = "std", feature = "unicode"))]
#[inline]
fn to_uppercase_into(&self, buf: &mut Vec<u8>) {
buf.reserve(self.as_bytes().len());
for (s, e, ch) in self.char_indices() {
if ch == '\u{FFFD}' {
buf.push_str(&self.as_bytes()[s..e]);
} else if ch.is_ascii() {
buf.push_char(ch.to_ascii_uppercase());
} else {
for upper in ch.to_uppercase() {
buf.push_char(upper);
}
}
}
}
#[cfg(feature = "std")]
#[inline]
fn to_ascii_uppercase(&self) -> Vec<u8> {
self.as_bytes().to_ascii_uppercase()
}
#[inline]
fn make_ascii_uppercase(&mut self) {
self.as_bytes_mut().make_ascii_uppercase();
}
#[inline]
fn reverse_bytes(&mut self) {
self.as_bytes_mut().reverse();
}
#[inline]
fn reverse_chars(&mut self) {
let mut i = 0;
loop {
let (_, size) = utf8::decode(&self.as_bytes()[i..]);
if size == 0 {
break;
}
if size > 1 {
self.as_bytes_mut()[i..i + size].reverse_bytes();
}
i += size;
}
self.reverse_bytes();
}
#[cfg(feature = "unicode")]
#[inline]
fn reverse_graphemes(&mut self) {
use unicode::decode_grapheme;
let mut i = 0;
loop {
let (_, size) = decode_grapheme(&self.as_bytes()[i..]);
if size == 0 {
break;
}
if size > 1 {
self.as_bytes_mut()[i..i + size].reverse_bytes();
}
i += size;
}
self.reverse_bytes();
}
#[inline]
fn is_ascii(&self) -> bool {
ascii::first_non_ascii_byte(self.as_bytes()) == self.as_bytes().len()
}
#[inline]
fn is_utf8(&self) -> bool {
utf8::validate(self.as_bytes()).is_ok()
}
#[inline]
fn last_byte(&self) -> Option<u8> {
let bytes = self.as_bytes();
bytes.get(bytes.len().saturating_sub(1)).map(|&b| b)
}
#[inline]
fn copy_within_str<R>(&mut self, src: R, dest: usize)
where
R: ops::RangeBounds<usize>,
{
let src_start = match src.start_bound() {
ops::Bound::Included(&n) => n,
ops::Bound::Excluded(&n) => {
n.checked_add(1).expect("attempted to index slice beyond max")
}
ops::Bound::Unbounded => 0,
};
let src_end = match src.end_bound() {
ops::Bound::Included(&n) => {
n.checked_add(1).expect("attempted to index slice beyond max")
}
ops::Bound::Excluded(&n) => n,
ops::Bound::Unbounded => self.as_bytes().len(),
};
assert!(src_start <= src_end, "src end is before src start");
assert!(src_end <= self.as_bytes().len(), "src is out of bounds");
let count = src_end - src_start;
assert!(
dest <= self.as_bytes().len() - count,
"dest is out of bounds",
);
unsafe {
ptr::copy(
self.as_bytes().get_unchecked(src_start),
self.as_bytes_mut().get_unchecked_mut(dest),
count,
);
}
}
}
#[derive(Clone, Debug)]
pub struct Finder<'a> {
searcher: TwoWay<'a>,
}
impl<'a> Finder<'a> {
#[inline]
pub fn new<B: ?Sized + AsRef<[u8]>>(needle: &'a B) -> Finder<'a> {
Finder { searcher: TwoWay::forward(needle.as_ref()) }
}
#[cfg(feature = "std")]
#[inline]
pub fn into_owned(self) -> Finder<'static> {
Finder { searcher: self.searcher.into_owned() }
}
#[inline]
pub fn needle(&self) -> &[u8] {
self.searcher.needle()
}
#[inline]
pub fn find<B: AsRef<[u8]>>(&self, haystack: B) -> Option<usize> {
self.searcher.find(haystack.as_ref())
}
}
#[derive(Clone, Debug)]
pub struct FinderReverse<'a> {
searcher: TwoWay<'a>,
}
impl<'a> FinderReverse<'a> {
#[inline]
pub fn new<B: ?Sized + AsRef<[u8]>>(needle: &'a B) -> FinderReverse<'a> {
FinderReverse { searcher: TwoWay::reverse(needle.as_ref()) }
}
#[cfg(feature = "std")]
#[inline]
pub fn into_owned(self) -> FinderReverse<'static> {
FinderReverse { searcher: self.searcher.into_owned() }
}
#[inline]
pub fn needle(&self) -> &[u8] {
self.searcher.needle()
}
#[inline]
pub fn rfind<B: AsRef<[u8]>>(&self, haystack: B) -> Option<usize> {
self.searcher.rfind(haystack.as_ref())
}
}
#[derive(Debug)]
pub struct Find<'a> {
haystack: &'a [u8],
prestate: PrefilterState,
searcher: TwoWay<'a>,
pos: usize,
}
impl<'a> Find<'a> {
fn new(haystack: &'a [u8], needle: &'a [u8]) -> Find<'a> {
let searcher = TwoWay::forward(needle);
let prestate = searcher.prefilter_state();
Find { haystack, prestate, searcher, pos: 0 }
}
}
impl<'a> Iterator for Find<'a> {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<usize> {
if self.pos > self.haystack.len() {
return None;
}
let result = self
.searcher
.find_with(&mut self.prestate, &self.haystack[self.pos..]);
match result {
None => None,
Some(i) => {
let pos = self.pos + i;
self.pos = pos + cmp::max(1, self.searcher.needle().len());
Some(pos)
}
}
}
}
#[derive(Debug)]
pub struct FindReverse<'a> {
haystack: &'a [u8],
prestate: PrefilterState,
searcher: TwoWay<'a>,
pos: Option<usize>,
}
impl<'a> FindReverse<'a> {
fn new(haystack: &'a [u8], needle: &'a [u8]) -> FindReverse<'a> {
let searcher = TwoWay::reverse(needle);
let prestate = searcher.prefilter_state();
let pos = Some(haystack.len());
FindReverse { haystack, prestate, searcher, pos }
}
fn haystack(&self) -> &'a [u8] {
self.haystack
}
fn needle(&self) -> &[u8] {
self.searcher.needle()
}
}
impl<'a> Iterator for FindReverse<'a> {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<usize> {
let pos = match self.pos {
None => return None,
Some(pos) => pos,
};
let result = self
.searcher
.rfind_with(&mut self.prestate, &self.haystack[..pos]);
match result {
None => None,
Some(i) => {
if pos == i {
self.pos = pos.checked_sub(1);
} else {
self.pos = Some(i);
}
Some(i)
}
}
}
}
#[derive(Clone, Debug)]
pub struct Bytes<'a> {
it: slice::Iter<'a, u8>,
}
impl<'a> Iterator for Bytes<'a> {
type Item = u8;
#[inline]
fn next(&mut self) -> Option<u8> {
self.it.next().map(|&b| b)
}
}
impl<'a> DoubleEndedIterator for Bytes<'a> {
#[inline]
fn next_back(&mut self) -> Option<u8> {
self.it.next_back().map(|&b| b)
}
}
impl<'a> ExactSizeIterator for Bytes<'a> {
#[inline]
fn len(&self) -> usize {
self.it.len()
}
}
#[derive(Debug)]
pub struct Fields<'a> {
it: FieldsWith<'a, fn(char) -> bool>,
}
impl<'a> Fields<'a> {
fn new(bytes: &'a [u8]) -> Fields<'a> {
Fields { it: bytes.fields_with(|ch| ch.is_whitespace()) }
}
}
impl<'a> Iterator for Fields<'a> {
type Item = &'a [u8];
#[inline]
fn next(&mut self) -> Option<&'a [u8]> {
self.it.next()
}
}
#[derive(Debug)]
pub struct FieldsWith<'a, F> {
f: F,
bytes: &'a [u8],
chars: CharIndices<'a>,
}
impl<'a, F: FnMut(char) -> bool> FieldsWith<'a, F> {
fn new(bytes: &'a [u8], f: F) -> FieldsWith<'a, F> {
FieldsWith { f: f, bytes: bytes, chars: bytes.char_indices() }
}
}
impl<'a, F: FnMut(char) -> bool> Iterator for FieldsWith<'a, F> {
type Item = &'a [u8];
#[inline]
fn next(&mut self) -> Option<&'a [u8]> {
let (start, mut end);
loop {
match self.chars.next() {
None => return None,
Some((s, e, ch)) => {
if !(self.f)(ch) {
start = s;
end = e;
break;
}
}
}
}
while let Some((_, e, ch)) = self.chars.next() {
if (self.f)(ch) {
break;
}
end = e;
}
Some(&self.bytes[start..end])
}
}
#[derive(Debug)]
pub struct Split<'a> {
finder: Find<'a>,
last: usize,
done: bool,
}
impl<'a> Split<'a> {
fn new(haystack: &'a [u8], splitter: &'a [u8]) -> Split<'a> {
let finder = haystack.find_iter(splitter);
Split { finder, last: 0, done: false }
}
}
impl<'a> Iterator for Split<'a> {
type Item = &'a [u8];
#[inline]
fn next(&mut self) -> Option<&'a [u8]> {
let haystack = self.finder.haystack;
match self.finder.next() {
Some(start) => {
let next = &haystack[self.last..start];
self.last = start + self.finder.searcher.needle().len();
Some(next)
}
None => {
if self.last >= haystack.len() {
if !self.done {
self.done = true;
Some(b"")
} else {
None
}
} else {
let s = &haystack[self.last..];
self.last = haystack.len();
self.done = true;
Some(s)
}
}
}
}
}
#[derive(Debug)]
pub struct SplitReverse<'a> {
finder: FindReverse<'a>,
last: usize,
done: bool,
}
impl<'a> SplitReverse<'a> {
fn new(haystack: &'a [u8], splitter: &'a [u8]) -> SplitReverse<'a> {
let finder = haystack.rfind_iter(splitter);
SplitReverse { finder, last: haystack.len(), done: false }
}
}
impl<'a> Iterator for SplitReverse<'a> {
type Item = &'a [u8];
#[inline]
fn next(&mut self) -> Option<&'a [u8]> {
let haystack = self.finder.haystack();
match self.finder.next() {
Some(start) => {
let nlen = self.finder.needle().len();
let next = &haystack[start + nlen..self.last];
self.last = start;
Some(next)
}
None => {
if self.last == 0 {
if !self.done {
self.done = true;
Some(b"")
} else {
None
}
} else {
let s = &haystack[..self.last];
self.last = 0;
self.done = true;
Some(s)
}
}
}
}
}
#[derive(Debug)]
pub struct SplitN<'a> {
split: Split<'a>,
limit: usize,
count: usize,
}
impl<'a> SplitN<'a> {
fn new(
haystack: &'a [u8],
splitter: &'a [u8],
limit: usize,
) -> SplitN<'a> {
let split = haystack.split_str(splitter);
SplitN { split, limit, count: 0 }
}
}
impl<'a> Iterator for SplitN<'a> {
type Item = &'a [u8];
#[inline]
fn next(&mut self) -> Option<&'a [u8]> {
self.count += 1;
if self.count > self.limit {
None
} else if self.count == self.limit {
Some(&self.split.finder.haystack[self.split.last..])
} else {
self.split.next()
}
}
}
#[derive(Debug)]
pub struct SplitNReverse<'a> {
split: SplitReverse<'a>,
limit: usize,
count: usize,
}
impl<'a> SplitNReverse<'a> {
fn new(
haystack: &'a [u8],
splitter: &'a [u8],
limit: usize,
) -> SplitNReverse<'a> {
let split = haystack.rsplit_str(splitter);
SplitNReverse { split, limit, count: 0 }
}
}
impl<'a> Iterator for SplitNReverse<'a> {
type Item = &'a [u8];
#[inline]
fn next(&mut self) -> Option<&'a [u8]> {
self.count += 1;
if self.count > self.limit {
None
} else if self.count == self.limit {
Some(&self.split.finder.haystack()[..self.split.last])
} else {
self.split.next()
}
}
}
pub struct Lines<'a> {
it: LinesWithTerminator<'a>,
}
impl<'a> Lines<'a> {
fn new(bytes: &'a [u8]) -> Lines<'a> {
Lines { it: LinesWithTerminator::new(bytes) }
}
}
impl<'a> Iterator for Lines<'a> {
type Item = &'a [u8];
#[inline]
fn next(&mut self) -> Option<&'a [u8]> {
let mut line = self.it.next()?;
if line.last_byte() == Some(b'\n') {
line = &line[..line.len() - 1];
if line.last_byte() == Some(b'\r') {
line = &line[..line.len() - 1];
}
}
Some(line)
}
}
pub struct LinesWithTerminator<'a> {
bytes: &'a [u8],
}
impl<'a> LinesWithTerminator<'a> {
fn new(bytes: &'a [u8]) -> LinesWithTerminator<'a> {
LinesWithTerminator { bytes }
}
}
impl<'a> Iterator for LinesWithTerminator<'a> {
type Item = &'a [u8];
#[inline]
fn next(&mut self) -> Option<&'a [u8]> {
match self.bytes.find_byte(b'\n') {
None if self.bytes.is_empty() => None,
None => {
let line = self.bytes;
self.bytes = b"";
Some(line)
}
Some(end) => {
let line = &self.bytes[..end + 1];
self.bytes = &self.bytes[end + 1..];
Some(line)
}
}
}
}
#[cfg(test)]
mod tests {
use ext_slice::{ByteSlice, B};
use tests::LOSSY_TESTS;
#[test]
fn to_str_lossy() {
for (i, &(expected, input)) in LOSSY_TESTS.iter().enumerate() {
let got = B(input).to_str_lossy();
assert_eq!(
expected.as_bytes(),
got.as_bytes(),
"to_str_lossy(ith: {:?}, given: {:?})",
i,
input,
);
let mut got = String::new();
B(input).to_str_lossy_into(&mut got);
assert_eq!(
expected.as_bytes(),
got.as_bytes(),
"to_str_lossy_into",
);
let got = String::from_utf8_lossy(input);
assert_eq!(expected.as_bytes(), got.as_bytes(), "std");
}
}
#[test]
#[should_panic]
fn copy_within_fail1() {
let mut buf = *b"foobar";
let s = &mut buf;
s.copy_within_str(0..2, 5);
}
#[test]
#[should_panic]
fn copy_within_fail2() {
let mut buf = *b"foobar";
let s = &mut buf;
s.copy_within_str(3..2, 0);
}
#[test]
#[should_panic]
fn copy_within_fail3() {
let mut buf = *b"foobar";
let s = &mut buf;
s.copy_within_str(5..7, 0);
}
#[test]
#[should_panic]
fn copy_within_fail4() {
let mut buf = *b"foobar";
let s = &mut buf;
s.copy_within_str(0..1, 6);
}
}