use crate::named_ref::{is_valid_name, ParsedRef};
pub struct ParsedRangeBounds {
pub sheet: String,
pub row_start: u32,
pub row_end: u32,
pub col_start: u32,
pub col_end: u32,
}
pub fn parsed_range_bounds(r: &str, parsed: &ParsedRef) -> Option<ParsedRangeBounds> {
let a1_part = r.rsplit_once('!')?.1;
let (start_raw, end_raw) = a1_part.split_once(':')?;
let start = crate::address::parse_a1(start_raw)?;
let end = crate::address::parse_a1(end_raw)?;
Some(ParsedRangeBounds {
sheet: parsed.sheet.clone(),
row_start: start.row,
row_end: end.row,
col_start: start.column,
col_end: end.column,
})
}
pub fn ranges_overlap(a: &ParsedRangeBounds, b: &ParsedRangeBounds) -> bool {
a.sheet == b.sheet
&& a.row_start <= b.row_end
&& b.row_start <= a.row_end
&& a.col_start <= b.col_end
&& b.col_start <= a.col_end
}
pub fn header_row_columns<'a>(
header_row_cells: impl Iterator<Item = &'a str>,
) -> Result<Vec<String>, String> {
use icu_casemap::CaseMapperBorrowed;
let folder = CaseMapperBorrowed::new();
let mut seen = std::collections::HashSet::new();
let mut columns = Vec::new();
for cell in header_row_cells {
if !is_valid_name(cell) {
return Err(format!(
"table header cell {cell:?} is not a valid column name (must match \
^[A-Za-z_][A-Za-z0-9_]*$, not an A1 address, not a boolean literal)"
));
}
let folded = crate::casefold::simple_fold(&folder, cell);
if !seen.insert(folded) {
return Err(format!("duplicate table column name {cell:?}"));
}
columns.push(cell.to_string());
}
Ok(columns)
}
#[cfg(test)]
mod tests;