use {
alloc::vec::Vec,
core::ops::Range,
crate::Order,
};
pub fn has_all<S0, S1, I>(s: S0, sub_strs: I, order: Order) -> bool where S0: AsRef<str>, S1: AsRef<str>, I: IntoIterator<Item=S1> {
match order {
Order::Any => has_all_in_any_order(s, sub_strs),
Order::Exact => has_all_in_exact_order(s, sub_strs),
}
}
fn has_all_in_any_order<S0, S1, I>(s: S0, sub_strs: I) -> bool where S0: AsRef<str>, S1: AsRef<str>, I: IntoIterator<Item=S1> {
let s = s.as_ref();
let mut sub_strs = sub_strs.into_iter();
sub_strs.try_fold(Vec::<Range<_>>::with_capacity(sub_strs.size_hint().0.max(3)), |mut result, next| {
let next = next.as_ref();
match s.find(next) {
Some(i) => {
let next = i..i + next.len();
if result.iter().any(|r| r.contains(&next.start) || r.contains(&next.end)) {
None
} else {
result.push(next);
Some(result)
}
},
None => None,
}
}).is_some()
}
fn has_all_in_exact_order<S0, S1, I>(s: S0, sub_strs: I) -> bool where S0: AsRef<str>, S1: AsRef<str>, I: IntoIterator<Item=S1> {
let s = s.as_ref();
let mut sub_strs = sub_strs.into_iter();
sub_strs.try_fold(s, |result, next| {
let next = next.as_ref();
match result.find(next) {
Some(i) => Some(&result[i + next.len()..]),
None => None,
}
}).is_some()
}
#[test]
fn test_has_all_in_exact_order() {
for (s, sub_strs) in &[
(concat!(r#"macro_rules! code_name { () => { ""#, code_name!(), "}}"), &["macro_rules!", "code_name", crate::CODE_NAME][..]),
] {
assert_eq!(sub_strs.len(), sub_strs.iter().size_hint().0);
assert!(has_all_in_exact_order(s, sub_strs.iter()));
}
}