blob: f10cd43b9f14ea66907881f3aeeb6449c079e6a9 [file] [log] [blame]
Jakub Koturc72d7202020-12-21 17:28:15 +01001use std::env;
2use std::error::Error;
3use std::io;
4use std::process;
5
6use 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")]
12struct Record {
13 city: String,
14 state: String,
15 population: Option<u64>,
16 latitude: f64,
17 longitude: f64,
18}
19
20fn 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
57fn main() {
58 if let Err(err) = run() {
59 println!("{}", err);
60 process::exit(1);
61 }
62}