#![allow(unused)]
#[doc(hidden)]
#[macro_export]
macro_rules! ok_or_continue {
( $e:expr ) => {
match $e {
Ok(value) => value,
Err(_e) => {
continue;
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! some_or_continue {
( $e:expr ) => {
match $e {
Some(value) => value,
None => continue,
}
};
}
pub struct SplitNewlines<'a> {
bytes: &'a [u8],
min_line_length: usize,
current_pos: usize, }
impl<'a> Iterator for SplitNewlines<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
if self.current_pos >= self.bytes.len() {
return None;
}
let start_pos = self.current_pos;
self.current_pos += self.min_line_length;
while let Some(&c) = self.bytes.get(self.current_pos) {
if c == b'\n' {
break;
}
self.current_pos += 1;
}
let line = &self.bytes[start_pos..self.current_pos];
self.current_pos += 1; Some(line)
}
}
pub struct CountInto<'a, I: Iterator> {
iterator: I,
count_variable: &'a mut usize,
}
impl<'a, I: Iterator> Iterator for CountInto<'a, I> {
type Item = I::Item;
fn next(&mut self) -> Option<I::Item> {
let item = self.iterator.next();
if item.is_some() {
*self.count_variable += 1;
}
item
}
}
pub fn split_newlines(bytes: &[u8], min_line_length: usize) -> SplitNewlines<'_> {
SplitNewlines {
bytes,
min_line_length,
current_pos: 0,
}
}
pub fn extract_str<'a>(string: &'a str, before: &str, after: &str) -> Option<&'a str> {
let before_index = twoway::find_str(string, before)?;
let start_index = before_index + before.len();
let end_index = start_index + twoway::find_str(&string[start_index..], after)?;
Some(&string[start_index..end_index])
}
pub fn extract_bstr<'a>(string: &'a [u8], before: &[u8], after: &[u8]) -> Option<&'a [u8]> {
let before_index = twoway::find_bytes(string, before)?;
let start_index = before_index + before.len();
let end_index = start_index + twoway::find_bytes(&string[start_index..], after)?;
Some(&string[start_index..end_index])
}
#[allow(clippy::type_complexity)]
pub fn first_and_last_and_count<I: std::iter::Iterator>(
mut iterator: I,
) -> (Option<(I::Item, I::Item)>, u64) {
let first_elem = match iterator.next() {
Some(a) => a,
None => return (None, 0),
};
let mut count = 1; let mut last_seen_elem = None;
for elem in iterator {
last_seen_elem = Some(elem);
count += 1;
}
let last_elem = match last_seen_elem {
Some(a) => a,
None => return (None, 1),
};
(Some((first_elem, last_elem)), count)
}
pub fn is_sorted<T: PartialOrd>(data: &[T]) -> bool {
data.windows(2).all(|w| w[0] <= w[1])
}
pub fn trim_bstr(bstr: &[u8]) -> &[u8] {
let start_index = match bstr.iter().position(|&c| !is_ascii_whitespace(c)) {
Some(a) => a,
None => return &[], };
let end_index = bstr.iter().rposition(|&c| !is_ascii_whitespace(c)).unwrap();
&bstr[start_index..=end_index]
}
pub fn mean<I: Iterator>(iterator: I) -> f32
where
I::Item: std::ops::Deref<Target = f32>,
{
let mut sum = 0.0;
let mut count = 0;
for value_ref in iterator {
sum += *value_ref;
count += 1;
}
sum / count as f32
}
pub fn is_ascii_whitespace(c: u8) -> bool {
c == b' ' || c == b'\t' || c == b'\n' || c == b'\r'
|| c == 0x0c || c == 0x0b }
#[allow(clippy::collapsible_if)]
pub fn longest_true_sequence(iterator: impl IntoIterator<Item = bool>) -> u32 {
let mut longest_so_far = 0;
let mut current_run = 0;
for is_true in iterator {
if is_true {
current_run += 1;
} else {
if current_run > longest_so_far {
longest_so_far = current_run;
}
current_run = 0;
}
}
if current_run > longest_so_far {
longest_so_far = current_run;
}
longest_so_far
}
pub fn is_equal_no_order_no_duplicates<T: PartialEq>(a: &[T], b: &[T]) -> bool {
a.iter().all(|a_elem| b.contains(a_elem)) && b.iter().all(|b_elem| a.contains(b_elem))
}
#[cfg(test)]
mod tests {
use super::*;
#[macro_export]
#[doc(hidden)]
macro_rules! assert_float_eq {
($left: expr, $right: expr; epsilon = $epsilon: expr) => {
let left = $left;
let right = $right;
let delta = (right - left).abs();
if delta > $epsilon {
panic!(
"assertion failed: `(left =~ right)`
left: `{:?}`
right: `{:?}`
delta: `{:?}`",
&left, &right, &delta
);
}
};
}
#[test]
fn test_split_newlines() {
let text = b"10charssss\n6chars\n10charssss\n6chars\n";
let lines: Vec<_> = split_newlines(text as &[u8], 6).collect();
assert_eq!(
lines,
vec![
b"10charssss" as &[u8],
b"6chars" as &[u8],
b"10charssss" as &[u8],
b"6chars" as &[u8]
]
);
let lines: Vec<&[u8]> = split_newlines(text as &[u8], 7).collect();
assert_eq!(
lines,
vec![
b"10charssss" as &[u8],
b"6chars\n10charssss" as &[u8],
b"6chars\n" as &[u8]
]
); }
#[test]
fn test_extract_str_and_bstr() {
for (string, before, after, expected_outcome) in [
("#TITLE:helo;", "#TITLE:", ";", Some("helo")),
("#TITLE::::#TITLE:;", "#TITLE:", ";", Some(":::#TITLE:")),
("#TITLE:helo:", "#TITLE:", ";", None),
("#TITLE helo;", "#TITLE:", ";", None),
]
.iter()
{
assert_eq!(extract_str(string, before, after), *expected_outcome);
assert_eq!(
extract_bstr(string.as_bytes(), before.as_bytes(), after.as_bytes()),
expected_outcome.map(|s| s.as_bytes())
);
}
}
#[test]
fn test_first_and_last_and_count() {
assert_eq!(
first_and_last_and_count("2357".chars()),
(Some(('2', '7')), 4)
);
assert_eq!(first_and_last_and_count("2".chars()), (None, 1));
assert_eq!(first_and_last_and_count("".chars()), (None, 0));
}
#[test]
fn test_is_sorted() {
assert_eq!(is_sorted(&[1, 2, 3, 2]), false);
assert_eq!(is_sorted(&[1, 2, 2, 3]), true);
}
#[test]
fn test_trim_bstr() {
assert_eq!(trim_bstr(b" hello world "), b"hello world");
assert_eq!(trim_bstr(b"hello world "), b"hello world");
assert_eq!(trim_bstr(b" hello world"), b"hello world");
assert_eq!(trim_bstr(b"hello world"), b"hello world");
assert_eq!(trim_bstr(b" hello world \n\n \t"), b"hello world");
}
#[test]
fn test_mean() {
assert_float_eq!(mean([0.0, 6.0, 1.0, 2.0].iter()), 2.25;
epsilon=0.0001);
assert_float_eq!(mean([0.0, 6.0, 1.0, 3.0].iter()), 2.5;
epsilon=0.0001);
assert_float_eq!(mean([-897193848.0, 69.0, 893784444.0, 211122.0, 422.0].iter()), -639558.2;
epsilon=10.0); }
#[test]
fn test_is_ascii_whitespace() {
let whitespace_chars: &[u8] = b" \t\n\r\x0c\x0b";
for char_code in 0..=255u8 {
assert_eq!(
is_ascii_whitespace(char_code),
whitespace_chars.contains(&char_code)
);
}
}
#[test]
fn test_is_equal_no_order_no_duplicates() {
assert!(is_equal_no_order_no_duplicates(b"hello", b"helo"));
assert!(is_equal_no_order_no_duplicates(b"hello", b"olleh"));
assert!(is_equal_no_order_no_duplicates(
b"llllllllllllllllllllllllllllhoehoehoehoe",
b"lheooleohohoholehloeloeoeloelohelohelehlehloeoleol"
));
assert!(!is_equal_no_order_no_duplicates(b"", b"hi"));
}
}