1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
/// Returns a `bool` saying whether the given string contains the specified pattern, expressed as an array of integers slices (e.g. `[&[20, 30], &[44, 65]]`). Avoids all heap allocations.
///
/// # Examples
///
/// ```
///
/// let bytes = &[20, 54, 115, 97, 97, 242];
/// let a = "s".as_bytes(); // 115
/// let b = "aa".as_bytes(); // 97, 97
/// assert_eq!(Some(2), find_bytes!(bytes; [a, b]));
///
#[macro_export]
macro_rules! find_bytes {
( $bytes:expr; $array:expr ) => ({
let bytes_len = $bytes.len();
// The start of the pattern that has to be checked, initialized as a `u8`.
let mut pat_start = 0;
// It is assigned the first character of the first non empty string.
for slice in $array {
if !slice.is_empty() {
pat_start = slice[0];
break
}
}
let array_len = $array.len();
let mut opt_index = None;
// Counter needed when there are matches, so as to keep track of how many characters have already matched.
let mut counter = 0;
'outer: for i in 0..bytes_len {
// Counter is reset.
counter = 0;
// If first character matches..
if pat_start == $bytes[i] {
'inner: for ii in 0..array_len {
let slice = $array[ii];
let len = slice.len();
// If slice is empty, skip iteration.
if len == 0 { continue 'inner }
// Avoids out of bounds index.
if i + len > bytes_len {
break 'outer
}
// If `slice` matches to the specified portion of `$string`.
if *slice == $bytes[i + counter..i + counter + len] {
// If it's the last element in the array, break the loop.
if ii == array_len - 1 {
opt_index = Some(i);
break 'outer
} else { // Else increase the number of characters that have already matched.
counter += len
}
} else {
continue 'outer
}
}
}
}
opt_index
});
}