csv

Function invalid_option

Source
pub fn invalid_option<'de, D, T>(de: D) -> Result<Option<T>, D::Error>
where D: Deserializer<'de>, Option<T>: Deserialize<'de>,
Expand description

A custom Serde deserializer for possibly invalid Option<T> fields.

When deserializing CSV data, it is sometimes desirable to simply ignore fields with invalid data. For example, there might be a field that is usually a number, but will occasionally contain garbage data that causes number parsing to fail.

You might be inclined to use, say, Option<i32> for fields such at this. By default, however, Option<i32> will either capture empty fields with None or valid numeric fields with Some(the_number). If the field is non-empty and not a valid number, then deserialization will return an error instead of using None.

This function allows you to override this default behavior. Namely, if Option<T> is deserialized with non-empty but invalid data, then the value will be None and the error will be ignored.

ยงExample

This example shows how to parse CSV records with numerical data, even if some numerical data is absent or invalid. Without the serde(deserialize_with = "...") annotations, this example would return an error.

use std::error::Error;

#[derive(Debug, serde::Deserialize, Eq, PartialEq)]
struct Row {
    #[serde(deserialize_with = "csv::invalid_option")]
    a: Option<i32>,
    #[serde(deserialize_with = "csv::invalid_option")]
    b: Option<i32>,
    #[serde(deserialize_with = "csv::invalid_option")]
    c: Option<i32>,
}

fn example() -> Result<(), Box<dyn Error>> {
    let data = "\
a,b,c
5,\"\",xyz
";
    let mut rdr = csv::Reader::from_reader(data.as_bytes());
    if let Some(result) = rdr.deserialize().next() {
        let record: Row = result?;
        assert_eq!(record, Row { a: Some(5), b: None, c: None });
        Ok(())
    } else {
        Err(From::from("expected at least one record but got none"))
    }
}