2021-11-05 22:32:43 +00:00
|
|
|
use std::borrow::{Borrow, Cow};
|
2021-08-28 14:40:14 +00:00
|
|
|
use std::fmt::{self, Write};
|
|
|
|
use std::hash::Hasher;
|
|
|
|
use std::slice::Iter as SliceIter;
|
|
|
|
|
2021-09-21 16:28:52 +00:00
|
|
|
use super::pattern::{SearchStep, Searcher};
|
2021-11-05 22:32:43 +00:00
|
|
|
use super::{utils, Pattern, Units, WStr, WString};
|
2021-08-28 14:40:14 +00:00
|
|
|
|
|
|
|
pub struct Iter<'a> {
|
|
|
|
inner: Units<SliceIter<'a, u8>, SliceIter<'a, u16>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Iterator for Iter<'a> {
|
|
|
|
type Item = u16;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
match &mut self.inner {
|
|
|
|
Units::Bytes(it) => it.next().map(|c| *c as u16),
|
|
|
|
Units::Wide(it) => it.next().copied(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-16 23:53:17 +00:00
|
|
|
impl<'a> DoubleEndedIterator for Iter<'a> {
|
|
|
|
#[inline]
|
|
|
|
fn next_back(&mut self) -> Option<Self::Item> {
|
|
|
|
match &mut self.inner {
|
|
|
|
Units::Bytes(it) => it.next_back().map(|c| *c as u16),
|
|
|
|
Units::Wide(it) => it.next_back().copied(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-04 23:27:13 +00:00
|
|
|
pub type Chars<'a> = std::char::DecodeUtf16<Iter<'a>>;
|
|
|
|
|
|
|
|
pub struct CharIndices<'a> {
|
|
|
|
chars: Chars<'a>,
|
|
|
|
start: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Iterator for CharIndices<'a> {
|
|
|
|
type Item = (usize, Result<char, std::char::DecodeUtf16Error>);
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
let res = (self.start, self.chars.next()?);
|
|
|
|
|
|
|
|
let in_bmp = match &res.1 {
|
|
|
|
Ok(c) => u32::from(*c) <= u16::MAX.into(),
|
|
|
|
Err(_) => false,
|
|
|
|
};
|
|
|
|
|
|
|
|
self.start += if in_bmp { 1 } else { 2 };
|
|
|
|
Some(res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-28 14:40:14 +00:00
|
|
|
#[inline]
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_iter(s: &WStr) -> Iter<'_> {
|
2021-08-28 14:40:14 +00:00
|
|
|
let inner = match s.units() {
|
|
|
|
Units::Bytes(us) => Units::Bytes(us.iter()),
|
|
|
|
Units::Wide(us) => Units::Wide(us.iter()),
|
|
|
|
};
|
|
|
|
Iter { inner }
|
|
|
|
}
|
|
|
|
|
2021-10-04 23:27:13 +00:00
|
|
|
#[inline]
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_char_indices(s: &WStr) -> CharIndices<'_> {
|
2021-10-04 23:27:13 +00:00
|
|
|
CharIndices {
|
|
|
|
chars: s.chars(),
|
|
|
|
start: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_fmt(s: &WStr, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2021-09-20 21:56:17 +00:00
|
|
|
let utf8 = WStrToUtf8::new(s);
|
|
|
|
f.write_str(utf8.head)?;
|
2021-10-04 23:27:13 +00:00
|
|
|
utf8.tail
|
|
|
|
.chars()
|
2021-08-28 14:40:14 +00:00
|
|
|
.map(|c| c.unwrap_or(char::REPLACEMENT_CHARACTER))
|
|
|
|
.try_for_each(|c| f.write_char(c))
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_debug_fmt(s: &WStr, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2021-08-28 14:40:14 +00:00
|
|
|
f.write_char('"')?;
|
|
|
|
|
|
|
|
for c in std::char::decode_utf16(s.iter()) {
|
|
|
|
match c {
|
|
|
|
Ok(c) => c.escape_debug().try_for_each(|c| f.write_char(c))?,
|
|
|
|
Err(err) => write!(f, "\\u{{{:x}}}", err.unpaired_surrogate())?,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f.write_char('"')
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_eq(left: &WStr, right: &WStr) -> bool {
|
2021-08-28 14:40:14 +00:00
|
|
|
let (bytes, wide) = match (left.units(), right.units()) {
|
|
|
|
(Units::Bytes(a), Units::Bytes(b)) => return a == b,
|
|
|
|
(Units::Wide(a), Units::Wide(b)) => return a == b,
|
|
|
|
(Units::Bytes(a), Units::Wide(b)) => (a, b),
|
|
|
|
(Units::Wide(a), Units::Bytes(b)) => (b, a),
|
|
|
|
};
|
|
|
|
|
|
|
|
if bytes.len() != wide.len() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
(0..bytes.len()).all(|i| {
|
|
|
|
// SAFETY: Both slices have the same length.
|
|
|
|
unsafe { *bytes.get_unchecked(i) as u16 == *wide.get_unchecked(i) }
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_eq_ignore_case(left: &WStr, right: &WStr) -> bool {
|
2021-09-16 19:10:51 +00:00
|
|
|
let left = left.iter().map(utils::swf_to_lowercase);
|
|
|
|
let right = right.iter().map(utils::swf_to_lowercase);
|
|
|
|
left.eq(right)
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_cmp(left: &WStr, right: &WStr) -> std::cmp::Ordering {
|
2021-08-28 14:40:14 +00:00
|
|
|
let (bytes, wide, rev) = match (left.units(), right.units()) {
|
|
|
|
(Units::Bytes(a), Units::Bytes(b)) => return a.cmp(b),
|
|
|
|
(Units::Wide(a), Units::Wide(b)) => return a.cmp(b),
|
|
|
|
(Units::Bytes(a), Units::Wide(b)) => (a, b, false),
|
|
|
|
(Units::Wide(a), Units::Bytes(b)) => (b, a, true),
|
|
|
|
};
|
|
|
|
|
|
|
|
let bytes = bytes.iter().map(|c| *c as u16);
|
|
|
|
let wide = wide.iter().copied();
|
|
|
|
let cmp = bytes.cmp(wide);
|
|
|
|
if rev {
|
|
|
|
cmp.reverse()
|
|
|
|
} else {
|
|
|
|
cmp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_cmp_ignore_case(left: &WStr, right: &WStr) -> std::cmp::Ordering {
|
2021-09-16 23:53:17 +00:00
|
|
|
let left = left.iter().map(utils::swf_to_lowercase);
|
|
|
|
let right = right.iter().map(utils::swf_to_lowercase);
|
|
|
|
left.cmp(right)
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_hash<H: Hasher>(s: &WStr, state: &mut H) {
|
2021-08-28 14:40:14 +00:00
|
|
|
match s.units() {
|
2021-11-27 20:17:52 +00:00
|
|
|
Units::Bytes(us) => state.write(us),
|
2021-11-27 19:48:51 +00:00
|
|
|
Units::Wide(us) => us.iter().for_each(|u| {
|
|
|
|
if *u <= 0xFF {
|
|
|
|
state.write_u8(*u as u8)
|
|
|
|
} else {
|
|
|
|
state.write_u16(*u)
|
|
|
|
}
|
|
|
|
}),
|
2021-08-28 14:40:14 +00:00
|
|
|
}
|
2021-11-05 22:32:43 +00:00
|
|
|
state.write_u8(0xff);
|
2021-08-28 14:40:14 +00:00
|
|
|
}
|
2021-09-15 09:59:43 +00:00
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_offset_in(s: &WStr, other: &WStr) -> Option<usize> {
|
2021-10-04 23:27:13 +00:00
|
|
|
match (s.units(), other.units()) {
|
|
|
|
(Units::Bytes(a), Units::Bytes(b)) => {
|
|
|
|
(a.as_ptr() as usize).checked_sub(b.as_ptr() as usize)
|
|
|
|
}
|
|
|
|
(Units::Wide(a), Units::Wide(b)) => (a.as_ptr() as usize)
|
|
|
|
.checked_sub(b.as_ptr() as usize)
|
|
|
|
.map(|n| n / std::mem::size_of::<u16>()),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
fn map_latin1_chars(s: &WStr, mut map: impl FnMut(u8) -> u8) -> WString {
|
2021-10-02 01:11:10 +00:00
|
|
|
match s.units() {
|
|
|
|
Units::Bytes(us) => {
|
|
|
|
let us: Vec<u8> = us.iter().map(|c| map(*c)).collect();
|
|
|
|
WString::from_buf(us)
|
|
|
|
}
|
|
|
|
Units::Wide(us) => {
|
|
|
|
let us: Vec<u16> = us
|
|
|
|
.iter()
|
|
|
|
.map(|c| match u8::try_from(*c) {
|
|
|
|
Ok(c) => map(c).into(),
|
|
|
|
Err(_) => *c,
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
WString::from_buf(us)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_to_ascii_lowercase(s: &WStr) -> WString {
|
2021-10-02 01:11:10 +00:00
|
|
|
map_latin1_chars(s, |c| c.to_ascii_lowercase())
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_is_latin1(s: &WStr) -> bool {
|
2021-09-17 19:12:11 +00:00
|
|
|
match s.units() {
|
|
|
|
Units::Bytes(_) => true,
|
|
|
|
Units::Wide(us) => us.iter().all(|c| *c <= u16::from(u8::MAX)),
|
|
|
|
}
|
2021-09-15 09:59:43 +00:00
|
|
|
}
|
2021-10-02 22:28:32 +00:00
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_join<E: Borrow<WStr>>(elems: &[E], sep: &WStr) -> WString {
|
|
|
|
fn join_inner<T, E, F>(total_len: usize, elems: &[E], sep: &WStr, mut extend: F) -> Vec<T>
|
2021-10-02 22:28:32 +00:00
|
|
|
where
|
2021-11-05 22:32:43 +00:00
|
|
|
E: Borrow<WStr>,
|
|
|
|
F: FnMut(&mut Vec<T>, &WStr),
|
2021-10-02 22:28:32 +00:00
|
|
|
{
|
|
|
|
let mut buf = Vec::with_capacity(total_len);
|
|
|
|
extend(&mut buf, elems[0].borrow());
|
|
|
|
for e in &elems[1..] {
|
|
|
|
extend(&mut buf, sep);
|
|
|
|
extend(&mut buf, e.borrow());
|
|
|
|
}
|
|
|
|
buf
|
|
|
|
}
|
|
|
|
|
|
|
|
if elems.is_empty() {
|
|
|
|
return WString::default();
|
|
|
|
}
|
|
|
|
|
|
|
|
let (len, is_latin1) = elems.iter().fold(
|
|
|
|
(sep.len() * elems.len().saturating_sub(1), sep.is_latin1()),
|
|
|
|
|(len, is_latin1), e| {
|
|
|
|
let e = e.borrow();
|
|
|
|
(len + e.len(), is_latin1 && e.is_latin1())
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
if is_latin1 {
|
|
|
|
let buf = join_inner(len, elems, sep, |buf: &mut Vec<u8>, e| match e.units() {
|
|
|
|
Units::Bytes(us) => buf.extend_from_slice(us),
|
|
|
|
Units::Wide(us) => buf.extend(us.iter().map(|c| *c as u8)),
|
|
|
|
});
|
|
|
|
WString::from_buf(buf)
|
|
|
|
} else {
|
|
|
|
let buf = join_inner(len, elems, sep, |buf: &mut Vec<u16>, e| match e.units() {
|
|
|
|
Units::Bytes(us) => buf.extend(us.iter().map(|c| *c as u16)),
|
|
|
|
Units::Wide(us) => buf.extend_from_slice(us),
|
|
|
|
});
|
|
|
|
WString::from_buf(buf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_repeat(s: &WStr, count: usize) -> WString {
|
2021-10-04 23:27:13 +00:00
|
|
|
if count == 0 || s.is_empty() {
|
|
|
|
return WString::new();
|
|
|
|
}
|
|
|
|
|
|
|
|
let len = s.len().saturating_mul(count);
|
|
|
|
if len > super::MAX_STRING_LEN {
|
|
|
|
super::panic_on_invalid_length(len);
|
|
|
|
}
|
|
|
|
|
|
|
|
match (s.units(), s.is_latin1()) {
|
|
|
|
(Units::Bytes(us), _) => WString::from_buf(us.repeat(count)),
|
|
|
|
(Units::Wide(us), false) => WString::from_buf(us.repeat(count)),
|
|
|
|
(Units::Wide(us), true) => {
|
|
|
|
let mut buf = Vec::with_capacity(len);
|
|
|
|
buf.extend(us.iter().map(|c| *c as u8));
|
|
|
|
while buf.len() <= len / 2 {
|
|
|
|
buf.extend_from_within(..);
|
|
|
|
}
|
|
|
|
buf.extend_from_within(..(len - buf.len()));
|
|
|
|
WString::from_buf(buf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_replace<'a, P: Pattern<'a>>(haystack: &'a WStr, pattern: P, with: &WStr) -> WString {
|
2021-10-04 23:27:13 +00:00
|
|
|
let mut result = WString::new();
|
|
|
|
let mut prev_end = 0;
|
|
|
|
|
|
|
|
let mut searcher = pattern.into_searcher(haystack);
|
|
|
|
while let Some((start, end)) = searcher.next_match() {
|
2021-11-05 22:32:43 +00:00
|
|
|
result.push_str(&haystack[prev_end..start]);
|
2021-10-04 23:27:13 +00:00
|
|
|
result.push_str(with);
|
|
|
|
prev_end = end;
|
|
|
|
}
|
2021-11-05 22:32:43 +00:00
|
|
|
result.push_str(&haystack[prev_end..]);
|
2021-10-04 23:27:13 +00:00
|
|
|
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_find<'a, P: Pattern<'a>>(haystack: &'a WStr, pattern: P) -> Option<usize> {
|
2021-09-17 19:12:11 +00:00
|
|
|
pattern
|
|
|
|
.into_searcher(haystack)
|
|
|
|
.next_match()
|
|
|
|
.map(|(start, _)| start)
|
|
|
|
}
|
2021-09-15 09:59:43 +00:00
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_rfind<'a, P: Pattern<'a>>(haystack: &'a WStr, pattern: P) -> Option<usize> {
|
2021-09-17 19:12:11 +00:00
|
|
|
pattern
|
|
|
|
.into_searcher(haystack)
|
|
|
|
.next_match_back()
|
|
|
|
.map(|(start, _)| start)
|
2021-09-15 09:59:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_split<'a, P: Pattern<'a>>(string: &'a WStr, pattern: P) -> Split<'a, P> {
|
2021-09-15 09:59:43 +00:00
|
|
|
Split {
|
2021-09-17 19:12:11 +00:00
|
|
|
string: Some(string),
|
|
|
|
searcher: pattern.into_searcher(string),
|
|
|
|
prev_end: 0,
|
2021-09-15 09:59:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-03 00:33:19 +00:00
|
|
|
pub fn str_rsplit_once<'a, P: Pattern<'a>>(
|
2021-11-05 22:32:43 +00:00
|
|
|
string: &'a WStr,
|
2021-10-03 00:33:19 +00:00
|
|
|
pattern: P,
|
2021-11-05 22:32:43 +00:00
|
|
|
) -> Option<(&'a WStr, &'a WStr)> {
|
2021-10-03 00:33:19 +00:00
|
|
|
let (start, end) = pattern.into_searcher(string).next_match_back()?;
|
2021-11-05 22:32:43 +00:00
|
|
|
Some((&string[..start], &string[end..]))
|
2021-10-03 00:33:19 +00:00
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn starts_with<'a, P: Pattern<'a>>(string: &'a WStr, pattern: P) -> bool {
|
2021-09-21 16:28:52 +00:00
|
|
|
matches!(
|
|
|
|
pattern.into_searcher(string).next(),
|
|
|
|
SearchStep::Match(_, _)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn ends_with<'a, P: Pattern<'a>>(string: &'a WStr, pattern: P) -> bool {
|
2021-09-21 16:28:52 +00:00
|
|
|
matches!(
|
|
|
|
pattern.into_searcher(string).next_back(),
|
|
|
|
SearchStep::Match(_, _)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn strip_prefix<'a, P: Pattern<'a>>(string: &'a WStr, pattern: P) -> Option<&'a WStr> {
|
2021-09-21 16:28:52 +00:00
|
|
|
match pattern.into_searcher(string).next() {
|
2021-11-05 22:32:43 +00:00
|
|
|
SearchStep::Match(_, end) => Some(&string[end..]),
|
2021-09-21 16:28:52 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn strip_suffix<'a, P: Pattern<'a>>(string: &'a WStr, pattern: P) -> Option<&'a WStr> {
|
2021-09-21 16:28:52 +00:00
|
|
|
match pattern.into_searcher(string).next_back() {
|
2021-11-05 22:32:43 +00:00
|
|
|
SearchStep::Match(start, _) => Some(&string[..start]),
|
2021-09-21 16:28:52 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_trim_matches<'a, P: Pattern<'a>>(string: &'a WStr, pattern: P) -> &'a WStr {
|
2021-09-21 16:28:52 +00:00
|
|
|
let mut i = 0;
|
|
|
|
let mut j = 0;
|
|
|
|
let mut searcher = pattern.into_searcher(string);
|
|
|
|
if let Some((start, end)) = searcher.next_reject() {
|
|
|
|
i = start;
|
|
|
|
j = end;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some((_, end)) = searcher.next_reject_back() {
|
|
|
|
j = end;
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
&string[i..j]
|
2021-09-21 16:28:52 +00:00
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_trim_start_matches<'a, P: Pattern<'a>>(string: &'a WStr, pattern: P) -> &'a WStr {
|
2021-09-21 16:28:52 +00:00
|
|
|
let mut i = string.len();
|
|
|
|
let mut searcher = pattern.into_searcher(string);
|
|
|
|
if let Some((start, _)) = searcher.next_reject() {
|
|
|
|
i = start;
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
&string[i..]
|
2021-09-21 16:28:52 +00:00
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn str_trim_end_matches<'a, P: Pattern<'a>>(string: &'a WStr, pattern: P) -> &'a WStr {
|
2021-09-21 16:28:52 +00:00
|
|
|
let mut i = 0;
|
|
|
|
let mut searcher = pattern.into_searcher(string);
|
|
|
|
if let Some((_, end)) = searcher.next_reject_back() {
|
|
|
|
i = end;
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
&string[..i]
|
2021-09-21 16:28:52 +00:00
|
|
|
}
|
|
|
|
|
2021-09-17 19:12:11 +00:00
|
|
|
pub struct Split<'a, P: Pattern<'a>> {
|
2021-11-05 22:32:43 +00:00
|
|
|
string: Option<&'a WStr>,
|
2021-09-17 19:12:11 +00:00
|
|
|
searcher: P::Searcher,
|
|
|
|
prev_end: usize,
|
2021-09-15 09:59:43 +00:00
|
|
|
}
|
|
|
|
|
2021-09-17 19:12:11 +00:00
|
|
|
impl<'a, P: Pattern<'a>> Iterator for Split<'a, P> {
|
2021-11-05 22:32:43 +00:00
|
|
|
type Item = &'a WStr;
|
2021-09-15 09:59:43 +00:00
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
2021-09-17 19:12:11 +00:00
|
|
|
let string = self.string?;
|
2021-09-15 09:59:43 +00:00
|
|
|
|
2021-09-17 19:12:11 +00:00
|
|
|
match self.searcher.next_match() {
|
|
|
|
Some((start, end)) => {
|
|
|
|
let end = std::mem::replace(&mut self.prev_end, end);
|
2021-11-05 22:32:43 +00:00
|
|
|
Some(&string[end..start])
|
2021-09-15 09:59:43 +00:00
|
|
|
}
|
|
|
|
None => {
|
2021-09-17 19:12:11 +00:00
|
|
|
self.string = None;
|
2021-11-05 22:32:43 +00:00
|
|
|
Some(&string[self.prev_end..])
|
2021-09-15 09:59:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-09-20 21:56:17 +00:00
|
|
|
|
2021-11-05 22:32:43 +00:00
|
|
|
/// A struct for converting a `WStr` to an UTF8 `String`.
|
2021-09-20 21:56:17 +00:00
|
|
|
pub struct WStrToUtf8<'a> {
|
|
|
|
head: &'a str,
|
2021-11-05 22:32:43 +00:00
|
|
|
tail: &'a WStr,
|
2021-09-20 21:56:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> WStrToUtf8<'a> {
|
2021-11-05 22:32:43 +00:00
|
|
|
pub fn new(s: &'a WStr) -> Self {
|
2021-09-20 21:56:17 +00:00
|
|
|
let (head, tail) = match s.units() {
|
|
|
|
Units::Bytes(b) => {
|
|
|
|
let (head, tail) = utils::split_ascii_prefix_bytes(b);
|
|
|
|
(head, WStr::from_units(tail))
|
|
|
|
}
|
|
|
|
Units::Wide(_) => ("", s),
|
|
|
|
};
|
|
|
|
|
|
|
|
Self { head, tail }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn to_utf8_lossy(&self) -> Cow<'a, str> {
|
|
|
|
if self.tail.is_empty() {
|
|
|
|
Cow::Borrowed(self.head)
|
|
|
|
} else {
|
|
|
|
let mut out = String::with_capacity(self.head.len() + self.tail.len());
|
|
|
|
out.push_str(self.head);
|
|
|
|
write!(out, "{}", self.tail).unwrap();
|
|
|
|
Cow::Owned(out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn prefix(&self) -> &str {
|
|
|
|
self.head
|
|
|
|
}
|
|
|
|
}
|