summaryrefslogtreecommitdiffstats
path: root/src/doc/book/listings/ch13-functional-features
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /src/doc/book/listings/ch13-functional-features
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/doc/book/listings/ch13-functional-features')
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/poem.txt9
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/src/lib.rs106
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/src/main.rs18
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/poem.txt9
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/src/lib.rs104
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/src/main.rs24
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-01/Cargo.lock7
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-01/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-01/output.txt6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-01/src/main.rs52
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-02/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-02/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-02/src/main.rs33
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-03/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-03/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-03/output.txt12
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-03/src/main.rs8
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-04/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-04/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-04/output.txt8
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-04/src/main.rs10
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-05/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-05/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-05/output.txt6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-05/src/main.rs9
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-06/Cargo.toml8
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-06/src/main.rs10
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-07/.rustfmt.toml2
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-07/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-07/output.txt18
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-07/src/main.rs16
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-08/.rustfmt.toml2
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-08/Cargo.toml8
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-08/output.txt18
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-08/src/main.rs22
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-09/.rustfmt.toml2
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-09/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-09/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-09/src/main.rs20
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-10/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-10/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-10/src/main.rs7
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-11/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-11/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-11/src/main.rs11
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-12/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-12/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-12/src/lib.rs16
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-13/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-13/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-13/src/lib.rs15
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-14/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-14/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-14/output.txt14
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-14/src/main.rs7
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-15/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-15/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-15/src/main.rs9
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-16/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-16/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-16/src/lib.rs48
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-18/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-18/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-18/poem.txt9
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-18/src/lib.rs104
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-18/src/main.rs22
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-19/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-19/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-19/poem.txt9
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-19/src/lib.rs109
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-19/src/main.rs16
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-20/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-20/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-20/poem.txt9
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-20/src/lib.rs113
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-20/src/main.rs16
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-22/Cargo.lock6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-22/Cargo.toml6
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-22/poem.txt9
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-22/src/lib.rs108
-rw-r--r--src/doc/book/listings/ch13-functional-features/listing-13-22/src/main.rs16
85 files changed, 1442 insertions, 0 deletions
diff --git a/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/Cargo.lock
new file mode 100644
index 000000000..88bf82d16
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "minigrep"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/Cargo.toml
new file mode 100644
index 000000000..64c2a3f52
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "minigrep"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/poem.txt b/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/poem.txt
new file mode 100644
index 000000000..870752731
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/poem.txt
@@ -0,0 +1,9 @@
+I'm nobody! Who are you?
+Are you nobody, too?
+Then there's a pair of us - don't tell!
+They'd banish us, you know.
+
+How dreary to be somebody!
+How public, like a frog
+To tell your name the livelong day
+To an admiring bog!
diff --git a/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/src/lib.rs b/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/src/lib.rs
new file mode 100644
index 000000000..e54343d24
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/src/lib.rs
@@ -0,0 +1,106 @@
+use std::env;
+use std::error::Error;
+use std::fs;
+
+pub struct Config {
+ pub query: String,
+ pub file_path: String,
+ pub ignore_case: bool,
+}
+
+// ANCHOR: ch13
+impl Config {
+ pub fn build(args: &[String]) -> Result<Config, &'static str> {
+ if args.len() < 3 {
+ return Err("not enough arguments");
+ }
+
+ let query = args[1].clone();
+ let file_path = args[2].clone();
+
+ let ignore_case = env::var("IGNORE_CASE").is_ok();
+
+ Ok(Config {
+ query,
+ file_path,
+ ignore_case,
+ })
+ }
+}
+// ANCHOR_END: ch13
+
+pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
+ let contents = fs::read_to_string(config.file_path)?;
+
+ let results = if config.ignore_case {
+ search_case_insensitive(&config.query, &contents)
+ } else {
+ search(&config.query, &contents)
+ };
+
+ for line in results {
+ println!("{line}");
+ }
+
+ Ok(())
+}
+
+pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
+ let mut results = Vec::new();
+
+ for line in contents.lines() {
+ if line.contains(query) {
+ results.push(line);
+ }
+ }
+
+ results
+}
+
+pub fn search_case_insensitive<'a>(
+ query: &str,
+ contents: &'a str,
+) -> Vec<&'a str> {
+ let query = query.to_lowercase();
+ let mut results = Vec::new();
+
+ for line in contents.lines() {
+ if line.to_lowercase().contains(&query) {
+ results.push(line);
+ }
+ }
+
+ results
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn case_sensitive() {
+ let query = "duct";
+ let contents = "\
+Rust:
+safe, fast, productive.
+Pick three.
+Duct tape.";
+
+ assert_eq!(vec!["safe, fast, productive."], search(query, contents));
+ }
+
+ #[test]
+ fn case_insensitive() {
+ let query = "rUsT";
+ let contents = "\
+Rust:
+safe, fast, productive.
+Pick three.
+Trust me.";
+
+ assert_eq!(
+ vec!["Rust:", "Trust me."],
+ search_case_insensitive(query, contents)
+ );
+ }
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/src/main.rs
new file mode 100644
index 000000000..a4f8a7411
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-12-23-reproduced/src/main.rs
@@ -0,0 +1,18 @@
+use std::env;
+use std::process;
+
+use minigrep::Config;
+
+fn main() {
+ let args: Vec<String> = env::args().collect();
+
+ let config = Config::build(&args).unwrap_or_else(|err| {
+ println!("Problem parsing arguments: {err}");
+ process::exit(1);
+ });
+
+ if let Err(e) = minigrep::run(config) {
+ println!("Application error: {e}");
+ process::exit(1);
+ }
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/Cargo.lock
new file mode 100644
index 000000000..88bf82d16
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "minigrep"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/Cargo.toml
new file mode 100644
index 000000000..64c2a3f52
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "minigrep"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/poem.txt b/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/poem.txt
new file mode 100644
index 000000000..870752731
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/poem.txt
@@ -0,0 +1,9 @@
+I'm nobody! Who are you?
+Are you nobody, too?
+Then there's a pair of us - don't tell!
+They'd banish us, you know.
+
+How dreary to be somebody!
+How public, like a frog
+To tell your name the livelong day
+To an admiring bog!
diff --git a/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/src/lib.rs b/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/src/lib.rs
new file mode 100644
index 000000000..292b09789
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/src/lib.rs
@@ -0,0 +1,104 @@
+use std::env;
+use std::error::Error;
+use std::fs;
+
+pub struct Config {
+ pub query: String,
+ pub file_path: String,
+ pub ignore_case: bool,
+}
+
+impl Config {
+ pub fn build(args: &[String]) -> Result<Config, &'static str> {
+ if args.len() < 3 {
+ return Err("not enough arguments");
+ }
+
+ let query = args[1].clone();
+ let file_path = args[2].clone();
+
+ let ignore_case = env::var("IGNORE_CASE").is_ok();
+
+ Ok(Config {
+ query,
+ file_path,
+ ignore_case,
+ })
+ }
+}
+
+pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
+ let contents = fs::read_to_string(config.file_path)?;
+
+ let results = if config.ignore_case {
+ search_case_insensitive(&config.query, &contents)
+ } else {
+ search(&config.query, &contents)
+ };
+
+ for line in results {
+ println!("{line}");
+ }
+
+ Ok(())
+}
+
+pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
+ let mut results = Vec::new();
+
+ for line in contents.lines() {
+ if line.contains(query) {
+ results.push(line);
+ }
+ }
+
+ results
+}
+
+pub fn search_case_insensitive<'a>(
+ query: &str,
+ contents: &'a str,
+) -> Vec<&'a str> {
+ let query = query.to_lowercase();
+ let mut results = Vec::new();
+
+ for line in contents.lines() {
+ if line.to_lowercase().contains(&query) {
+ results.push(line);
+ }
+ }
+
+ results
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn case_sensitive() {
+ let query = "duct";
+ let contents = "\
+Rust:
+safe, fast, productive.
+Pick three.
+Duct tape.";
+
+ assert_eq!(vec!["safe, fast, productive."], search(query, contents));
+ }
+
+ #[test]
+ fn case_insensitive() {
+ let query = "rUsT";
+ let contents = "\
+Rust:
+safe, fast, productive.
+Pick three.
+Trust me.";
+
+ assert_eq!(
+ vec!["Rust:", "Trust me."],
+ search_case_insensitive(query, contents)
+ );
+ }
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/src/main.rs
new file mode 100644
index 000000000..f9d179c8c
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-12-24-reproduced/src/main.rs
@@ -0,0 +1,24 @@
+use std::env;
+use std::process;
+
+use minigrep::Config;
+
+// ANCHOR: ch13
+fn main() {
+ let args: Vec<String> = env::args().collect();
+
+ let config = Config::build(&args).unwrap_or_else(|err| {
+ eprintln!("Problem parsing arguments: {err}");
+ process::exit(1);
+ });
+
+ // --snip--
+ // ANCHOR_END: ch13
+
+ if let Err(e) = minigrep::run(config) {
+ eprintln!("Application error: {e}");
+ process::exit(1);
+ }
+ // ANCHOR: ch13
+}
+// ANCHOR_END: ch13
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-01/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-01/Cargo.lock
new file mode 100644
index 000000000..6f974d1ba
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-01/Cargo.lock
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "shirt-company"
+version = "0.1.0"
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-01/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-01/Cargo.toml
new file mode 100644
index 000000000..1eb392dfa
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-01/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "shirt-company"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-01/output.txt b/src/doc/book/listings/ch13-functional-features/listing-13-01/output.txt
new file mode 100644
index 000000000..b64a4d8dc
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-01/output.txt
@@ -0,0 +1,6 @@
+$ cargo run
+ Compiling shirt-company v0.1.0 (file:///projects/shirt-company)
+ Finished dev [unoptimized + debuginfo] target(s) in 0.27s
+ Running `target/debug/shirt-company`
+The user with preference Some(Red) gets Red
+The user with preference None gets Blue
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-01/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-01/src/main.rs
new file mode 100644
index 000000000..2c87d6965
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-01/src/main.rs
@@ -0,0 +1,52 @@
+#[derive(Debug, PartialEq, Copy, Clone)]
+enum ShirtColor {
+ Red,
+ Blue,
+}
+
+struct Inventory {
+ shirts: Vec<ShirtColor>,
+}
+
+impl Inventory {
+ fn giveaway(&self, user_preference: Option<ShirtColor>) -> ShirtColor {
+ user_preference.unwrap_or_else(|| self.most_stocked())
+ }
+
+ fn most_stocked(&self) -> ShirtColor {
+ let mut num_red = 0;
+ let mut num_blue = 0;
+
+ for color in &self.shirts {
+ match color {
+ ShirtColor::Red => num_red += 1,
+ ShirtColor::Blue => num_blue += 1,
+ }
+ }
+ if num_red > num_blue {
+ ShirtColor::Red
+ } else {
+ ShirtColor::Blue
+ }
+ }
+}
+
+fn main() {
+ let store = Inventory {
+ shirts: vec![ShirtColor::Blue, ShirtColor::Red, ShirtColor::Blue],
+ };
+
+ let user_pref1 = Some(ShirtColor::Red);
+ let giveaway1 = store.giveaway(user_pref1);
+ println!(
+ "The user with preference {:?} gets {:?}",
+ user_pref1, giveaway1
+ );
+
+ let user_pref2 = None;
+ let giveaway2 = store.giveaway(user_pref2);
+ println!(
+ "The user with preference {:?} gets {:?}",
+ user_pref2, giveaway2
+ );
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-02/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-02/Cargo.lock
new file mode 100644
index 000000000..75ff09e51
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-02/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "workout-app"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-02/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-02/Cargo.toml
new file mode 100644
index 000000000..f09a737d4
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-02/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "workout-app"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-02/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-02/src/main.rs
new file mode 100644
index 000000000..b3f4cc2c2
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-02/src/main.rs
@@ -0,0 +1,33 @@
+use std::thread;
+use std::time::Duration;
+
+fn generate_workout(intensity: u32, random_number: u32) {
+ // ANCHOR: here
+ let expensive_closure = |num: u32| -> u32 {
+ println!("calculating slowly...");
+ thread::sleep(Duration::from_secs(2));
+ num
+ };
+ // ANCHOR_END: here
+
+ if intensity < 25 {
+ println!("Today, do {} pushups!", expensive_closure(intensity));
+ println!("Next, do {} situps!", expensive_closure(intensity));
+ } else {
+ if random_number == 3 {
+ println!("Take a break today! Remember to stay hydrated!");
+ } else {
+ println!(
+ "Today, run for {} minutes!",
+ expensive_closure(intensity)
+ );
+ }
+ }
+}
+
+fn main() {
+ let simulated_user_specified_value = 10;
+ let simulated_random_number = 7;
+
+ generate_workout(simulated_user_specified_value, simulated_random_number);
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-03/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-03/Cargo.lock
new file mode 100644
index 000000000..c190d3a41
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-03/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "closure-example"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-03/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-03/Cargo.toml
new file mode 100644
index 000000000..914c4cfaa
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-03/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "closure-example"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-03/output.txt b/src/doc/book/listings/ch13-functional-features/listing-13-03/output.txt
new file mode 100644
index 000000000..37d83618a
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-03/output.txt
@@ -0,0 +1,12 @@
+$ cargo run
+ Compiling closure-example v0.1.0 (file:///projects/closure-example)
+error[E0308]: mismatched types
+ --> src/main.rs:5:29
+ |
+5 | let n = example_closure(5);
+ | ^- help: try using a conversion method: `.to_string()`
+ | |
+ | expected struct `String`, found integer
+
+For more information about this error, try `rustc --explain E0308`.
+error: could not compile `closure-example` due to previous error
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-03/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-03/src/main.rs
new file mode 100644
index 000000000..ebb2489bf
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-03/src/main.rs
@@ -0,0 +1,8 @@
+fn main() {
+ // ANCHOR: here
+ let example_closure = |x| x;
+
+ let s = example_closure(String::from("hello"));
+ let n = example_closure(5);
+ // ANCHOR_END: here
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-04/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-04/Cargo.lock
new file mode 100644
index 000000000..75ff09e51
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-04/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "workout-app"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-04/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-04/Cargo.toml
new file mode 100644
index 000000000..914c4cfaa
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-04/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "closure-example"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-04/output.txt b/src/doc/book/listings/ch13-functional-features/listing-13-04/output.txt
new file mode 100644
index 000000000..64d763b51
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-04/output.txt
@@ -0,0 +1,8 @@
+$ cargo run
+ Compiling closure-example v0.1.0 (file:///projects/closure-example)
+ Finished dev [unoptimized + debuginfo] target(s) in 0.43s
+ Running `target/debug/closure-example`
+Before defining closure: [1, 2, 3]
+Before calling closure: [1, 2, 3]
+From closure: [1, 2, 3]
+After calling closure: [1, 2, 3]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-04/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-04/src/main.rs
new file mode 100644
index 000000000..43b91bb30
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-04/src/main.rs
@@ -0,0 +1,10 @@
+fn main() {
+ let list = vec![1, 2, 3];
+ println!("Before defining closure: {:?}", list);
+
+ let only_borrows = || println!("From closure: {:?}", list);
+
+ println!("Before calling closure: {:?}", list);
+ only_borrows();
+ println!("After calling closure: {:?}", list);
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-05/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-05/Cargo.lock
new file mode 100644
index 000000000..75ff09e51
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-05/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "workout-app"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-05/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-05/Cargo.toml
new file mode 100644
index 000000000..914c4cfaa
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-05/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "closure-example"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-05/output.txt b/src/doc/book/listings/ch13-functional-features/listing-13-05/output.txt
new file mode 100644
index 000000000..ce0ad5e37
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-05/output.txt
@@ -0,0 +1,6 @@
+$ cargo run
+ Compiling closure-example v0.1.0 (file:///projects/closure-example)
+ Finished dev [unoptimized + debuginfo] target(s) in 0.43s
+ Running `target/debug/closure-example`
+Before defining closure: [1, 2, 3]
+After calling closure: [1, 2, 3, 7]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-05/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-05/src/main.rs
new file mode 100644
index 000000000..37f8130e2
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-05/src/main.rs
@@ -0,0 +1,9 @@
+fn main() {
+ let mut list = vec![1, 2, 3];
+ println!("Before defining closure: {:?}", list);
+
+ let mut borrows_mutably = || list.push(7);
+
+ borrows_mutably();
+ println!("After calling closure: {:?}", list);
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-06/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-06/Cargo.toml
new file mode 100644
index 000000000..8085ade0f
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-06/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "closure-example"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-06/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-06/src/main.rs
new file mode 100644
index 000000000..2c8e18c9f
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-06/src/main.rs
@@ -0,0 +1,10 @@
+use std::thread;
+
+fn main() {
+ let list = vec![1, 2, 3];
+ println!("Before defining closure: {:?}", list);
+
+ thread::spawn(move || println!("From thread: {:?}", list))
+ .join()
+ .unwrap();
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-07/.rustfmt.toml b/src/doc/book/listings/ch13-functional-features/listing-13-07/.rustfmt.toml
new file mode 100644
index 000000000..ee10c634b
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-07/.rustfmt.toml
@@ -0,0 +1,2 @@
+struct_lit_width = 50
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-07/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-07/Cargo.toml
new file mode 100644
index 000000000..4a279a450
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-07/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "rectangles"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-07/output.txt b/src/doc/book/listings/ch13-functional-features/listing-13-07/output.txt
new file mode 100644
index 000000000..f18fce46e
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-07/output.txt
@@ -0,0 +1,18 @@
+$ cargo run
+ Compiling rectangles v0.1.0 (file:///projects/rectangles)
+ Finished dev [unoptimized + debuginfo] target(s) in 0.41s
+ Running `target/debug/rectangles`
+[
+ Rectangle {
+ width: 3,
+ height: 5,
+ },
+ Rectangle {
+ width: 7,
+ height: 12,
+ },
+ Rectangle {
+ width: 10,
+ height: 1,
+ },
+]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-07/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-07/src/main.rs
new file mode 100644
index 000000000..73a25e5f9
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-07/src/main.rs
@@ -0,0 +1,16 @@
+#[derive(Debug)]
+struct Rectangle {
+ width: u32,
+ height: u32,
+}
+
+fn main() {
+ let mut list = [
+ Rectangle { width: 10, height: 1 },
+ Rectangle { width: 3, height: 5 },
+ Rectangle { width: 7, height: 12 },
+ ];
+
+ list.sort_by_key(|r| r.width);
+ println!("{:#?}", list);
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-08/.rustfmt.toml b/src/doc/book/listings/ch13-functional-features/listing-13-08/.rustfmt.toml
new file mode 100644
index 000000000..ee10c634b
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-08/.rustfmt.toml
@@ -0,0 +1,2 @@
+struct_lit_width = 50
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-08/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-08/Cargo.toml
new file mode 100644
index 000000000..703c9d977
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-08/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "rectangles"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-08/output.txt b/src/doc/book/listings/ch13-functional-features/listing-13-08/output.txt
new file mode 100644
index 000000000..7a39ac618
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-08/output.txt
@@ -0,0 +1,18 @@
+$ cargo run
+ Compiling rectangles v0.1.0 (file:///projects/rectangles)
+error[E0507]: cannot move out of `value`, a captured variable in an `FnMut` closure
+ --> src/main.rs:18:30
+ |
+15 | let value = String::from("by key called");
+ | ----- captured outer variable
+16 |
+17 | list.sort_by_key(|r| {
+ | ______________________-
+18 | | sort_operations.push(value);
+ | | ^^^^^ move occurs because `value` has type `String`, which does not implement the `Copy` trait
+19 | | r.width
+20 | | });
+ | |_____- captured by this `FnMut` closure
+
+For more information about this error, try `rustc --explain E0507`.
+error: could not compile `rectangles` due to previous error
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-08/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-08/src/main.rs
new file mode 100644
index 000000000..3b9c9cbdf
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-08/src/main.rs
@@ -0,0 +1,22 @@
+#[derive(Debug)]
+struct Rectangle {
+ width: u32,
+ height: u32,
+}
+
+fn main() {
+ let mut list = [
+ Rectangle { width: 10, height: 1 },
+ Rectangle { width: 3, height: 5 },
+ Rectangle { width: 7, height: 12 },
+ ];
+
+ let mut sort_operations = vec![];
+ let value = String::from("by key called");
+
+ list.sort_by_key(|r| {
+ sort_operations.push(value);
+ r.width
+ });
+ println!("{:#?}", list);
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-09/.rustfmt.toml b/src/doc/book/listings/ch13-functional-features/listing-13-09/.rustfmt.toml
new file mode 100644
index 000000000..ee10c634b
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-09/.rustfmt.toml
@@ -0,0 +1,2 @@
+struct_lit_width = 50
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-09/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-09/Cargo.lock
new file mode 100644
index 000000000..e090432bc
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-09/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "cacher"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-09/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-09/Cargo.toml
new file mode 100644
index 000000000..4a279a450
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-09/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "rectangles"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-09/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-09/src/main.rs
new file mode 100644
index 000000000..a60d6fd3f
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-09/src/main.rs
@@ -0,0 +1,20 @@
+#[derive(Debug)]
+struct Rectangle {
+ width: u32,
+ height: u32,
+}
+
+fn main() {
+ let mut list = [
+ Rectangle { width: 10, height: 1 },
+ Rectangle { width: 3, height: 5 },
+ Rectangle { width: 7, height: 12 },
+ ];
+
+ let mut num_sort_operations = 0;
+ list.sort_by_key(|r| {
+ num_sort_operations += 1;
+ r.width
+ });
+ println!("{:#?}, sorted in {num_sort_operations} operations", list);
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-10/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-10/Cargo.lock
new file mode 100644
index 000000000..e91eaa8d4
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-10/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "iterators"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-10/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-10/Cargo.toml
new file mode 100644
index 000000000..2652a8a1a
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-10/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "iterators"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-10/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-10/src/main.rs
new file mode 100644
index 000000000..55a0dd37e
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-10/src/main.rs
@@ -0,0 +1,7 @@
+fn main() {
+ // ANCHOR: here
+ let v1 = vec![1, 2, 3];
+
+ let v1_iter = v1.iter();
+ // ANCHOR_END: here
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-11/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-11/Cargo.lock
new file mode 100644
index 000000000..e91eaa8d4
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-11/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "iterators"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-11/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-11/Cargo.toml
new file mode 100644
index 000000000..2652a8a1a
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-11/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "iterators"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-11/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-11/src/main.rs
new file mode 100644
index 000000000..712aff408
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-11/src/main.rs
@@ -0,0 +1,11 @@
+fn main() {
+ // ANCHOR: here
+ let v1 = vec![1, 2, 3];
+
+ let v1_iter = v1.iter();
+
+ for val in v1_iter {
+ println!("Got: {}", val);
+ }
+ // ANCHOR_END: here
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-12/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-12/Cargo.lock
new file mode 100644
index 000000000..e91eaa8d4
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-12/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "iterators"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-12/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-12/Cargo.toml
new file mode 100644
index 000000000..2652a8a1a
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-12/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "iterators"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-12/src/lib.rs b/src/doc/book/listings/ch13-functional-features/listing-13-12/src/lib.rs
new file mode 100644
index 000000000..758284044
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-12/src/lib.rs
@@ -0,0 +1,16 @@
+#[cfg(test)]
+mod tests {
+ // ANCHOR: here
+ #[test]
+ fn iterator_demonstration() {
+ let v1 = vec![1, 2, 3];
+
+ let mut v1_iter = v1.iter();
+
+ assert_eq!(v1_iter.next(), Some(&1));
+ assert_eq!(v1_iter.next(), Some(&2));
+ assert_eq!(v1_iter.next(), Some(&3));
+ assert_eq!(v1_iter.next(), None);
+ }
+ // ANCHOR_END: here
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-13/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-13/Cargo.lock
new file mode 100644
index 000000000..e91eaa8d4
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-13/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "iterators"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-13/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-13/Cargo.toml
new file mode 100644
index 000000000..2652a8a1a
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-13/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "iterators"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-13/src/lib.rs b/src/doc/book/listings/ch13-functional-features/listing-13-13/src/lib.rs
new file mode 100644
index 000000000..d1cb54d0a
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-13/src/lib.rs
@@ -0,0 +1,15 @@
+#[cfg(test)]
+mod tests {
+ // ANCHOR: here
+ #[test]
+ fn iterator_sum() {
+ let v1 = vec![1, 2, 3];
+
+ let v1_iter = v1.iter();
+
+ let total: i32 = v1_iter.sum();
+
+ assert_eq!(total, 6);
+ }
+ // ANCHOR_END: here
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-14/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-14/Cargo.lock
new file mode 100644
index 000000000..e91eaa8d4
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-14/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "iterators"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-14/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-14/Cargo.toml
new file mode 100644
index 000000000..2652a8a1a
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-14/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "iterators"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-14/output.txt b/src/doc/book/listings/ch13-functional-features/listing-13-14/output.txt
new file mode 100644
index 000000000..228c764ed
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-14/output.txt
@@ -0,0 +1,14 @@
+$ cargo run
+ Compiling iterators v0.1.0 (file:///projects/iterators)
+warning: unused `Map` that must be used
+ --> src/main.rs:4:5
+ |
+4 | v1.iter().map(|x| x + 1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unused_must_use)]` on by default
+ = note: iterators are lazy and do nothing unless consumed
+
+warning: `iterators` (bin "iterators") generated 1 warning
+ Finished dev [unoptimized + debuginfo] target(s) in 0.47s
+ Running `target/debug/iterators`
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-14/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-14/src/main.rs
new file mode 100644
index 000000000..62a68be9b
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-14/src/main.rs
@@ -0,0 +1,7 @@
+fn main() {
+ // ANCHOR: here
+ let v1: Vec<i32> = vec![1, 2, 3];
+
+ v1.iter().map(|x| x + 1);
+ // ANCHOR_END: here
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-15/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-15/Cargo.lock
new file mode 100644
index 000000000..e91eaa8d4
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-15/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "iterators"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-15/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-15/Cargo.toml
new file mode 100644
index 000000000..2652a8a1a
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-15/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "iterators"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-15/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-15/src/main.rs
new file mode 100644
index 000000000..db9025d6f
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-15/src/main.rs
@@ -0,0 +1,9 @@
+fn main() {
+ // ANCHOR: here
+ let v1: Vec<i32> = vec![1, 2, 3];
+
+ let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
+
+ assert_eq!(v2, vec![2, 3, 4]);
+ // ANCHOR_END: here
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-16/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-16/Cargo.lock
new file mode 100644
index 000000000..0b15e2157
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-16/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "shoe_size"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-16/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-16/Cargo.toml
new file mode 100644
index 000000000..cc803776b
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-16/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "shoe_size"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-16/src/lib.rs b/src/doc/book/listings/ch13-functional-features/listing-13-16/src/lib.rs
new file mode 100644
index 000000000..281c3c9e4
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-16/src/lib.rs
@@ -0,0 +1,48 @@
+#[derive(PartialEq, Debug)]
+struct Shoe {
+ size: u32,
+ style: String,
+}
+
+fn shoes_in_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
+ shoes.into_iter().filter(|s| s.size == shoe_size).collect()
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn filters_by_size() {
+ let shoes = vec![
+ Shoe {
+ size: 10,
+ style: String::from("sneaker"),
+ },
+ Shoe {
+ size: 13,
+ style: String::from("sandal"),
+ },
+ Shoe {
+ size: 10,
+ style: String::from("boot"),
+ },
+ ];
+
+ let in_my_size = shoes_in_size(shoes, 10);
+
+ assert_eq!(
+ in_my_size,
+ vec![
+ Shoe {
+ size: 10,
+ style: String::from("sneaker")
+ },
+ Shoe {
+ size: 10,
+ style: String::from("boot")
+ },
+ ]
+ );
+ }
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-18/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-18/Cargo.lock
new file mode 100644
index 000000000..88bf82d16
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-18/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "minigrep"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-18/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-18/Cargo.toml
new file mode 100644
index 000000000..64c2a3f52
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-18/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "minigrep"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-18/poem.txt b/src/doc/book/listings/ch13-functional-features/listing-13-18/poem.txt
new file mode 100644
index 000000000..870752731
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-18/poem.txt
@@ -0,0 +1,9 @@
+I'm nobody! Who are you?
+Are you nobody, too?
+Then there's a pair of us - don't tell!
+They'd banish us, you know.
+
+How dreary to be somebody!
+How public, like a frog
+To tell your name the livelong day
+To an admiring bog!
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-18/src/lib.rs b/src/doc/book/listings/ch13-functional-features/listing-13-18/src/lib.rs
new file mode 100644
index 000000000..292b09789
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-18/src/lib.rs
@@ -0,0 +1,104 @@
+use std::env;
+use std::error::Error;
+use std::fs;
+
+pub struct Config {
+ pub query: String,
+ pub file_path: String,
+ pub ignore_case: bool,
+}
+
+impl Config {
+ pub fn build(args: &[String]) -> Result<Config, &'static str> {
+ if args.len() < 3 {
+ return Err("not enough arguments");
+ }
+
+ let query = args[1].clone();
+ let file_path = args[2].clone();
+
+ let ignore_case = env::var("IGNORE_CASE").is_ok();
+
+ Ok(Config {
+ query,
+ file_path,
+ ignore_case,
+ })
+ }
+}
+
+pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
+ let contents = fs::read_to_string(config.file_path)?;
+
+ let results = if config.ignore_case {
+ search_case_insensitive(&config.query, &contents)
+ } else {
+ search(&config.query, &contents)
+ };
+
+ for line in results {
+ println!("{line}");
+ }
+
+ Ok(())
+}
+
+pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
+ let mut results = Vec::new();
+
+ for line in contents.lines() {
+ if line.contains(query) {
+ results.push(line);
+ }
+ }
+
+ results
+}
+
+pub fn search_case_insensitive<'a>(
+ query: &str,
+ contents: &'a str,
+) -> Vec<&'a str> {
+ let query = query.to_lowercase();
+ let mut results = Vec::new();
+
+ for line in contents.lines() {
+ if line.to_lowercase().contains(&query) {
+ results.push(line);
+ }
+ }
+
+ results
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn case_sensitive() {
+ let query = "duct";
+ let contents = "\
+Rust:
+safe, fast, productive.
+Pick three.
+Duct tape.";
+
+ assert_eq!(vec!["safe, fast, productive."], search(query, contents));
+ }
+
+ #[test]
+ fn case_insensitive() {
+ let query = "rUsT";
+ let contents = "\
+Rust:
+safe, fast, productive.
+Pick three.
+Trust me.";
+
+ assert_eq!(
+ vec!["Rust:", "Trust me."],
+ search_case_insensitive(query, contents)
+ );
+ }
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-18/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-18/src/main.rs
new file mode 100644
index 000000000..40109ef63
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-18/src/main.rs
@@ -0,0 +1,22 @@
+use std::env;
+use std::process;
+
+use minigrep::Config;
+
+// ANCHOR: here
+fn main() {
+ let config = Config::build(env::args()).unwrap_or_else(|err| {
+ eprintln!("Problem parsing arguments: {err}");
+ process::exit(1);
+ });
+
+ // --snip--
+ // ANCHOR_END: here
+
+ if let Err(e) = minigrep::run(config) {
+ eprintln!("Application error: {e}");
+ process::exit(1);
+ }
+ // ANCHOR: here
+}
+// ANCHOR_END: here
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-19/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-19/Cargo.lock
new file mode 100644
index 000000000..88bf82d16
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-19/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "minigrep"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-19/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-19/Cargo.toml
new file mode 100644
index 000000000..64c2a3f52
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-19/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "minigrep"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-19/poem.txt b/src/doc/book/listings/ch13-functional-features/listing-13-19/poem.txt
new file mode 100644
index 000000000..870752731
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-19/poem.txt
@@ -0,0 +1,9 @@
+I'm nobody! Who are you?
+Are you nobody, too?
+Then there's a pair of us - don't tell!
+They'd banish us, you know.
+
+How dreary to be somebody!
+How public, like a frog
+To tell your name the livelong day
+To an admiring bog!
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-19/src/lib.rs b/src/doc/book/listings/ch13-functional-features/listing-13-19/src/lib.rs
new file mode 100644
index 000000000..79ae2b8f6
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-19/src/lib.rs
@@ -0,0 +1,109 @@
+use std::env;
+use std::error::Error;
+use std::fs;
+
+pub struct Config {
+ pub query: String,
+ pub file_path: String,
+ pub ignore_case: bool,
+}
+
+// ANCHOR: here
+impl Config {
+ pub fn build(
+ mut args: impl Iterator<Item = String>,
+ ) -> Result<Config, &'static str> {
+ // --snip--
+ // ANCHOR_END: here
+ if args.len() < 3 {
+ return Err("not enough arguments");
+ }
+
+ let query = args[1].clone();
+ let file_path = args[2].clone();
+
+ let ignore_case = env::var("IGNORE_CASE").is_ok();
+
+ Ok(Config {
+ query,
+ file_path,
+ ignore_case,
+ })
+ }
+}
+
+pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
+ let contents = fs::read_to_string(config.file_path)?;
+
+ let results = if config.ignore_case {
+ search_case_insensitive(&config.query, &contents)
+ } else {
+ search(&config.query, &contents)
+ };
+
+ for line in results {
+ println!("{line}");
+ }
+
+ Ok(())
+}
+
+pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
+ let mut results = Vec::new();
+
+ for line in contents.lines() {
+ if line.contains(query) {
+ results.push(line);
+ }
+ }
+
+ results
+}
+
+pub fn search_case_insensitive<'a>(
+ query: &str,
+ contents: &'a str,
+) -> Vec<&'a str> {
+ let query = query.to_lowercase();
+ let mut results = Vec::new();
+
+ for line in contents.lines() {
+ if line.to_lowercase().contains(&query) {
+ results.push(line);
+ }
+ }
+
+ results
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn case_sensitive() {
+ let query = "duct";
+ let contents = "\
+Rust:
+safe, fast, productive.
+Pick three.
+Duct tape.";
+
+ assert_eq!(vec!["safe, fast, productive."], search(query, contents));
+ }
+
+ #[test]
+ fn case_insensitive() {
+ let query = "rUsT";
+ let contents = "\
+Rust:
+safe, fast, productive.
+Pick three.
+Trust me.";
+
+ assert_eq!(
+ vec!["Rust:", "Trust me."],
+ search_case_insensitive(query, contents)
+ );
+ }
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-19/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-19/src/main.rs
new file mode 100644
index 000000000..9ac022545
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-19/src/main.rs
@@ -0,0 +1,16 @@
+use std::env;
+use std::process;
+
+use minigrep::Config;
+
+fn main() {
+ let config = Config::build(env::args()).unwrap_or_else(|err| {
+ eprintln!("Problem parsing arguments: {err}");
+ process::exit(1);
+ });
+
+ if let Err(e) = minigrep::run(config) {
+ eprintln!("Application error: {e}");
+ process::exit(1);
+ }
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-20/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-20/Cargo.lock
new file mode 100644
index 000000000..88bf82d16
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-20/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "minigrep"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-20/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-20/Cargo.toml
new file mode 100644
index 000000000..64c2a3f52
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-20/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "minigrep"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-20/poem.txt b/src/doc/book/listings/ch13-functional-features/listing-13-20/poem.txt
new file mode 100644
index 000000000..870752731
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-20/poem.txt
@@ -0,0 +1,9 @@
+I'm nobody! Who are you?
+Are you nobody, too?
+Then there's a pair of us - don't tell!
+They'd banish us, you know.
+
+How dreary to be somebody!
+How public, like a frog
+To tell your name the livelong day
+To an admiring bog!
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-20/src/lib.rs b/src/doc/book/listings/ch13-functional-features/listing-13-20/src/lib.rs
new file mode 100644
index 000000000..4410964a7
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-20/src/lib.rs
@@ -0,0 +1,113 @@
+use std::env;
+use std::error::Error;
+use std::fs;
+
+pub struct Config {
+ pub query: String,
+ pub file_path: String,
+ pub ignore_case: bool,
+}
+
+// ANCHOR: here
+impl Config {
+ pub fn build(
+ mut args: impl Iterator<Item = String>,
+ ) -> Result<Config, &'static str> {
+ args.next();
+
+ let query = match args.next() {
+ Some(arg) => arg,
+ None => return Err("Didn't get a query string"),
+ };
+
+ let file_path = match args.next() {
+ Some(arg) => arg,
+ None => return Err("Didn't get a file path"),
+ };
+
+ let ignore_case = env::var("IGNORE_CASE").is_ok();
+
+ Ok(Config {
+ query,
+ file_path,
+ ignore_case,
+ })
+ }
+}
+// ANCHOR_END: here
+
+pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
+ let contents = fs::read_to_string(config.file_path)?;
+
+ let results = if config.ignore_case {
+ search_case_insensitive(&config.query, &contents)
+ } else {
+ search(&config.query, &contents)
+ };
+
+ for line in results {
+ println!("{line}");
+ }
+
+ Ok(())
+}
+
+pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
+ let mut results = Vec::new();
+
+ for line in contents.lines() {
+ if line.contains(query) {
+ results.push(line);
+ }
+ }
+
+ results
+}
+
+pub fn search_case_insensitive<'a>(
+ query: &str,
+ contents: &'a str,
+) -> Vec<&'a str> {
+ let query = query.to_lowercase();
+ let mut results = Vec::new();
+
+ for line in contents.lines() {
+ if line.to_lowercase().contains(&query) {
+ results.push(line);
+ }
+ }
+
+ results
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn case_sensitive() {
+ let query = "duct";
+ let contents = "\
+Rust:
+safe, fast, productive.
+Pick three.
+Duct tape.";
+
+ assert_eq!(vec!["safe, fast, productive."], search(query, contents));
+ }
+
+ #[test]
+ fn case_insensitive() {
+ let query = "rUsT";
+ let contents = "\
+Rust:
+safe, fast, productive.
+Pick three.
+Trust me.";
+
+ assert_eq!(
+ vec!["Rust:", "Trust me."],
+ search_case_insensitive(query, contents)
+ );
+ }
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-20/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-20/src/main.rs
new file mode 100644
index 000000000..9ac022545
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-20/src/main.rs
@@ -0,0 +1,16 @@
+use std::env;
+use std::process;
+
+use minigrep::Config;
+
+fn main() {
+ let config = Config::build(env::args()).unwrap_or_else(|err| {
+ eprintln!("Problem parsing arguments: {err}");
+ process::exit(1);
+ });
+
+ if let Err(e) = minigrep::run(config) {
+ eprintln!("Application error: {e}");
+ process::exit(1);
+ }
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-22/Cargo.lock b/src/doc/book/listings/ch13-functional-features/listing-13-22/Cargo.lock
new file mode 100644
index 000000000..88bf82d16
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-22/Cargo.lock
@@ -0,0 +1,6 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "minigrep"
+version = "0.1.0"
+
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-22/Cargo.toml b/src/doc/book/listings/ch13-functional-features/listing-13-22/Cargo.toml
new file mode 100644
index 000000000..64c2a3f52
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-22/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "minigrep"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-22/poem.txt b/src/doc/book/listings/ch13-functional-features/listing-13-22/poem.txt
new file mode 100644
index 000000000..870752731
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-22/poem.txt
@@ -0,0 +1,9 @@
+I'm nobody! Who are you?
+Are you nobody, too?
+Then there's a pair of us - don't tell!
+They'd banish us, you know.
+
+How dreary to be somebody!
+How public, like a frog
+To tell your name the livelong day
+To an admiring bog!
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-22/src/lib.rs b/src/doc/book/listings/ch13-functional-features/listing-13-22/src/lib.rs
new file mode 100644
index 000000000..d694669b4
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-22/src/lib.rs
@@ -0,0 +1,108 @@
+use std::env;
+use std::error::Error;
+use std::fs;
+
+pub struct Config {
+ pub query: String,
+ pub file_path: String,
+ pub ignore_case: bool,
+}
+
+impl Config {
+ pub fn build(
+ mut args: impl Iterator<Item = String>,
+ ) -> Result<Config, &'static str> {
+ args.next();
+
+ let query = match args.next() {
+ Some(arg) => arg,
+ None => return Err("Didn't get a query string"),
+ };
+
+ let file_path = match args.next() {
+ Some(arg) => arg,
+ None => return Err("Didn't get a file path"),
+ };
+
+ let ignore_case = env::var("IGNORE_CASE").is_ok();
+
+ Ok(Config {
+ query,
+ file_path,
+ ignore_case,
+ })
+ }
+}
+
+pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
+ let contents = fs::read_to_string(config.file_path)?;
+
+ let results = if config.ignore_case {
+ search_case_insensitive(&config.query, &contents)
+ } else {
+ search(&config.query, &contents)
+ };
+
+ for line in results {
+ println!("{line}");
+ }
+
+ Ok(())
+}
+
+// ANCHOR: here
+pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
+ contents
+ .lines()
+ .filter(|line| line.contains(query))
+ .collect()
+}
+// ANCHOR_END: here
+
+pub fn search_case_insensitive<'a>(
+ query: &str,
+ contents: &'a str,
+) -> Vec<&'a str> {
+ let query = query.to_lowercase();
+ let mut results = Vec::new();
+
+ for line in contents.lines() {
+ if line.to_lowercase().contains(&query) {
+ results.push(line);
+ }
+ }
+
+ results
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn case_sensitive() {
+ let query = "duct";
+ let contents = "\
+Rust:
+safe, fast, productive.
+Pick three.
+Duct tape.";
+
+ assert_eq!(vec!["safe, fast, productive."], search(query, contents));
+ }
+
+ #[test]
+ fn case_insensitive() {
+ let query = "rUsT";
+ let contents = "\
+Rust:
+safe, fast, productive.
+Pick three.
+Trust me.";
+
+ assert_eq!(
+ vec!["Rust:", "Trust me."],
+ search_case_insensitive(query, contents)
+ );
+ }
+}
diff --git a/src/doc/book/listings/ch13-functional-features/listing-13-22/src/main.rs b/src/doc/book/listings/ch13-functional-features/listing-13-22/src/main.rs
new file mode 100644
index 000000000..9ac022545
--- /dev/null
+++ b/src/doc/book/listings/ch13-functional-features/listing-13-22/src/main.rs
@@ -0,0 +1,16 @@
+use std::env;
+use std::process;
+
+use minigrep::Config;
+
+fn main() {
+ let config = Config::build(env::args()).unwrap_or_else(|err| {
+ eprintln!("Problem parsing arguments: {err}");
+ process::exit(1);
+ });
+
+ if let Err(e) = minigrep::run(config) {
+ eprintln!("Application error: {e}");
+ process::exit(1);
+ }
+}