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