X-Git-Url: https://git.ralfj.de/rust-101.git/blobdiff_plain/5f6e02d64e3789115ea4327a045b8ad3c39b1808..0223210576f27d0743c2d12b890d30f5c2ef6b2d:/workspace/src/part12.rs?ds=inline diff --git a/workspace/src/part12.rs b/workspace/src/part12.rs index 1d75bfd..4996ac1 100644 --- a/workspace/src/part12.rs +++ b/workspace/src/part12.rs @@ -1,5 +1,5 @@ -// Rust-101, Part 12: Concurrency (WIP) -// ================= +// Rust-101, Part 12: Concurrency, Arc, Send +// ========================================= use std::io::prelude::*; use std::{io, fs, thread}; @@ -9,23 +9,22 @@ use std::sync::Arc; // Before we come to the actual code, we define a data-structure `Options` to store all the information we need // to complete the job: Which files to work on, which pattern to look for, and how to output.
-// Besides just printing all the matching lines, we will also offer to count them, or alternatively to sort them. #[derive(Clone,Copy)] -enum OutputMode { +pub enum OutputMode { Print, SortAndPrint, Count, } use self::OutputMode::*; -struct Options { - files: Vec, - pattern: String, - output_mode: OutputMode, +pub struct Options { + pub files: Vec, + pub pattern: String, + pub output_mode: OutputMode, } -// The first functions reads the files, and sends every line over the `out_channel`. +// The first function reads the files, and sends every line over the `out_channel`. fn read_files(options: Arc, out_channel: SyncSender) { for file in options.files.iter() { // First, we open the file, ignoring any errors. @@ -43,11 +42,13 @@ fn read_files(options: Arc, out_channel: SyncSender) { // The second function filters the lines it receives through `in_channel` with the pattern, and sends // matches via `out_channel`. -fn filter_lines(options: Arc, in_channel: Receiver, out_channel: SyncSender) { +fn filter_lines(options: Arc, + in_channel: Receiver, + out_channel: SyncSender) { // We can simply iterate over the channel, which will stop when the channel is closed. for line in in_channel.iter() { // `contains` works on lots of types of patterns, but in particular, we can use it to test whether - // one string is contained in another. + // one string is contained in another. This is another example of Rust using traits as substitute for overloading. if line.contains(&options.pattern) { unimplemented!() } @@ -70,7 +71,7 @@ fn output_lines(options: Arc, in_channel: Receiver) { }, SortAndPrint => { // We are asked to sort the matching lines before printing. So let's collect them all in a local vector... - let data: Vec = in_channel.iter().collect(); + let mut data: Vec = in_channel.iter().collect(); // ...and implement the actual sorting later. unimplemented!() } @@ -79,11 +80,11 @@ fn output_lines(options: Arc, in_channel: Receiver) { // With the operations of the three threads defined, we can now implement a function that performs grepping according // to some given options. -fn run(options: Options) { +pub fn run(options: Options) { // We move the `options` into an `Arc`, as that's what the thread workers expect. let options = Arc::new(options); - // Set up the channels. Use `sync_channel` with buffer-size of 16 to avoid needlessly filling RAM. + // This sets up the channels. We use a `sync_channel` with buffer-size of 16 to avoid needlessly filling RAM. let (line_sender, line_receiver) = sync_channel(16); let (filtered_sender, filtered_receiver) = sync_channel(16); @@ -93,7 +94,9 @@ fn run(options: Options) { // Same with the filter thread. let options2 = options.clone(); - let handle2 = thread::spawn(move || filter_lines(options2, line_receiver, filtered_sender)); + let handle2 = thread::spawn(move || { + filter_lines(options2, line_receiver, filtered_sender) + }); // And the output thread. let options3 = options.clone(); @@ -105,17 +108,19 @@ fn run(options: Options) { handle3.join().unwrap(); } -// Now we have all the pieces together for testing our `rgrep` with some hard-coded options. +// Now we have all the pieces together for testing our rgrep with some hard-coded options. pub fn main() { let options = Options { - files: vec!["src/part10.rs".to_string(), "src/part11.rs".to_string(), "src/part12.rs".to_string()], + files: vec!["src/part10.rs".to_string(), + "src/part11.rs".to_string(), + "src/part12.rs".to_string()], pattern: "let".to_string(), output_mode: Print }; run(options); } -// **Exercise 12.1**: Change `rgrep` such that it prints now only the matching lines, but also the name of the file +// **Exercise 12.1**: Change rgrep such that it prints not only the matching lines, but also the name of the file // and the number of the line in the file. You will have to change the type of the channels from `String` to something // that records this extra information.