rust_assembler/str/contains_str.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_str {
12 ( $string:expr; $array:expr ) => ({
13 let bytes = $string.as_bytes();
14 let bytes_len = bytes.len();
15 // The start of the pattern that has to be checked, initialized as a `u8`.
16 let mut pat_start = 0u8;
17 // It is assigned the first character of the first non empty string.
18 for slice in $array {
19 if slice != "" {
20 pat_start = slice.as_bytes()[0];
21 break
22 }
23 }
24 let array_len = $array.len();
25
26 let mut is_contained = false;
27
28 // Counter needed when there are matches, so as to keep track of how many characters have already matched.
29 let mut counter = 0;
30
31 'outer: for i in 0..bytes_len {
32 // Counter is reset.
33 counter = 0;
34 // If first character matches..
35 if pat_start == bytes[i] {
36 'inner: for ii in 0..array_len {
37 let slice = $array[ii].as_bytes();
38 let len = slice.len();
39 // If slice is empty, skip iteration. If it's last one, returns true.
40 if len == 0 { if ii == array_len - 1 {
41 is_contained = true;
42 break 'outer
43 } else {
44 continue 'inner
45 } }
46 // Avoids out of bounds index.
47 if i + len > bytes_len {
48 break 'outer
49 }
50
51 // If `slice` matches to the specified portion of `$string`.
52 if *slice == bytes[i + counter..i + counter + len] {
53 // If it's the last element in the array, returns true and breaks the loop.
54 if ii == array_len - 1 {
55 is_contained = true;
56 break 'outer
57 } else { // Else increase the number of characters that have already matched.
58 counter += len
59 }
60 } else {
61 continue 'outer
62 }
63 }
64 }
65 }
66
67 is_contained
68 });
69}