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