Shared Rust kernels
ported/address
All modules · quoted at commit 9e1884369a67 of DnaCalc/DnaCalc. Comments are the source's own.
address_name_character · 23 lines · calc-func/src/ported/address.rs on GitHubfn address_name_character(unit: u16, initial: bool) -> bool {
if unit < 128 {
let byte = unit as u8;
byte.is_ascii_alphabetic()
|| matches!(byte, b'_' | b'\\')
|| (!initial && (byte.is_ascii_digit() || matches!(byte, b'.' | b'?')))
} else if unit < 256 {
// Excel's legacy name classes are distinct from Unicode alphabetic
// categories (for example multiplication and division signs qualify).
matches!(unit, 0xA1 | 0xA4 | 0xA7 | 0xA8 | 0xAA | 0xAD | 0xAF..=0xBA | 0xBC..=0xFF)
} else if (0xD800..=0xDFFF).contains(&unit) {
// Classification is by UTF-16 unit, even for isolated surrogates.
!initial || unit <= 0xDBFF
} else {
let ranges = if initial {
address_name_classes::NAME_START
} else {
address_name_classes::NAME_CONTINUE
};
let index = ranges.partition_point(|&(_, end)| end < unit);
ranges.get(index).is_some_and(|&(start, _)| start <= unit)
}
}
Used by 6 functions.
address_name_is_reference · 35 lines · calc-func/src/ported/address.rs on GitHubfn address_name_is_reference(units: &[u16]) -> bool {
use super::a1_refs::{A1ReferenceNotation, parse_a1_reference};
// Reference tokens are ASCII. Lossy conversion here affects no emitted
// text and cannot turn a non-ASCII unit into an ASCII reference character.
let name = String::from_utf16_lossy(units).to_ascii_uppercase();
if let Some(reference) = parse_a1_reference(&name) {
if reference.notation == A1ReferenceNotation::Rect
&& reference.end_row <= 1_048_576
&& reference.end_col <= 16_384
{
return true;
}
}
if matches!(name.as_str(), "R" | "C" | "RC" | "TRUE" | "FALSE") {
return true;
}
// Defined-name ambiguity uses a leading R1C1 axis token. A dot immediately
// after its digits instead makes a dotted name token. The suffix need not
// itself form a reference (R1foo and C1R0 still require quoting).
let (rest, limit) = if let Some(rest) = name.strip_prefix("RC") {
(rest, 16_384)
} else if let Some(rest) = name.strip_prefix('R') {
(rest, 1_048_576)
} else if let Some(rest) = name.strip_prefix('C') {
(rest, 16_384)
} else {
return false;
};
let count = rest.bytes().take_while(u8::is_ascii_digit).count();
count > 0
&& !rest[count..].starts_with('.')
&& rest[..count]
.parse::<u32>()
.is_ok_and(|number| (1..=limit).contains(&number))
}
Used by 6 functions.
quote_sheet_text_if_needed · 44 lines · calc-func/src/ported/address.rs on GitHubpub(crate) fn quote_sheet_text_if_needed(
sheet_text: &ExcelText,
) -> Result<Vec<u16>, WorksheetErrorCode> {
let units = sheet_text.utf16_code_units();
let escaped_len = units.len() + units.iter().filter(|&&unit| unit == 39).count();
if units.len() > 255 || escaped_len > 256 {
return Err(WorksheetErrorCode::Value);
}
let simple_token = |token: &[u16]| {
token
.iter()
.enumerate()
.all(|(index, &unit)| address_name_character(unit, index == 0))
};
let simple = if units.is_empty() {
true
} else if units[0] == 91 {
units
.iter()
.position(|&unit| unit == 93)
.is_some_and(|end| {
end > 1
&& units[1..end]
.iter()
.all(|&unit| address_name_character(unit, false))
&& simple_token(&units[end + 1..])
})
} else {
simple_token(units) && !address_name_is_reference(units)
};
if simple {
return Ok(units.to_vec());
}
let mut quoted = Vec::with_capacity(escaped_len + 2);
quoted.push(39);
for &unit in units {
quoted.push(unit);
if unit == 39 {
quoted.push(39);
}
}
quoted.push(39);
Ok(quoted)
}
Used by 6 functions.