Shared Rust kernels
ported/a1_refs
All modules · quoted at commit 9e1884369a67 of DnaCalc/DnaCalc. Comments are the source's own.
split_prefix · 13 lines · calc-func/src/ported/a1_refs.rs on GitHubfn split_prefix(target: &str) -> (Option<String>, &str) {
if let Some(idx) = target.rfind('!') {
let prefix = target[..idx].trim();
let rest = target[idx + 1..].trim();
if prefix.is_empty() {
(None, rest)
} else {
(Some(prefix.to_string()), rest)
}
} else {
(None, target.trim())
}
}
Used by 6 functions.
parse_cell_token · 40 lines · calc-func/src/ported/a1_refs.rs on GitHubfn parse_cell_token(token: &str) -> Option<(usize, usize)> {
let trimmed = token.trim();
if trimmed.is_empty() {
return None;
}
let mut letters = String::new();
let mut digits = String::new();
for ch in trimmed.chars() {
if ch == '$' {
continue;
}
if ch.is_ascii_alphabetic() && digits.is_empty() {
letters.push(ch.to_ascii_uppercase());
continue;
}
if ch.is_ascii_digit() {
digits.push(ch);
continue;
}
return None;
}
if letters.is_empty() || digits.is_empty() {
return None;
}
let mut col = 0usize;
for ch in letters.chars() {
let value = usize::from((ch as u8) - b'A' + 1);
col = col.checked_mul(26)?.checked_add(value)?;
}
let row = digits.parse::<usize>().ok()?;
if row == 0 || col == 0 {
return None;
}
Some((row, col))
}
Used by 6 functions.
parse_column_token · 34 lines · calc-func/src/ported/a1_refs.rs on GitHubfn parse_column_token(token: &str) -> Option<usize> {
let trimmed = token.trim();
if trimmed.is_empty() {
return None;
}
let mut letters = String::new();
for ch in trimmed.chars() {
if ch == '$' {
continue;
}
if ch.is_ascii_alphabetic() {
letters.push(ch.to_ascii_uppercase());
continue;
}
return None;
}
if letters.is_empty() {
return None;
}
let mut col = 0usize;
for ch in letters.chars() {
let value = usize::from((ch as u8) - b'A' + 1);
col = col.checked_mul(26)?.checked_add(value)?;
}
if col == 0 || col > EXCEL_MAX_COLS {
return None;
}
Some(col)
}
Used by 6 functions.
parse_row_token · 18 lines · calc-func/src/ported/a1_refs.rs on GitHubfn parse_row_token(token: &str) -> Option<usize> {
let trimmed = token.trim();
if trimmed.is_empty() {
return None;
}
let digits: String = trimmed.chars().filter(|ch| *ch != '$').collect();
if digits.is_empty() || !digits.chars().all(|ch| ch.is_ascii_digit()) {
return None;
}
let row = digits.parse::<usize>().ok()?;
if row == 0 || row > EXCEL_MAX_ROWS {
return None;
}
Some(row)
}
Used by 6 functions.
parse_a1_reference · 59 lines · calc-func/src/ported/a1_refs.rs on GitHubpub fn parse_a1_reference(target: impl AsRef<str>) -> Option<A1Reference> {
let (prefix, body) = split_prefix(target.as_ref());
if body.is_empty() {
return None;
}
let parts: Vec<&str> = body.split(':').collect();
if parts.len() > 2 {
return None;
}
let parsed = if let Some((start_row, start_col)) = parse_cell_token(parts[0]) {
let (end_row, end_col) = if parts.len() == 2 {
parse_cell_token(parts[1])?
} else {
(start_row, start_col)
};
A1Reference {
prefix,
start_row: start_row.min(end_row),
start_col: start_col.min(end_col),
end_row: start_row.max(end_row),
end_col: start_col.max(end_col),
notation: A1ReferenceNotation::Rect,
}
} else if let Some(start_col) = parse_column_token(parts[0]) {
let end_col = if parts.len() == 2 {
parse_column_token(parts[1])?
} else {
start_col
};
A1Reference {
prefix,
start_row: 1,
start_col: start_col.min(end_col),
end_row: EXCEL_MAX_ROWS,
end_col: start_col.max(end_col),
notation: A1ReferenceNotation::WholeColumn,
}
} else if let Some(start_row) = parse_row_token(parts[0]) {
let end_row = if parts.len() == 2 {
parse_row_token(parts[1])?
} else {
start_row
};
A1Reference {
prefix,
start_row: start_row.min(end_row),
start_col: 1,
end_row: start_row.max(end_row),
end_col: EXCEL_MAX_COLS,
notation: A1ReferenceNotation::WholeRow,
}
} else {
return None;
};
Some(parsed)
}
Used by 6 functions.