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-17 19:12:11 +00:00
|
|
|
use super::pattern::Searcher;
|
|
|
|
use super::{utils, Pattern, WStr, Units};
|
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-08-28 14:40:14 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn str_iter(s: WStr<'_>) -> Iter<'_> {
|
|
|
|
let inner = match s.units() {
|
|
|
|
Units::Bytes(us) => Units::Bytes(us.iter()),
|
|
|
|
Units::Wide(us) => Units::Wide(us.iter()),
|
|
|
|
};
|
|
|
|
Iter { inner }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn str_fmt(s: WStr<'_>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
std::char::decode_utf16(s.iter())
|
|
|
|
.map(|c| c.unwrap_or(char::REPLACEMENT_CHARACTER))
|
|
|
|
.try_for_each(|c| f.write_char(c))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn str_debug_fmt(s: WStr<'_>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
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('"')
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn str_eq(left: WStr<'_>, right: WStr<'_>) -> bool {
|
|
|
|
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-09-16 19:10:51 +00:00
|
|
|
pub fn str_eq_ignore_case(left: WStr<'_>, right: WStr<'_>) -> bool {
|
|
|
|
let left = left.iter().map(utils::swf_to_lowercase);
|
|
|
|
let right = right.iter().map(utils::swf_to_lowercase);
|
|
|
|
left.eq(right)
|
|
|
|
}
|
|
|
|
|
2021-08-28 14:40:14 +00:00
|
|
|
pub fn str_cmp(left: WStr<'_>, right: WStr<'_>) -> std::cmp::Ordering {
|
|
|
|
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-09-16 23:53:17 +00:00
|
|
|
pub fn str_cmp_ignore_case(left: WStr<'_>, right: WStr<'_>) -> std::cmp::Ordering {
|
|
|
|
let left = left.iter().map(utils::swf_to_lowercase);
|
|
|
|
let right = right.iter().map(utils::swf_to_lowercase);
|
|
|
|
left.cmp(right)
|
|
|
|
}
|
|
|
|
|
2021-08-28 14:40:14 +00:00
|
|
|
pub fn str_hash<H: Hasher>(s: WStr<'_>, state: &mut H) {
|
|
|
|
match s.units() {
|
|
|
|
Units::Bytes(us) => us.iter().for_each(|u| state.write_u16(u16::from(*u))),
|
|
|
|
Units::Wide(us) => us.iter().for_each(|u| state.write_u16(*u)),
|
|
|
|
}
|
|
|
|
}
|
2021-09-15 09:59:43 +00:00
|
|
|
|
2021-09-17 19:12:11 +00:00
|
|
|
pub fn str_is_latin1(s: WStr<'_>) -> bool {
|
|
|
|
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-09-17 19:12:11 +00:00
|
|
|
pub fn str_find<'a, P: Pattern<'a>>(haystack: WStr<'a>, pattern: P) -> Option<usize> {
|
|
|
|
pattern
|
|
|
|
.into_searcher(haystack)
|
|
|
|
.next_match()
|
|
|
|
.map(|(start, _)| start)
|
|
|
|
}
|
2021-09-15 09:59:43 +00:00
|
|
|
|
2021-09-17 19:12:11 +00:00
|
|
|
pub fn str_rfind<'a, P: Pattern<'a>>(haystack: WStr<'a>, pattern: P) -> Option<usize> {
|
|
|
|
pattern
|
|
|
|
.into_searcher(haystack)
|
|
|
|
.next_match_back()
|
|
|
|
.map(|(start, _)| start)
|
2021-09-15 09:59:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2021-09-17 19:12:11 +00:00
|
|
|
pub fn str_split<'a, P: Pattern<'a>>(string: WStr<'a>, 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-09-17 19:12:11 +00:00
|
|
|
pub struct Split<'a, P: Pattern<'a>> {
|
|
|
|
string: Option<WStr<'a>>,
|
|
|
|
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-09-15 09:59:43 +00:00
|
|
|
type Item = WStr<'a>;
|
|
|
|
|
|
|
|
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);
|
|
|
|
Some(string.slice(end..start))
|
2021-09-15 09:59:43 +00:00
|
|
|
}
|
|
|
|
None => {
|
2021-09-17 19:12:11 +00:00
|
|
|
self.string = None;
|
|
|
|
Some(string.slice(self.prev_end..))
|
2021-09-15 09:59:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|