| use std::{env, error::Error, io, process}; | |
| use serde::{Deserialize, Serialize}; | |
| // Unlike previous examples, we derive both Deserialize and Serialize. This | |
| // means we'll be able to automatically deserialize and serialize this type. | |
| #[derive(Debug, Deserialize, Serialize)] | |
| #[serde(rename_all = "PascalCase")] | |
| struct Record { | |
| city: String, | |
| state: String, | |
| population: Option<u64>, | |
| latitude: f64, | |
| longitude: f64, | |
| } | |
| fn run() -> Result<(), Box<dyn Error>> { | |
| // Get the query from the positional arguments. | |
| // If one doesn't exist or isn't an integer, return an error. | |
| let minimum_pop: u64 = match env::args().nth(1) { | |
| None => return Err(From::from("expected 1 argument, but got none")), | |
| Some(arg) => arg.parse()?, | |
| }; | |
| // Build CSV readers and writers to stdin and stdout, respectively. | |
| // Note that we don't need to write headers explicitly. Since we're | |
| // serializing a custom struct, that's done for us automatically. | |
| let mut rdr = csv::Reader::from_reader(io::stdin()); | |
| let mut wtr = csv::Writer::from_writer(io::stdout()); | |
| // Iterate over all the records in `rdr`, and write only records containing | |
| // a population that is greater than or equal to `minimum_pop`. | |
| for result in rdr.deserialize() { | |
| // Remember that when deserializing, we must use a type hint to | |
| // indicate which type we want to deserialize our record into. | |
| let record: Record = result?; | |
| // `map_or` is a combinator on `Option`. It take two parameters: | |
| // a value to use when the `Option` is `None` (i.e., the record has | |
| // no population count) and a closure that returns another value of | |
| // the same type when the `Option` is `Some`. In this case, we test it | |
| // against our minimum population count that we got from the command | |
| // line. | |
| if record.population.map_or(false, |pop| pop >= minimum_pop) { | |
| wtr.serialize(record)?; | |
| } | |
| } | |
| // CSV writers use an internal buffer, so we should always flush when done. | |
| wtr.flush()?; | |
| Ok(()) | |
| } | |
| fn main() { | |
| if let Err(err) = run() { | |
| println!("{}", err); | |
| process::exit(1); | |
| } | |
| } |