use crate::error::Error;
use crate::model::{CellValue, Sheet};
use crate::parse::{PendingSharedString, SharedStringTable};
pub(crate) fn resolve(
sheet: &mut Sheet,
pending: &[PendingSharedString],
table: &SharedStringTable,
) -> Result<(), Error> {
for entry in pending {
let text = table
.get(entry.index)
.ok_or(Error::SharedStringIndexOutOfBounds {
index: entry.index,
len: table.len(),
})?;
let cell = sheet
.get_mut(entry.cell_ref)
.expect("pending shared string references a cell not inserted by parse/worksheet.rs");
cell.value = Some(CellValue::Text(text.clone()));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::model::{CellRef, SheetVisibility};
use std::sync::Arc;
fn sheet_with_pending_cell(cell_ref: CellRef) -> Sheet {
let mut sheet = Sheet::new("Sheet1".into(), SheetVisibility::Visible);
sheet.insert_cell(
cell_ref,
crate::model::Cell {
value: None,
style: None,
},
);
sheet
}
fn table(strings: &[&str]) -> SharedStringTable {
let mut xml = String::from("<sst>");
for s in strings {
xml.push_str(&format!("<si><t>{s}</t></si>"));
}
xml.push_str("</sst>");
crate::parse::parse_shared_strings(xml.as_bytes(), "xl/sharedStrings.xml").unwrap()
}
#[test]
fn resolves_valid_index_to_text() {
let cell_ref = CellRef { row: 1, col: 1 };
let mut sheet = sheet_with_pending_cell(cell_ref);
let table = table(&["hello", "world"]);
resolve(
&mut sheet,
&[PendingSharedString { cell_ref, index: 1 }],
&table,
)
.unwrap();
assert_eq!(
sheet.get(cell_ref).unwrap().value,
Some(CellValue::Text(Arc::from("world")))
);
}
#[test]
fn out_of_range_index_is_an_error() {
let cell_ref = CellRef { row: 1, col: 1 };
let mut sheet = sheet_with_pending_cell(cell_ref);
let table = table(&["only"]);
let err = resolve(
&mut sheet,
&[PendingSharedString { cell_ref, index: 1 }],
&table,
)
.unwrap_err();
assert!(matches!(
err,
Error::SharedStringIndexOutOfBounds { index: 1, len: 1 }
));
}
#[test]
fn duplicate_string_references_share_the_same_arc_allocation() {
let ref_a = CellRef { row: 1, col: 1 };
let ref_b = CellRef { row: 1, col: 2 };
let mut sheet = Sheet::new("Sheet1".into(), SheetVisibility::Visible);
sheet.insert_cell(
ref_a,
crate::model::Cell {
value: None,
style: None,
},
);
sheet.insert_cell(
ref_b,
crate::model::Cell {
value: None,
style: None,
},
);
let table = table(&["shared"]);
resolve(
&mut sheet,
&[
PendingSharedString {
cell_ref: ref_a,
index: 0,
},
PendingSharedString {
cell_ref: ref_b,
index: 0,
},
],
&table,
)
.unwrap();
let (Some(CellValue::Text(a)), Some(CellValue::Text(b))) = (
&sheet.get(ref_a).unwrap().value,
&sheet.get(ref_b).unwrap().value,
) else {
unreachable!()
};
assert!(Arc::ptr_eq(a, b));
}
#[test]
fn empty_pending_list_is_a_no_op() {
let mut sheet = Sheet::new("Sheet1".into(), SheetVisibility::Visible);
let table = table(&[]);
resolve(&mut sheet, &[], &table).unwrap();
}
}