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