1 use std::{env, error::Error, io, process};
2 
3 use serde::{Deserialize, Serialize};
4 
5 // Unlike previous examples, we derive both Deserialize and Serialize. This
6 // means we'll be able to automatically deserialize and serialize this type.
7 #[derive(Debug, Deserialize, Serialize)]
8 #[serde(rename_all = "PascalCase")]
9 struct Record {
10     city: String,
11     state: String,
12     population: Option<u64>,
13     latitude: f64,
14     longitude: f64,
15 }
16 
run() -> Result<(), Box<dyn Error>>17 fn run() -> Result<(), Box<dyn Error>> {
18     // Get the query from the positional arguments.
19     // If one doesn't exist or isn't an integer, return an error.
20     let minimum_pop: u64 = match env::args().nth(1) {
21         None => return Err(From::from("expected 1 argument, but got none")),
22         Some(arg) => arg.parse()?,
23     };
24 
25     // Build CSV readers and writers to stdin and stdout, respectively.
26     // Note that we don't need to write headers explicitly. Since we're
27     // serializing a custom struct, that's done for us automatically.
28     let mut rdr = csv::Reader::from_reader(io::stdin());
29     let mut wtr = csv::Writer::from_writer(io::stdout());
30 
31     // Iterate over all the records in `rdr`, and write only records containing
32     // a population that is greater than or equal to `minimum_pop`.
33     for result in rdr.deserialize() {
34         // Remember that when deserializing, we must use a type hint to
35         // indicate which type we want to deserialize our record into.
36         let record: Record = result?;
37 
38         // `map_or` is a combinator on `Option`. It take two parameters:
39         // a value to use when the `Option` is `None` (i.e., the record has
40         // no population count) and a closure that returns another value of
41         // the same type when the `Option` is `Some`. In this case, we test it
42         // against our minimum population count that we got from the command
43         // line.
44         if record.population.map_or(false, |pop| pop >= minimum_pop) {
45             wtr.serialize(record)?;
46         }
47     }
48 
49     // CSV writers use an internal buffer, so we should always flush when done.
50     wtr.flush()?;
51     Ok(())
52 }
53 
main()54 fn main() {
55     if let Err(err) = run() {
56         println!("{}", err);
57         process::exit(1);
58     }
59 }
60