use super::{
iter::{
MatchIndicesInternal, MatchesInternal, SearcherIterator, SearcherIteratorRev,
SplitInclusiveInternal, SplitInternal, SplitNInternal,
},
pattern::{Pattern, ReverseSearcher, SearchStep, Searcher, StrSearcher},
};
use std::{
borrow::{Borrow, Cow},
error::Error,
ffi::OsStr,
fmt::{Debug, Display},
hash::Hash,
ops::{Add, Deref, RangeBounds},
path::{Path, PathBuf},
rc::Rc,
str::FromStr,
sync::Arc,
};
#[doc(hidden)]
#[cfg(any(
not(feature = "stack"),
target_pointer_width = "16",
target_pointer_width = "32"
))]
#[path = "normal.rs"]
mod internal;
#[doc(hidden)]
#[cfg(not(any(
not(feature = "stack"),
target_pointer_width = "16",
target_pointer_width = "32"
)))]
#[path = "stack.rs"]
mod internal;
pub use self::internal::FastStr;
unsafe impl Sync for FastStr {}
unsafe impl Send for FastStr {}
impl FastStr {
pub fn repeat(&self, n: usize) -> Self {
if n == 1 {
self.clone()
} else {
Self::from_string(self.as_str().repeat(n))
}
}
#[inline]
pub fn to_ascii_uppercase(&self) -> Self {
Self::from_string(self.as_str().to_ascii_uppercase())
}
#[inline]
pub fn to_ascii_lowercase(&self) -> Self {
Self::from_string(self.as_str().to_ascii_lowercase())
}
#[inline]
pub fn to_uppercase(&self) -> Self {
Self::from_string(self.as_str().to_uppercase())
}
#[inline]
pub fn to_lowercase(&self) -> Self {
Self::from_string(self.as_str().to_lowercase())
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
self.as_str().as_bytes()
}
pub fn slice<R>(&self, range: R) -> Self
where
R: RangeBounds<usize>,
{
use std::ops::Bound;
self.do_sub_with(|str, wrapper| {
let len = str.len();
let start = match range.start_bound() {
Bound::Included(&n) => std::cmp::max(0, n),
Bound::Excluded(&n) => std::cmp::max(0, n + 1),
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(&n) => std::cmp::min(len, n + 1),
Bound::Excluded(&n) => std::cmp::min(len, n),
Bound::Unbounded => len,
};
wrapper(&str[start..end])
})
}
#[inline]
pub fn trim(&self) -> Self {
self.do_sub_with(|str, wrapper| wrapper(str.trim()))
}
#[inline]
pub fn trim_into(self) -> Self {
self.do_sub_into(|str| str.trim())
}
#[inline]
pub fn trim_start(&self) -> Self {
self.do_sub_with(|str, wrapper| wrapper(str.trim_start()))
}
#[inline]
pub fn trim_start_into(self) -> Self {
self.do_sub_into(|str| str.trim_start())
}
#[inline]
pub fn trim_end(&self) -> Self {
self.do_sub_with(|str, wrapper| wrapper(str.trim_end()))
}
#[inline]
pub fn trim_end_into(self) -> Self {
self.do_sub_into(|str| str.trim_end())
}
pub fn matches<'a, P: Pattern<'a> + 'a>(
&'a self,
pat: P,
) -> impl Iterator<Item = FastStr> + 'a {
self.do_sub_with(move |str, wrapper| {
SearcherIterator::new(MatchesInternal::<P>::new(pat.into_searcher(str))).map(wrapper)
})
}
pub fn match_indices<'a, P: Pattern<'a> + 'a>(
&'a self,
pat: P,
) -> impl Iterator<Item = (usize, FastStr)> + 'a {
self.do_sub_with(move |str, wrapper| {
SearcherIterator::new(MatchIndicesInternal::<P>::new(pat.into_searcher(str)))
.map(move |(i, str)| (i, wrapper(str)))
})
}
pub fn rmatches<'a, P: Pattern<'a> + 'a>(&'a self, pat: P) -> impl Iterator<Item = FastStr> + 'a
where
P::Searcher: ReverseSearcher<'a>,
{
self.do_sub_with(move |str, wrapper| {
SearcherIteratorRev::new(MatchesInternal::<P>::new(pat.into_searcher(str))).map(wrapper)
})
}
pub fn rmatch_indices<'a, P: Pattern<'a> + 'a>(
&'a self,
pat: P,
) -> impl Iterator<Item = (usize, FastStr)> + 'a
where
P::Searcher: ReverseSearcher<'a>,
{
self.do_sub_with(move |str, wrapper| {
SearcherIteratorRev::new(MatchIndicesInternal::<P>::new(pat.into_searcher(str)))
.map(move |(i, str)| (i, wrapper(str)))
})
}
pub fn replace<'a, P: Pattern<'a> + 'a, To: AsRef<str>>(&'a self, from: P, to: To) -> FastStr {
let mut result = String::with_capacity(32);
let mut last_end = 0;
let to = to.as_ref();
let str = self.as_str();
for (start, part) in
SearcherIterator::new(MatchIndicesInternal::<P>::new(from.into_searcher(str)))
{
result.push_str(unsafe { str.get_unchecked(last_end..start) });
result.push_str(to);
last_end = start + part.len();
}
result.push_str(unsafe { str.get_unchecked(last_end..str.len()) });
result.into()
}
pub fn replacen<'a, P: Pattern<'a> + 'a, To: AsRef<str>>(
&'a self,
from: P,
to: To,
count: usize,
) -> FastStr {
let mut result = String::with_capacity(32);
let mut last_end = 0;
let to = to.as_ref();
let str = self.as_str();
for (start, part) in
SearcherIterator::new(MatchIndicesInternal::<P>::new(from.into_searcher(str)))
.take(count)
{
result.push_str(unsafe { str.get_unchecked(last_end..start) });
result.push_str(to);
last_end = start + part.len();
}
result.push_str(unsafe { str.get_unchecked(last_end..str.len()) });
result.into()
}
pub fn split<'a, P: Pattern<'a> + 'a>(&'a self, pat: P) -> impl Iterator<Item = FastStr> + 'a {
self.do_sub_with(move |str, wrapper| {
SearcherIterator::new(SplitInternal::<P> {
start: 0,
end: str.len(),
matcher: pat.into_searcher(str),
allow_trailing_empty: true,
finished: false,
})
.map(wrapper)
})
}
pub fn splitn<'a, P: Pattern<'a> + 'a>(
&'a self,
n: usize,
pat: P,
) -> impl Iterator<Item = FastStr> + 'a {
self.do_sub_with(move |str, wrapper| {
SearcherIterator::new(SplitNInternal::<P> {
iter: SplitInternal {
start: 0,
end: str.len(),
matcher: pat.into_searcher(str),
allow_trailing_empty: true,
finished: false,
},
count: n,
})
.map(wrapper)
})
}
pub fn split_terminator<'a, P: Pattern<'a> + 'a>(
&'a self,
pat: P,
) -> impl Iterator<Item = FastStr> + 'a {
self.do_sub_with(move |str, wrapper| {
SearcherIterator::new(SplitInternal::<P> {
start: 0,
end: str.len(),
matcher: pat.into_searcher(str),
allow_trailing_empty: false,
finished: false,
})
.map(wrapper)
})
}
pub fn split_inclusive<'a, P: Pattern<'a> + 'a>(
&'a self,
pat: P,
) -> impl Iterator<Item = FastStr> + 'a {
self.do_sub_with(move |str, wrapper| {
SearcherIterator::new(SplitInclusiveInternal::<P>(SplitInternal {
start: 0,
end: str.len(),
matcher: pat.into_searcher(str),
allow_trailing_empty: false,
finished: false,
}))
.map(wrapper)
})
}
pub fn split_whitespace<'a>(&'a self) -> impl Iterator<Item = FastStr> + 'a {
self.split(char::is_whitespace)
.filter(|str| !str.is_empty())
}
pub fn split_ascii_whitespace<'a>(&'a self) -> impl Iterator<Item = FastStr> + 'a {
self.do_sub_with(move |str, wrapper| {
str.as_bytes()
.split(u8::is_ascii_whitespace)
.filter(|bytes| !bytes.is_empty())
.map(move |bytes| wrapper(unsafe { std::str::from_utf8_unchecked(bytes) }))
})
}
pub fn split_once<'a, P: Pattern<'a>>(&'a self, delimiter: P) -> Option<(FastStr, FastStr)> {
self.do_sub_with(move |str, wrapper| {
let (start, end) = delimiter.into_searcher(str).next_match()?;
unsafe {
Some((
wrapper(str.get_unchecked(..start)),
wrapper(str.get_unchecked(end..)),
))
}
})
}
pub fn split_at(&self, mid: usize) -> (FastStr, FastStr) {
self.do_sub_with(move |str, wrapper| {
if str.is_char_boundary(mid) {
unsafe {
(
wrapper(str.get_unchecked(0..mid)),
wrapper(str.get_unchecked(mid..str.len())),
)
}
} else {
panic!("failed to slice string");
}
})
}
pub fn rsplit<'a, P: Pattern<'a> + 'a>(&'a self, pat: P) -> impl Iterator<Item = FastStr> + 'a
where
P::Searcher: ReverseSearcher<'a>,
{
self.do_sub_with(move |str, wrapper| {
SearcherIteratorRev::new(SplitInternal::<P> {
start: 0,
end: str.len(),
matcher: pat.into_searcher(str),
allow_trailing_empty: true,
finished: false,
})
.map(wrapper)
})
}
pub fn rsplitn<'a, P: Pattern<'a> + 'a>(
&'a self,
n: usize,
pat: P,
) -> impl Iterator<Item = FastStr> + 'a
where
P::Searcher: ReverseSearcher<'a>,
{
self.do_sub_with(move |str, wrapper| {
SearcherIteratorRev::new(SplitNInternal::<P> {
iter: SplitInternal {
start: 0,
end: str.len(),
matcher: pat.into_searcher(str),
allow_trailing_empty: true,
finished: false,
},
count: n,
})
.map(wrapper)
})
}
pub fn rsplit_terminator<'a, P: Pattern<'a> + 'a>(
&'a self,
pat: P,
) -> impl Iterator<Item = FastStr> + 'a
where
P::Searcher: ReverseSearcher<'a>,
{
self.do_sub_with(move |str, wrapper| {
SearcherIteratorRev::new(SplitInternal::<P> {
start: 0,
end: str.len(),
matcher: pat.into_searcher(str),
allow_trailing_empty: false,
finished: false,
})
.map(wrapper)
})
}
pub fn rsplit_once<'a, P: Pattern<'a>>(&'a self, delimiter: P) -> Option<(FastStr, FastStr)>
where
P::Searcher: ReverseSearcher<'a>,
{
self.do_sub_with(move |str, wrapper| {
let (start, end) = delimiter.into_searcher(str).next_match_back()?;
unsafe {
Some((
wrapper(str.get_unchecked(..start)),
wrapper(str.get_unchecked(end..)),
))
}
})
}
pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<FastStr> {
self.do_sub_with(|str, wrapper| prefix.strip_prefix_of(str).map(wrapper))
}
pub fn strip_suffix<'a, P: Pattern<'a>>(&'a self, suffix: P) -> Option<FastStr>
where
P::Searcher: ReverseSearcher<'a>,
{
self.do_sub_with(|str, wrapper| suffix.strip_suffix_of(str).map(wrapper))
}
}
impl Default for FastStr {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl Default for &FastStr {
#[inline]
fn default() -> Self {
const FAST_STR_DEFAULT: &FastStr = &FastStr::new();
FAST_STR_DEFAULT
}
}
impl Deref for FastStr {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl Borrow<str> for FastStr {
#[inline]
fn borrow(&self) -> &str {
self.as_str()
}
}
impl AsRef<str> for FastStr {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl AsRef<[u8]> for FastStr {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_str().as_ref()
}
}
impl AsRef<Path> for FastStr {
#[inline]
fn as_ref(&self) -> &Path {
self.as_str().as_ref()
}
}
impl AsRef<OsStr> for FastStr {
#[inline]
fn as_ref(&self) -> &OsStr {
self.as_str().as_ref()
}
}
impl Hash for FastStr {
#[inline]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.as_str().hash(state)
}
}
impl Eq for FastStr {}
impl PartialEq for FastStr {
#[inline]
fn eq(&self, other: &Self) -> bool {
PartialEq::eq(self, other.as_str())
}
}
impl PartialEq<&FastStr> for FastStr {
#[inline]
fn eq(&self, other: &&FastStr) -> bool {
PartialEq::eq(self, *other)
}
}
impl PartialEq<str> for FastStr {
#[inline]
fn eq(&self, other: &str) -> bool {
let this = self.as_str();
std::ptr::eq(std::ptr::addr_of!(*this), std::ptr::addr_of!(*other))
|| PartialEq::eq(this, other)
}
}
impl PartialEq<FastStr> for str {
#[inline]
fn eq(&self, other: &FastStr) -> bool {
PartialEq::eq(other, self)
}
}
impl PartialEq<&str> for FastStr {
#[inline]
fn eq(&self, other: &&str) -> bool {
PartialEq::eq(self, *other)
}
}
impl PartialEq<FastStr> for &str {
#[inline]
fn eq(&self, other: &FastStr) -> bool {
PartialEq::eq(other, *self)
}
}
impl PartialEq<&FastStr> for str {
#[inline]
fn eq(&self, other: &&FastStr) -> bool {
PartialEq::eq(*other, self)
}
}
impl PartialEq<String> for FastStr {
#[inline]
fn eq(&self, other: &String) -> bool {
PartialEq::eq(self.as_str(), other.as_str())
}
}
impl PartialEq<FastStr> for String {
#[inline]
fn eq(&self, other: &FastStr) -> bool {
PartialEq::eq(other, self)
}
}
impl PartialEq<&String> for FastStr {
#[inline]
fn eq(&self, other: &&String) -> bool {
PartialEq::eq(self.as_str(), other.as_str())
}
}
impl PartialEq<FastStr> for &String {
#[inline]
fn eq(&self, other: &FastStr) -> bool {
PartialEq::eq(other, self)
}
}
impl Ord for FastStr {
#[inline]
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
let str1 = self.as_str();
let str2 = other.as_str();
if std::ptr::eq(std::ptr::addr_of!(*str1), std::ptr::addr_of!(*str2)) {
return std::cmp::Ordering::Equal;
}
Ord::cmp(str1, str2)
}
}
impl PartialOrd for FastStr {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
PartialOrd::partial_cmp(self, other.as_str())
}
}
impl PartialOrd<&FastStr> for FastStr {
#[inline]
fn partial_cmp(&self, other: &&FastStr) -> Option<std::cmp::Ordering> {
PartialOrd::partial_cmp(self, *other)
}
}
impl PartialOrd<str> for FastStr {
#[inline]
fn partial_cmp(&self, other: &str) -> Option<std::cmp::Ordering> {
let str1 = self.as_str();
let str2 = other;
if std::ptr::eq(std::ptr::addr_of!(*str1), std::ptr::addr_of!(*str2)) {
return Some(std::cmp::Ordering::Equal);
}
PartialOrd::partial_cmp(self.as_str(), other)
}
}
impl PartialOrd<FastStr> for str {
#[inline]
fn partial_cmp(&self, other: &FastStr) -> Option<std::cmp::Ordering> {
PartialOrd::partial_cmp(other, self)
}
}
impl PartialOrd<&str> for FastStr {
#[inline]
fn partial_cmp(&self, other: &&str) -> Option<std::cmp::Ordering> {
PartialOrd::partial_cmp(self.as_str(), *other)
}
}
impl PartialOrd<&FastStr> for str {
#[inline]
fn partial_cmp(&self, other: &&FastStr) -> Option<std::cmp::Ordering> {
PartialOrd::partial_cmp(*other, self)
}
}
impl PartialOrd<FastStr> for &str {
#[inline]
fn partial_cmp(&self, other: &FastStr) -> Option<std::cmp::Ordering> {
PartialOrd::partial_cmp(other, *self)
}
}
impl PartialOrd<String> for FastStr {
#[inline]
fn partial_cmp(&self, other: &String) -> Option<std::cmp::Ordering> {
PartialOrd::partial_cmp(self.as_str(), other.as_str())
}
}
impl PartialOrd<FastStr> for String {
#[inline]
fn partial_cmp(&self, other: &FastStr) -> Option<std::cmp::Ordering> {
PartialOrd::partial_cmp(other, self)
}
}
impl PartialOrd<&String> for FastStr {
#[inline]
fn partial_cmp(&self, other: &&String) -> Option<std::cmp::Ordering> {
PartialOrd::partial_cmp(self.as_str(), other.as_str())
}
}
impl PartialOrd<FastStr> for &String {
#[inline]
fn partial_cmp(&self, other: &FastStr) -> Option<std::cmp::Ordering> {
PartialOrd::partial_cmp(other, *self)
}
}
impl Debug for FastStr {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(self.as_str(), f)
}
}
impl Display for FastStr {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(self.as_str(), f)
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for FastStr {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serde::Serialize::serialize(self.as_str(), serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for FastStr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let result = <String as serde::Deserialize>::deserialize(deserializer);
match result {
Ok(ok) => Ok(Self::from_string(ok)),
Err(err) => Err(err),
}
}
}
impl FromStr for FastStr {
type Err = <String as FromStr>::Err;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
let result = FromStr::from_str(s);
match result {
Ok(ok) => Ok(Self::from_string(ok)),
Err(err) => Err(err),
}
}
}
impl TryFrom<&[u8]> for FastStr {
type Error = std::str::Utf8Error;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
std::str::from_utf8(value).map(Self::from_ref)
}
}
impl TryFrom<Vec<u8>> for FastStr {
type Error = std::string::FromUtf8Error;
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
String::from_utf8(value).map(Self::from_string)
}
}
impl From<&&str> for FastStr {
#[inline]
fn from(str: &&str) -> Self {
Self::from_ref(*str)
}
}
impl From<&'static str> for FastStr {
#[inline]
fn from(str: &'static str) -> Self {
Self::from_static(str)
}
}
impl From<&mut str> for FastStr {
#[inline]
fn from(str: &mut str) -> Self {
Self::from_ref(str)
}
}
impl From<Rc<str>> for FastStr {
#[inline]
fn from(str: Rc<str>) -> Self {
Self::from_ref(str.as_ref())
}
}
impl From<Arc<str>> for FastStr {
#[inline]
fn from(str: Arc<str>) -> Self {
Self::from_ref(str.as_ref())
}
}
impl From<Box<str>> for FastStr {
#[inline]
fn from(str: Box<str>) -> Self {
Self::from_string(str.into())
}
}
impl From<String> for FastStr {
#[inline]
fn from(str: String) -> Self {
Self::from_string(str)
}
}
impl From<&String> for FastStr {
#[inline]
fn from(str: &String) -> Self {
Self::from_ref(str)
}
}
impl From<&FastStr> for FastStr {
#[inline]
fn from(str: &FastStr) -> Self {
str.clone()
}
}
impl From<Cow<'_, str>> for FastStr {
#[inline]
fn from(str: Cow<'_, str>) -> Self {
Self::from_string(str.into_owned())
}
}
impl From<&Cow<'_, str>> for FastStr {
#[inline]
fn from(str: &Cow<'_, str>) -> Self {
Self::from_ref(str.as_ref())
}
}
impl From<Cow<'_, String>> for FastStr {
#[inline]
fn from(str: Cow<'_, String>) -> Self {
Self::from_string(str.into_owned())
}
}
impl From<&Cow<'_, String>> for FastStr {
#[inline]
fn from(str: &Cow<'_, String>) -> Self {
Self::from_ref(str.as_ref())
}
}
impl From<()> for FastStr {
#[inline]
fn from(_: ()) -> Self {
Self::new()
}
}
impl From<&()> for FastStr {
#[inline]
fn from(_: &()) -> Self {
Self::new()
}
}
impl From<bool> for FastStr {
#[inline]
fn from(b: bool) -> Self {
Self::from_static(if b { "true" } else { "false" })
}
}
impl From<&bool> for FastStr {
#[inline]
fn from(b: &bool) -> Self {
Self::from(*b)
}
}
impl From<FastStr> for String {
#[inline]
fn from(str: FastStr) -> Self {
str.into_string()
}
}
impl From<FastStr> for PathBuf {
#[inline]
fn from(str: FastStr) -> Self {
str.into_string().into()
}
}
impl From<FastStr> for Box<str> {
#[inline]
fn from(str: FastStr) -> Self {
str.into_string().into()
}
}
impl From<&FastStr> for Box<str> {
#[inline]
fn from(str: &FastStr) -> Self {
str.as_str().into()
}
}
impl From<FastStr> for Rc<str> {
#[inline]
fn from(str: FastStr) -> Self {
str.as_str().into()
}
}
impl From<&FastStr> for Rc<str> {
#[inline]
fn from(str: &FastStr) -> Self {
str.as_str().into()
}
}
impl From<FastStr> for Arc<str> {
#[inline]
fn from(str: FastStr) -> Self {
str.as_str().into()
}
}
impl From<&FastStr> for Arc<str> {
#[inline]
fn from(str: &FastStr) -> Self {
str.as_str().into()
}
}
impl From<FastStr> for Vec<u8> {
#[inline]
fn from(str: FastStr) -> Self {
str.into_string().into()
}
}
impl From<&FastStr> for Vec<u8> {
#[inline]
fn from(str: &FastStr) -> Self {
str.as_str().into()
}
}
impl From<FastStr> for Box<dyn Error + 'static> {
fn from(str: FastStr) -> Self {
str.into_string().into()
}
}
impl From<FastStr> for Box<dyn Error + Send + Sync + 'static> {
fn from(str: FastStr) -> Self {
str.into_string().into()
}
}
impl From<&FastStr> for Box<dyn Error + 'static> {
fn from(str: &FastStr) -> Self {
str.as_str().into()
}
}
impl From<&FastStr> for Box<dyn Error + Send + Sync + 'static> {
fn from(str: &FastStr) -> Self {
str.as_str().into()
}
}
impl<'a> From<FastStr> for Cow<'a, str> {
fn from(str: FastStr) -> Self {
if let Some(str) = str.static_str() {
Cow::Borrowed(str)
} else {
Cow::Owned(str.into_string())
}
}
}
impl<'a> From<&'a FastStr> for Cow<'a, str> {
#[inline]
fn from(str: &'a FastStr) -> Self {
Cow::Borrowed(str.as_str())
}
}
impl From<&FastStr> for String {
#[inline]
fn from(str: &FastStr) -> Self {
str.as_str().into()
}
}
impl<'a> From<&'a FastStr> for &'a str {
#[inline]
fn from(str: &'a FastStr) -> Self {
str.as_str()
}
}
#[cfg(target_arch = "wasm32")]
impl From<js_sys::JsString> for FastStr {
#[inline]
fn from(str: js_sys::JsString) -> Self {
Self::from_string(String::from(str))
}
}
#[cfg(target_arch = "wasm32")]
impl From<&js_sys::JsString> for FastStr {
#[inline]
fn from(str: &js_sys::JsString) -> Self {
Self::from_string(String::from(str))
}
}
#[cfg(target_arch = "wasm32")]
impl From<FastStr> for js_sys::JsString {
#[inline]
fn from(str: FastStr) -> Self {
js_sys::JsString::from(str.as_str())
}
}
#[cfg(target_arch = "wasm32")]
impl From<&FastStr> for js_sys::JsString {
#[inline]
fn from(str: &FastStr) -> Self {
js_sys::JsString::from(str.as_str())
}
}
#[cfg(target_arch = "wasm32")]
impl From<FastStr> for wasm_bindgen::JsValue {
#[inline]
fn from(str: FastStr) -> Self {
wasm_bindgen::JsValue::from_str(str.as_str())
}
}
#[cfg(target_arch = "wasm32")]
impl From<&FastStr> for wasm_bindgen::JsValue {
#[inline]
fn from(str: &FastStr) -> Self {
wasm_bindgen::JsValue::from_str(str.as_str())
}
}
impl<A> FromIterator<A> for FastStr
where
String: FromIterator<A>,
{
#[inline]
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
Self::from_string(String::from_iter(iter))
}
}
impl FromIterator<FastStr> for FastStr {
fn from_iter<T: IntoIterator<Item = FastStr>>(iter: T) -> Self {
let mut buf = String::new();
for s in iter.into_iter() {
buf += s.borrow();
}
Self::from(buf)
}
}
impl<'a> FromIterator<&'a FastStr> for FastStr {
fn from_iter<T: IntoIterator<Item = &'a FastStr>>(iter: T) -> Self {
Self::from_string(String::from_iter(iter.into_iter().map(|s| s.as_str())))
}
}
impl Add<&str> for FastStr {
type Output = FastStr;
#[inline]
fn add(self, rhs: &str) -> Self::Output {
Self::from_string(String::from(self) + rhs)
}
}
impl Add<&FastStr> for FastStr {
type Output = FastStr;
#[inline]
fn add(self, rhs: &FastStr) -> Self::Output {
Self::from_string(String::from(self) + rhs.as_str())
}
}
impl Add<FastStr> for FastStr {
type Output = FastStr;
#[inline]
fn add(self, rhs: FastStr) -> Self::Output {
Self::from_string(String::from(self) + rhs.as_str())
}
}
impl Add<String> for FastStr {
type Output = FastStr;
#[inline]
fn add(self, rhs: String) -> Self::Output {
Self::from_string(String::from(self) + rhs.as_str())
}
}
impl Add<&String> for FastStr {
type Output = FastStr;
#[inline]
fn add(self, rhs: &String) -> Self::Output {
Self::from_string(String::from(self) + rhs.as_str())
}
}
#[cfg(target_arch = "wasm32")]
impl wasm_bindgen::describe::WasmDescribe for FastStr {
#[inline]
fn describe() {
<String as wasm_bindgen::describe::WasmDescribe>::describe()
}
}
#[cfg(target_arch = "wasm32")]
impl wasm_bindgen::convert::FromWasmAbi for FastStr {
type Abi = <String as wasm_bindgen::convert::FromWasmAbi>::Abi;
#[inline]
unsafe fn from_abi(js: Self::Abi) -> Self {
Self::from(<String as wasm_bindgen::convert::FromWasmAbi>::from_abi(js))
}
}
#[cfg(target_arch = "wasm32")]
impl wasm_bindgen::convert::IntoWasmAbi for FastStr {
type Abi = <String as wasm_bindgen::convert::IntoWasmAbi>::Abi;
#[inline]
fn into_abi(self) -> Self::Abi {
<String as wasm_bindgen::convert::IntoWasmAbi>::into_abi(self.into_string())
}
}
#[cfg(target_arch = "wasm32")]
impl<'a> wasm_bindgen::convert::IntoWasmAbi for &'a FastStr {
type Abi = <&'a str as wasm_bindgen::convert::IntoWasmAbi>::Abi;
#[inline]
fn into_abi(self) -> Self::Abi {
<&'a str as wasm_bindgen::convert::IntoWasmAbi>::into_abi(self.as_str())
}
}
#[cfg(target_arch = "wasm32")]
impl wasm_bindgen::convert::OptionFromWasmAbi for FastStr {
#[inline]
fn is_none(abi: &Self::Abi) -> bool {
<String as wasm_bindgen::convert::OptionFromWasmAbi>::is_none(abi)
}
}
#[cfg(target_arch = "wasm32")]
impl wasm_bindgen::convert::OptionIntoWasmAbi for FastStr {
#[inline]
fn none() -> Self::Abi {
<String as wasm_bindgen::convert::OptionIntoWasmAbi>::none()
}
}
#[cfg(feature = "actix-web")]
impl actix_web::Responder for FastStr {
type Body = <String as actix_web::Responder>::Body;
#[inline]
fn respond_to(self, req: &actix_web::HttpRequest) -> actix_web::HttpResponse<Self::Body> {
<String as actix_web::Responder>::respond_to(self.into(), req)
}
}
#[cfg(feature = "actix-web")]
impl actix_web::Responder for &FastStr {
type Body = <String as actix_web::Responder>::Body;
#[inline]
fn respond_to(self, req: &actix_web::HttpRequest) -> actix_web::HttpResponse<Self::Body> {
<String as actix_web::Responder>::respond_to(self.into(), req)
}
}
#[cfg(feature = "arbitrary")]
impl<'a> arbitrary::Arbitrary<'a> for FastStr {
#[inline]
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
<String as arbitrary::Arbitrary<'a>>::arbitrary(u).map(Self::from)
}
#[inline]
fn arbitrary_take_rest(u: arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
<String as arbitrary::Arbitrary<'a>>::arbitrary_take_rest(u).map(Self::from)
}
#[inline]
fn size_hint(depth: usize) -> (usize, Option<usize>) {
<String as arbitrary::Arbitrary<'a>>::size_hint(depth)
}
}
#[cfg(feature = "diffus")]
impl diffus::Same for FastStr {
fn same(&self, other: &Self) -> bool {
self == other
}
}
#[cfg(feature = "diffus")]
impl<'a> diffus::Diffable<'a> for FastStr {
type Diff = (&'a Self, &'a Self);
fn diff(&'a self, other: &'a Self) -> diffus::edit::Edit<'a, Self> {
if self == other {
diffus::edit::Edit::Copy(self)
} else {
diffus::edit::Edit::Change((self, other))
}
}
}
impl<'a> Pattern<'a> for &'a FastStr {
type Searcher = <&'a str as Pattern<'a>>::Searcher;
fn into_searcher(self, haystack: &'a str) -> Self::Searcher {
<&'a str as Pattern<'a>>::into_searcher(self.as_str(), haystack)
}
}
pub struct FastStrSearch<'a, 'b> {
_str: Box<FastStr>,
searcher: StrSearcher<'a, 'b>,
}
unsafe impl<'a, 'b> Searcher<'a> for FastStrSearch<'a, 'b> {
#[inline]
fn haystack(&self) -> &'a str {
self.searcher.haystack()
}
#[inline]
fn next(&mut self) -> SearchStep {
self.searcher.next()
}
}
impl<'a> Pattern<'a> for FastStr {
type Searcher = FastStrSearch<'a, 'a>;
fn into_searcher(self, haystack: &'a str) -> Self::Searcher {
let _str = Box::new(self);
let searcher = <&'a str as Pattern<'a>>::into_searcher(
unsafe { &*std::ptr::addr_of!(*_str.as_str()) },
haystack,
);
FastStrSearch { _str, searcher }
}
}