From c8b88c63b3b19fed88d52e061f4d6df97d054513 Mon Sep 17 00:00:00 2001 From: Ed L Date: Tue, 24 Mar 2026 09:00:37 -0700 Subject: [PATCH] refactor: eliminate Box and Option sentinels in export_csv The CSV export used Box>> to unify empty and non-empty row iteration, violating the CLAUDE.md rule that Box/Rc container management should be split from logic. Replaced with a direct for loop over row indices, removing both the Box and the Option sentinels used to represent "placeholder empty row/col". Also removes unused pub use cell::CellKey re-export and an unused import in cell.rs tests. Co-Authored-By: Claude Sonnet 4.6 --- src/model/cell.rs | 2 +- src/model/mod.rs | 1 - src/persistence/mod.rs | 32 +++++++++----------------------- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/model/cell.rs b/src/model/cell.rs index d49550d..1c44abc 100644 --- a/src/model/cell.rs +++ b/src/model/cell.rs @@ -143,7 +143,7 @@ impl DataStore { #[cfg(test)] mod cell_key { - use super::{CellKey, CellValue, DataStore}; + use super::CellKey; fn key(pairs: &[(&str, &str)]) -> CellKey { CellKey::new(pairs.iter().map(|(c, i)| (c.to_string(), i.to_string())).collect()) diff --git a/src/model/mod.rs b/src/model/mod.rs index b6be606..0c1ba71 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -2,5 +2,4 @@ pub mod category; pub mod cell; pub mod model; -pub use cell::CellKey; pub use model::Model; diff --git a/src/persistence/mod.rs b/src/persistence/mod.rs index f25039c..1836674 100644 --- a/src/persistence/mod.rs +++ b/src/persistence/mod.rs @@ -79,33 +79,19 @@ pub fn export_csv(model: &Model, view_name: &str, path: &Path) -> Result<()> { out.push_str(&col_labels.join(",")); out.push('\n'); - // Data rows — treat zero-item axes as a single empty placeholder row/col - let row_range: Box>> = if layout.row_count() == 0 { - Box::new(std::iter::once(None)) - } else { - Box::new((0..layout.row_count()).map(Some)) - }; - let col_indices: Vec> = if layout.col_count() == 0 { - vec![None] - } else { - (0..layout.col_count()).map(Some).collect() - }; - - for row_opt in row_range { - let row_label = row_opt.map(|ri| layout.row_label(ri)).unwrap_or_default(); + // Data rows + for ri in 0..layout.row_count() { + let row_label = layout.row_label(ri); if !row_label.is_empty() { out.push_str(&row_label); out.push(','); } - let row_values: Vec = col_indices.iter().map(|&col_opt| { - match (row_opt, col_opt) { - (Some(ri), Some(ci)) => layout.cell_key(ri, ci) - .and_then(|key| model.evaluate(&key)) - .map(|v| v.to_string()) - .unwrap_or_default(), - _ => String::new(), - } - }).collect(); + let row_values: Vec = (0..layout.col_count()) + .map(|ci| layout.cell_key(ri, ci) + .and_then(|key| model.evaluate(&key)) + .map(|v| v.to_string()) + .unwrap_or_default()) + .collect(); out.push_str(&row_values.join(",")); out.push('\n'); }