use df_derive::ToDataFrame;
use df_derive::dataframe;
use df_derive::dataframe::ToDataFrameVec;
#[derive(ToDataFrame, Clone)]
struct Sample {
id: u32,
#[allow(clippy::option_option)]
counts: Option<Option<Vec<i32>>>,
#[allow(clippy::option_option)]
readings: Option<Option<Vec<Option<i64>>>>,
}
fn main() -> polars::prelude::PolarsResult<()> {
let samples = vec![
Sample {
id: 1,
counts: Some(Some(vec![10, 20, 30])),
readings: Some(Some(vec![Some(100), None, Some(300)])),
},
Sample {
id: 2,
counts: Some(Some(vec![])),
readings: Some(Some(vec![])),
},
Sample {
id: 3,
counts: Some(None),
readings: Some(None),
},
Sample {
id: 4,
counts: None,
readings: None,
},
];
let df = samples.as_slice().to_dataframe()?;
println!("Multi-Option-over-Vec DataFrame:");
println!("{df}");
let schema = <Sample as dataframe::ToDataFrame>::schema()?;
println!("\nSchema (consecutive Options collapse to one list-level validity bit):");
for (name, dtype) in schema {
println!(" {name}: {dtype:?}");
}
println!(
"\nRows 3 (Some(None)) and 4 (None) both surface as the same null cell — \
Polars carries one validity bit per nullable level, so the two source \
values are indistinguishable in the column.",
);
Ok(())
}