summaryrefslogtreecommitdiff
path: root/meap/meap-code/ch2/ch2-introducing-vec.rs
blob: 0a3cf4b8b3849c22a0c0ae0c34fbdf0a7feb1015 (plain) (blame)
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
fn main() {
  // PARAMETERS
  let context_lines = 2;
  let needle = "oo";
  let haystack = "Every face, every shop,
bedroom window, public-house, and
dark square is a picture
feverishly turned--in search of what?
It is the same with books.
What do we seek
through millions of pages?";

  // INITIALIZATION
  let mut tags: Vec<usize> = Vec::new(); // <1> `tags` holds line numbers where matches occur
  let mut ctx: Vec<Vec<(usize, String)>> = Vec::new(); // <2> `ctx` contains a vector per match to hold that match's context lines

  // PASS 1
  for (i, line) in haystack.lines().enumerate() { // <3> iterate through the lines, recording line numbers where matches are encountered
    if line.contains(needle) {
      tags.push(i);

      let v = Vec::with_capacity(2*context_lines + 1); // <4> <5> `Vec::with_capacity(_n_)` reserves space for _n_ items
      ctx.push(v);
    }
  }

  if tags.len() == 0 { // <6> When there are no matches, exit early
    return;
  }

  // PASS 2
  for (i, line) in haystack.lines().enumerate() { // <7> For each tag, at every line, check to see if we are nearby a match. When we are, add that line to the relevant `Vec<T>` within `ctx`.
    for (j, tag) in tags.iter().enumerate() {
      let lower_bound = tag.saturating_sub(context_lines); // <8> `usize.saturating_sub()` returns 0, rather than underflowing
      let upper_bound = tag + context_lines;

      if (i >= lower_bound) && (i <= upper_bound) {
          let line_as_string = String::from(line); // <9> Copy `line` into a new `String` and store that locally for each match
          let local_ctx = (i, line_as_string);
          ctx[j].push(local_ctx);
      }
    }
  }

  // OUTPUT
  for local_ctx in ctx.iter() {
    for &(i, ref line) in local_ctx.iter() { // <10> `ref line` informs the compiler that we wish to borrow this value, rather than move it. These two terms are explained fully later in later chapters.
      let line_num = i + 1;
      println!("{}: {}", line_num, line);
    }
  }
}