Parse CSV Records into Serde Structs

Deserialize CSV records into typed Serde structs with header mapping, numeric parsing, and an error on negative quantities.

RustData Integrity

Code

snippet
use serde::Deserialize;
use std::error::Error;
use std::io;

#[derive(Debug, Deserialize, PartialEq)]
struct InventoryRow {
    sku: String,
    quantity: u32,
    price_cents: u32,
}

fn parse_inventory(csv_data: &str) -> Result<Vec<InventoryRow>, Box<dyn Error>> {
    let mut reader = csv::ReaderBuilder::new()
        .trim(csv::Trim::All)
        .from_reader(io::Cursor::new(csv_data));

    let mut rows = Vec::new();
    for record in reader.deserialize() {
        let row: InventoryRow = record?;
        rows.push(row);
    }
    Ok(rows)
}

fn main() -> Result<(), Box<dyn Error>> {
    let data = "sku,quantity,price_cents\nA-1,5,1200\nB-2,3,800\n";
    let rows = parse_inventory(data)?;
    println!("{} rows, first={:?}", rows.len(), rows.first());
    assert_eq!(rows.len(), 2);
    assert_eq!(
        rows[0],
        InventoryRow {
            sku: "A-1".into(),
            quantity: 5,
            price_cents: 1200,
        }
    );

    let bad = "sku,quantity,price_cents\nA-1,-5,1200\n";
    assert!(parse_inventory(bad).is_err(), "negative quantity must fail");
    Ok(())
}