use core::fmt;
use core::str::Utf8Error;
use std::borrow::{Borrow, Cow};
use std::cmp::Ordering;
use std::fmt::Display;
use std::hash::Hash;
use std::ops::Deref;
use std::str::FromStr;
use std::sync::Arc;
#[derive(Clone)]
#[repr(transparent)]
pub struct CheetahString {
pub(super) inner: InnerString,
}
impl Default for CheetahString {
fn default() -> Self {
CheetahString {
inner: InnerString::Inline {
len: 0,
data: [0; INLINE_CAPACITY],
},
}
}
}
impl From<String> for CheetahString {
#[inline]
fn from(s: String) -> Self {
CheetahString::from_string(s)
}
}
impl From<Arc<String>> for CheetahString {
#[inline]
fn from(s: Arc<String>) -> Self {
CheetahString::from_arc_string(s)
}
}
impl<'a> From<&'a str> for CheetahString {
#[inline]
fn from(s: &'a str) -> Self {
CheetahString::from_slice(s)
}
}
impl From<&[u8]> for CheetahString {
#[inline]
fn from(b: &[u8]) -> Self {
CheetahString::from_slice(unsafe { std::str::from_utf8_unchecked(b) })
}
}
impl FromStr for CheetahString {
type Err = std::string::ParseError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(CheetahString::from_slice(s))
}
}
impl From<Vec<u8>> for CheetahString {
#[inline]
fn from(v: Vec<u8>) -> Self {
CheetahString::from_slice(unsafe { std::str::from_utf8_unchecked(&v) })
}
}
impl From<Cow<'static, str>> for CheetahString {
#[inline]
fn from(cow: Cow<'static, str>) -> Self {
match cow {
Cow::Borrowed(s) => CheetahString::from_static_str(s),
Cow::Owned(s) => CheetahString::from_string(s),
}
}
}
impl From<Cow<'_, String>> for CheetahString {
#[inline]
fn from(cow: Cow<'_, String>) -> Self {
match cow {
Cow::Borrowed(s) => CheetahString::from_slice(s),
Cow::Owned(s) => CheetahString::from_string(s),
}
}
}
impl From<char> for CheetahString {
#[inline]
fn from(c: char) -> Self {
CheetahString::from_string(c.to_string())
}
}
impl<'a> FromIterator<&'a char> for CheetahString {
#[inline]
fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> CheetahString {
let mut buf = String::new();
buf.extend(iter);
CheetahString::from_string(buf)
}
}
impl<'a> FromIterator<&'a str> for CheetahString {
fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> CheetahString {
let mut buf = String::new();
buf.extend(iter);
CheetahString::from_string(buf)
}
}
impl FromIterator<String> for CheetahString {
#[inline]
fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
let mut buf = String::new();
buf.extend(iter);
CheetahString::from_string(buf)
}
}
impl<'a> FromIterator<&'a String> for CheetahString {
#[inline]
fn from_iter<T: IntoIterator<Item = &'a String>>(iter: T) -> Self {
let mut buf = String::new();
buf.extend(iter.into_iter().map(|s| s.as_str()));
CheetahString::from_string(buf)
}
}
#[cfg(feature = "bytes")]
impl From<bytes::Bytes> for CheetahString {
#[inline]
fn from(b: bytes::Bytes) -> Self {
CheetahString::from_bytes(b)
}
}
impl From<&CheetahString> for CheetahString {
#[inline]
fn from(s: &CheetahString) -> Self {
s.clone()
}
}
impl From<CheetahString> for String {
#[inline]
fn from(s: CheetahString) -> Self {
match s {
CheetahString {
inner: InnerString::Inline { len, data },
} => {
unsafe { String::from_utf8_unchecked(data[..len as usize].to_vec()) }
}
CheetahString {
inner: InnerString::StaticStr(s),
} => s.to_string(),
CheetahString {
inner: InnerString::ArcStr(s),
} => s.to_string(),
CheetahString {
inner: InnerString::ArcString(s),
} => s.as_ref().clone(),
CheetahString {
inner: InnerString::ArcVecString(s),
} => {
unsafe { String::from_utf8_unchecked(s.to_vec()) }
}
#[cfg(feature = "bytes")]
CheetahString {
inner: InnerString::Bytes(b),
} => {
unsafe { String::from_utf8_unchecked(b.to_vec()) }
}
}
}
}
impl Deref for CheetahString {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl AsRef<str> for CheetahString {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl AsRef<[u8]> for CheetahString {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsRef<CheetahString> for CheetahString {
#[inline]
fn as_ref(&self) -> &CheetahString {
self
}
}
impl From<&String> for CheetahString {
#[inline]
fn from(s: &String) -> Self {
CheetahString::from_slice(s)
}
}
impl CheetahString {
#[inline]
pub const fn empty() -> Self {
CheetahString {
inner: InnerString::Inline {
len: 0,
data: [0; INLINE_CAPACITY],
},
}
}
#[inline]
pub fn new() -> Self {
CheetahString::default()
}
#[inline]
pub const fn from_static_str(s: &'static str) -> Self {
CheetahString {
inner: InnerString::StaticStr(s),
}
}
#[inline]
pub fn from_vec(s: Vec<u8>) -> Self {
CheetahString {
inner: InnerString::ArcVecString(Arc::new(s)),
}
}
pub fn try_from_vec(v: Vec<u8>) -> Result<Self, Utf8Error> {
std::str::from_utf8(&v)?;
Ok(CheetahString {
inner: InnerString::ArcVecString(Arc::new(v)),
})
}
pub fn try_from_bytes(b: &[u8]) -> Result<Self, Utf8Error> {
let s = std::str::from_utf8(b)?;
Ok(CheetahString::from_slice(s))
}
#[inline]
pub fn from_arc_vec(s: Arc<Vec<u8>>) -> Self {
CheetahString {
inner: InnerString::ArcVecString(s),
}
}
#[inline]
pub fn from_slice(s: &str) -> Self {
if s.len() <= INLINE_CAPACITY {
let mut data = [0u8; INLINE_CAPACITY];
data[..s.len()].copy_from_slice(s.as_bytes());
CheetahString {
inner: InnerString::Inline {
len: s.len() as u8,
data,
},
}
} else {
CheetahString {
inner: InnerString::ArcString(Arc::new(s.to_owned())),
}
}
}
#[inline]
pub fn from_string(s: String) -> Self {
if s.len() <= INLINE_CAPACITY {
let mut data = [0u8; INLINE_CAPACITY];
data[..s.len()].copy_from_slice(s.as_bytes());
CheetahString {
inner: InnerString::Inline {
len: s.len() as u8,
data,
},
}
} else {
let arc_str: Arc<str> = s.into_boxed_str().into();
CheetahString {
inner: InnerString::ArcStr(arc_str),
}
}
}
#[inline]
pub fn from_arc_string(s: Arc<String>) -> Self {
CheetahString {
inner: InnerString::ArcString(s),
}
}
#[inline]
#[cfg(feature = "bytes")]
pub fn from_bytes(b: bytes::Bytes) -> Self {
CheetahString {
inner: InnerString::Bytes(b),
}
}
#[inline]
pub fn as_str(&self) -> &str {
match &self.inner {
InnerString::Inline { len, data } => {
unsafe { std::str::from_utf8_unchecked(&data[..*len as usize]) }
}
InnerString::StaticStr(s) => s,
InnerString::ArcStr(s) => s.as_ref(),
InnerString::ArcString(s) => s.as_str(),
InnerString::ArcVecString(s) => {
unsafe { std::str::from_utf8_unchecked(s.as_ref()) }
}
#[cfg(feature = "bytes")]
InnerString::Bytes(b) => {
unsafe { std::str::from_utf8_unchecked(b.as_ref()) }
}
}
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
match &self.inner {
InnerString::Inline { len, data } => &data[..*len as usize],
InnerString::StaticStr(s) => s.as_bytes(),
InnerString::ArcStr(s) => s.as_bytes(),
InnerString::ArcString(s) => s.as_bytes(),
InnerString::ArcVecString(s) => s.as_ref(),
#[cfg(feature = "bytes")]
InnerString::Bytes(b) => b.as_ref(),
}
}
#[inline]
pub fn len(&self) -> usize {
match &self.inner {
InnerString::Inline { len, .. } => *len as usize,
InnerString::StaticStr(s) => s.len(),
InnerString::ArcStr(s) => s.len(),
InnerString::ArcString(s) => s.len(),
InnerString::ArcVecString(s) => s.len(),
#[cfg(feature = "bytes")]
InnerString::Bytes(b) => b.len(),
}
}
#[inline]
pub fn is_empty(&self) -> bool {
match &self.inner {
InnerString::Inline { len, .. } => *len == 0,
InnerString::StaticStr(s) => s.is_empty(),
InnerString::ArcStr(s) => s.is_empty(),
InnerString::ArcString(s) => s.is_empty(),
InnerString::ArcVecString(s) => s.is_empty(),
#[cfg(feature = "bytes")]
InnerString::Bytes(b) => b.is_empty(),
}
}
#[inline]
pub fn starts_with<P: StrPattern>(&self, pat: P) -> bool {
match pat.as_str_pattern() {
StrPatternImpl::Char(c) => self.as_str().starts_with(c),
StrPatternImpl::Str(s) => {
#[cfg(all(feature = "simd", target_arch = "x86_64"))]
{
crate::simd::starts_with_bytes(self.as_bytes(), s.as_bytes())
}
#[cfg(not(all(feature = "simd", target_arch = "x86_64")))]
{
self.as_str().starts_with(s)
}
}
}
}
#[inline]
pub fn starts_with_char(&self, pat: char) -> bool {
self.as_str().starts_with(pat)
}
#[inline]
pub fn ends_with<P: StrPattern>(&self, pat: P) -> bool {
match pat.as_str_pattern() {
StrPatternImpl::Char(c) => self.as_str().ends_with(c),
StrPatternImpl::Str(s) => {
#[cfg(all(feature = "simd", target_arch = "x86_64"))]
{
crate::simd::ends_with_bytes(self.as_bytes(), s.as_bytes())
}
#[cfg(not(all(feature = "simd", target_arch = "x86_64")))]
{
self.as_str().ends_with(s)
}
}
}
}
#[inline]
pub fn ends_with_char(&self, pat: char) -> bool {
self.as_str().ends_with(pat)
}
#[inline]
pub fn contains<P: StrPattern>(&self, pat: P) -> bool {
match pat.as_str_pattern() {
StrPatternImpl::Char(c) => self.as_str().contains(c),
StrPatternImpl::Str(s) => {
#[cfg(all(feature = "simd", target_arch = "x86_64"))]
{
crate::simd::find_bytes(self.as_bytes(), s.as_bytes()).is_some()
}
#[cfg(not(all(feature = "simd", target_arch = "x86_64")))]
{
self.as_str().contains(s)
}
}
}
}
#[inline]
pub fn contains_char(&self, pat: char) -> bool {
self.as_str().contains(pat)
}
#[inline]
pub fn find<P: AsRef<str>>(&self, pat: P) -> Option<usize> {
let pat = pat.as_ref();
#[cfg(all(feature = "simd", target_arch = "x86_64"))]
{
crate::simd::find_bytes(self.as_bytes(), pat.as_bytes())
}
#[cfg(not(all(feature = "simd", target_arch = "x86_64")))]
{
self.as_str().find(pat)
}
}
#[inline]
pub fn rfind<P: AsRef<str>>(&self, pat: P) -> Option<usize> {
self.as_str().rfind(pat.as_ref())
}
#[inline]
pub fn trim(&self) -> &str {
self.as_str().trim()
}
#[inline]
pub fn trim_start(&self) -> &str {
self.as_str().trim_start()
}
#[inline]
pub fn trim_end(&self) -> &str {
self.as_str().trim_end()
}
#[inline]
pub fn split<'a, P>(&'a self, pat: P) -> SplitWrapper<'a>
where
P: SplitPattern<'a>,
{
pat.split_str(self.as_str())
}
#[inline]
pub fn lines(&self) -> impl Iterator<Item = &str> {
self.as_str().lines()
}
#[inline]
pub fn chars(&self) -> std::str::Chars<'_> {
self.as_str().chars()
}
#[inline]
pub fn to_uppercase(&self) -> CheetahString {
CheetahString::from_string(self.as_str().to_uppercase())
}
#[inline]
pub fn to_lowercase(&self) -> CheetahString {
CheetahString::from_string(self.as_str().to_lowercase())
}
#[inline]
pub fn replace<P: AsRef<str>>(&self, from: P, to: &str) -> CheetahString {
CheetahString::from_string(self.as_str().replace(from.as_ref(), to))
}
#[inline]
pub fn replacen<P: AsRef<str>>(&self, from: P, to: &str, count: usize) -> CheetahString {
CheetahString::from_string(self.as_str().replacen(from.as_ref(), to, count))
}
#[inline]
pub fn substring(&self, start: usize, end: usize) -> CheetahString {
CheetahString::from_slice(&self.as_str()[start..end])
}
#[inline]
pub fn repeat(&self, n: usize) -> CheetahString {
CheetahString::from_string(self.as_str().repeat(n))
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
if capacity <= INLINE_CAPACITY {
CheetahString::empty()
} else {
CheetahString::from_string(String::with_capacity(capacity))
}
}
#[inline]
pub fn push_str(&mut self, string: &str) {
*self += string;
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
let new_len = self.len() + additional;
if new_len <= INLINE_CAPACITY {
return;
}
match &mut self.inner {
InnerString::Inline { .. } => {
let mut s = String::with_capacity(new_len);
s.push_str(self.as_str());
*self = CheetahString {
inner: InnerString::ArcString(Arc::new(s)),
};
}
InnerString::ArcString(arc) if Arc::strong_count(arc) == 1 => {
if let Some(s) = Arc::get_mut(arc) {
s.reserve(additional);
}
}
InnerString::StaticStr(_) | InnerString::ArcStr(_) => {
let mut s = String::with_capacity(new_len);
s.push_str(self.as_str());
*self = CheetahString {
inner: InnerString::ArcString(Arc::new(s)),
};
}
_ => {
if Arc::strong_count(match &self.inner {
InnerString::ArcString(arc) => arc,
_ => return,
}) > 1
{
let mut s = String::with_capacity(new_len);
s.push_str(self.as_str());
*self = CheetahString {
inner: InnerString::ArcString(Arc::new(s)),
};
}
}
}
}
}
impl PartialEq for CheetahString {
#[inline]
fn eq(&self, other: &Self) -> bool {
#[cfg(all(feature = "simd", target_arch = "x86_64"))]
{
crate::simd::eq_bytes(self.as_bytes(), other.as_bytes())
}
#[cfg(not(all(feature = "simd", target_arch = "x86_64")))]
{
self.as_str() == other.as_str()
}
}
}
impl PartialEq<str> for CheetahString {
#[inline]
fn eq(&self, other: &str) -> bool {
#[cfg(all(feature = "simd", target_arch = "x86_64"))]
{
crate::simd::eq_bytes(self.as_bytes(), other.as_bytes())
}
#[cfg(not(all(feature = "simd", target_arch = "x86_64")))]
{
self.as_str() == other
}
}
}
impl PartialEq<String> for CheetahString {
#[inline]
fn eq(&self, other: &String) -> bool {
#[cfg(all(feature = "simd", target_arch = "x86_64"))]
{
crate::simd::eq_bytes(self.as_bytes(), other.as_bytes())
}
#[cfg(not(all(feature = "simd", target_arch = "x86_64")))]
{
self.as_str() == other.as_str()
}
}
}
impl PartialEq<Vec<u8>> for CheetahString {
#[inline]
fn eq(&self, other: &Vec<u8>) -> bool {
self.as_bytes() == other.as_slice()
}
}
impl<'a> PartialEq<&'a str> for CheetahString {
#[inline]
fn eq(&self, other: &&'a str) -> bool {
self.as_str() == *other
}
}
impl PartialEq<CheetahString> for str {
#[inline]
fn eq(&self, other: &CheetahString) -> bool {
self == other.as_str()
}
}
impl PartialEq<CheetahString> for String {
#[inline]
fn eq(&self, other: &CheetahString) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialEq<CheetahString> for &str {
#[inline]
fn eq(&self, other: &CheetahString) -> bool {
*self == other.as_str()
}
}
impl Eq for CheetahString {}
impl PartialOrd for CheetahString {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for CheetahString {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.as_str().cmp(other.as_str())
}
}
impl Hash for CheetahString {
#[inline]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.as_str().hash(state);
}
}
impl Display for CheetahString {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.as_str().fmt(f)
}
}
impl std::fmt::Debug for CheetahString {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
fmt::Debug::fmt(self.as_str(), f)
}
}
impl Borrow<str> for CheetahString {
#[inline]
fn borrow(&self) -> &str {
self.as_str()
}
}
impl std::ops::Add<&str> for CheetahString {
type Output = CheetahString;
#[inline]
fn add(self, rhs: &str) -> Self::Output {
let total_len = self.len() + rhs.len();
if total_len <= INLINE_CAPACITY {
let mut data = [0u8; INLINE_CAPACITY];
let self_bytes = self.as_bytes();
data[..self_bytes.len()].copy_from_slice(self_bytes);
data[self_bytes.len()..total_len].copy_from_slice(rhs.as_bytes());
return CheetahString {
inner: InnerString::Inline {
len: total_len as u8,
data,
},
};
}
let mut result = String::with_capacity(total_len);
result.push_str(self.as_str());
result.push_str(rhs);
CheetahString::from_string(result)
}
}
impl std::ops::Add<&CheetahString> for CheetahString {
type Output = CheetahString;
#[inline]
fn add(self, rhs: &CheetahString) -> Self::Output {
let total_len = self.len() + rhs.len();
if total_len <= INLINE_CAPACITY {
let mut data = [0u8; INLINE_CAPACITY];
let self_bytes = self.as_bytes();
data[..self_bytes.len()].copy_from_slice(self_bytes);
data[self_bytes.len()..total_len].copy_from_slice(rhs.as_bytes());
return CheetahString {
inner: InnerString::Inline {
len: total_len as u8,
data,
},
};
}
let mut result = String::with_capacity(total_len);
result.push_str(self.as_str());
result.push_str(rhs.as_str());
CheetahString::from_string(result)
}
}
impl std::ops::Add<String> for CheetahString {
type Output = CheetahString;
#[inline]
fn add(self, rhs: String) -> Self::Output {
let total_len = self.len() + rhs.len();
if total_len <= INLINE_CAPACITY {
let mut data = [0u8; INLINE_CAPACITY];
let self_bytes = self.as_bytes();
data[..self_bytes.len()].copy_from_slice(self_bytes);
data[self_bytes.len()..total_len].copy_from_slice(rhs.as_bytes());
return CheetahString {
inner: InnerString::Inline {
len: total_len as u8,
data,
},
};
}
let mut result = String::with_capacity(total_len);
result.push_str(self.as_str());
result.push_str(&rhs);
CheetahString::from_string(result)
}
}
impl std::ops::AddAssign<&str> for CheetahString {
#[inline]
fn add_assign(&mut self, rhs: &str) {
let total_len = self.len() + rhs.len();
match &mut self.inner {
InnerString::Inline { len, data } if total_len <= INLINE_CAPACITY => {
data[*len as usize..total_len].copy_from_slice(rhs.as_bytes());
*len = total_len as u8;
return;
}
InnerString::ArcString(arc) if Arc::strong_count(arc) == 1 => {
if let Some(s) = Arc::get_mut(arc) {
s.push_str(rhs);
return;
}
}
_ => {}
}
let mut result = String::with_capacity(total_len);
result.push_str(self.as_str());
result.push_str(rhs);
*self = CheetahString::from_string(result);
}
}
impl std::ops::AddAssign<&CheetahString> for CheetahString {
#[inline]
fn add_assign(&mut self, rhs: &CheetahString) {
let total_len = self.len() + rhs.len();
match &mut self.inner {
InnerString::Inline { len, data } if total_len <= INLINE_CAPACITY => {
data[*len as usize..total_len].copy_from_slice(rhs.as_bytes());
*len = total_len as u8;
return;
}
InnerString::ArcString(arc) if Arc::strong_count(arc) == 1 => {
if let Some(s) = Arc::get_mut(arc) {
s.push_str(rhs.as_str());
return;
}
}
_ => {}
}
let mut result = String::with_capacity(total_len);
result.push_str(self.as_str());
result.push_str(rhs.as_str());
*self = CheetahString::from_string(result);
}
}
const INLINE_CAPACITY: usize = 23;
#[derive(Clone)]
pub(super) enum InnerString {
Inline {
len: u8,
data: [u8; INLINE_CAPACITY],
},
StaticStr(&'static str),
ArcStr(Arc<str>),
ArcString(Arc<String>),
ArcVecString(Arc<Vec<u8>>),
#[cfg(feature = "bytes")]
Bytes(bytes::Bytes),
}
mod private {
pub trait Sealed {}
impl Sealed for char {}
impl Sealed for &str {}
impl Sealed for &String {}
pub trait SplitSealed {}
impl SplitSealed for char {}
impl SplitSealed for &str {}
}
pub trait StrPattern: private::Sealed {
#[doc(hidden)]
fn as_str_pattern(&self) -> StrPatternImpl<'_>;
}
#[doc(hidden)]
pub enum StrPatternImpl<'a> {
Char(char),
Str(&'a str),
}
impl StrPattern for char {
fn as_str_pattern(&self) -> StrPatternImpl<'_> {
StrPatternImpl::Char(*self)
}
}
impl StrPattern for &str {
fn as_str_pattern(&self) -> StrPatternImpl<'_> {
StrPatternImpl::Str(self)
}
}
impl StrPattern for &String {
fn as_str_pattern(&self) -> StrPatternImpl<'_> {
StrPatternImpl::Str(self.as_str())
}
}
pub trait SplitPattern<'a>: private::SplitSealed {
#[doc(hidden)]
fn split_str(self, s: &'a str) -> SplitWrapper<'a>;
}
impl SplitPattern<'_> for char {
fn split_str(self, s: &str) -> SplitWrapper<'_> {
SplitWrapper::Char(s.split(self))
}
}
impl<'a> SplitPattern<'a> for &'a str {
fn split_str(self, s: &'a str) -> SplitWrapper<'a> {
let empty_pattern_state = if self.is_empty() {
Some(EmptyPatternState {
chars: s.char_indices(),
original: s,
started: false,
})
} else {
None
};
SplitWrapper::Str(SplitStr {
string: s,
pattern: self,
finished: false,
empty_pattern_state,
})
}
}
pub struct SplitStr<'a> {
string: &'a str,
pattern: &'a str,
finished: bool,
empty_pattern_state: Option<EmptyPatternState<'a>>,
}
#[derive(Clone)]
struct EmptyPatternState<'a> {
chars: std::str::CharIndices<'a>,
original: &'a str,
started: bool,
}
impl<'a> Iterator for SplitStr<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
if self.finished {
return None;
}
if self.pattern.is_empty() {
if let Some(ref mut state) = self.empty_pattern_state {
if !state.started {
state.started = true;
return Some("");
}
match state.chars.next() {
Some((pos, ch)) => {
let char_end = pos + ch.len_utf8();
let result = &state.original[pos..char_end];
Some(result)
}
None => {
self.finished = true;
Some("")
}
}
} else {
unreachable!("empty_pattern_state should be Some for empty pattern")
}
} else {
match self.string.find(self.pattern) {
Some(pos) => {
let result = &self.string[..pos];
self.string = &self.string[pos + self.pattern.len()..];
Some(result)
}
None => {
self.finished = true;
Some(self.string)
}
}
}
}
}
pub enum SplitWrapper<'a> {
#[doc(hidden)]
Char(std::str::Split<'a, char>),
#[doc(hidden)]
Str(SplitStr<'a>),
}
impl<'a> Iterator for SplitWrapper<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
match self {
SplitWrapper::Char(iter) => iter.next(),
SplitWrapper::Str(iter) => iter.next(),
}
}
}
impl<'a> DoubleEndedIterator for SplitWrapper<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
match self {
SplitWrapper::Char(iter) => iter.next_back(),
SplitWrapper::Str(_) => {
panic!("split with string pattern does not support reverse iteration")
}
}
}
}