use calamine::{
deserialize_as_f64_or_none, deserialize_as_f64_or_string, open_workbook,
RangeDeserializerBuilder, Reader, Xlsx,
};
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct RowOrNone {
label: String,
#[serde(default, deserialize_with = "deserialize_as_f64_or_none")]
value: Option<f64>,
#[serde(default)]
notes: String,
}
#[derive(Debug, Deserialize)]
struct RowOrString {
label: String,
#[serde(
default = "missing_value",
deserialize_with = "deserialize_as_f64_or_string"
)]
value: Result<f64, String>,
#[serde(default)]
notes: String,
}
fn missing_value() -> Result<f64, String> {
Err(String::new())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = "tests/temperature-fallible.xlsx";
let mut workbook: Xlsx<_> = open_workbook(path)?;
let range = workbook.worksheet_range("Sheet1")?;
let rows_a: Vec<RowOrNone> = RangeDeserializerBuilder::with_deserialize_headers::<RowOrNone>()
.from_range(&range)?
.collect::<Result<_, _>>()?;
assert_eq!(rows_a[0].value, Some(22.2222));
assert_eq!(rows_a[1].value, Some(72.0));
assert_eq!(rows_a[2].value, None); assert_eq!(rows_a[3].value, None);
assert_eq!(rows_a[2].notes, "");
assert_eq!(rows_a[3].notes, "derived");
println!("or_none:");
for row in &rows_a {
println!(" {} {:?} {:?}", row.label, row.value, row.notes);
}
let rows_b: Vec<RowOrString> =
RangeDeserializerBuilder::with_deserialize_headers::<RowOrString>()
.from_range(&range)?
.collect::<Result<_, _>>()?;
assert_eq!(rows_b[0].value, Ok(22.2222));
assert_eq!(rows_b[1].value, Ok(72.0));
assert_eq!(rows_b[2].value, Err(String::new()));
assert_eq!(rows_b[3].value, Err("N/A".to_string()));
println!("or_string:");
for row in &rows_b {
println!(" {} {:?} {:?}", row.label, row.value, row.notes);
}
Ok(())
}