Shared Rust kernels
catalogue/text_functions
All modules · quoted at commit 9e1884369a67 of DnaCalc/DnaCalc. Comments are the source's own.
count_surrogate_pairs · 10 lines · calc-func/src/catalogue/text_functions.rs on GitHub/// Microsoft Compatibility Versions: LEN/MID/FIND/SEARCH/REPLACE change their counting.
/// https://support.microsoft.com/en-gb/excel/compatibility-versions
/// Missing legacy services retain Version 1. An explicit unsupported version is a typed refusal.
fn count_surrogate_pairs(site: &Site<'_>) -> Step<bool> {
match site.environment().map_or(1, |environment| environment.compatibility_version) {
1 => Ok(false),
2 => Ok(true),
_ => Err(site.not_modelled(None)),
}
}
Used by 9 functions.
cased · 8 lines · calc-func/src/catalogue/text_functions.rs on GitHub/// A text result of a casing kernel, refused when the text is not well-formed UTF-16.
fn cased(site: &Site<'_>, a: &[CalcValue], kernel: fn(&ExcelText) -> ExcelText) -> Step<CalcValue> {
let text = text_arg(site, a, 0)?;
if !k::is_well_formed(&text) {
return Err(site.not_modelled(Some(0)));
}
Ok(CalcValue::text(kernel(&text)))
}
Used by 3 functions.
single_byte · 12 lines · calc-func/src/catalogue/text_functions.rs on GitHub/// The byte functions (LENB, LEFTB, RIGHTB, MIDB, FINDB, SEARCHB, REPLACEB) count as their
/// character twins do (Excel 16.0.20527 under en-ZA, the catalogue's sheet dczsn3_bytes), unless
/// the language is a double-byte one, where Excel counts a double-byte character as two bytes:
/// refused under the ja-JP, ko-KR and zh-CN profiles (bead dc-zsn.3).
fn single_byte(site: &Site<'_>) -> Step<()> {
match site.environment().and_then(|e| e.profile.as_ref()) {
Some(p) if matches!(p.id, LocaleId::JaJp | LocaleId::KoKr | LocaleId::ZhCn) => {
Err(site.not_modelled(None))
}
_ => Ok(()),
}
}
Used by 7 functions.
side_count · 8 lines · calc-func/src/catalogue/text_functions.rs on GitHub/// The optional count of LEFT, RIGHT, LEFTB and RIGHTB: 1 when the call does not reach it.
fn side_count(site: &Site<'_>, a: &[CalcValue]) -> Step<usize> {
if a.len() < 2 {
return Ok(1);
}
let n = num(site, a, 1)?;
k::nonnegative_count(n, true).map_err(Exit::Error)
}
Used by 5 functions.
left · 5 lines · calc-func/src/catalogue/text_functions.rs on GitHubfn left(site: &Site<'_>, a: &[CalcValue]) -> Step<CalcValue> {
let text = text_arg(site, a, 0)?;
let count = side_count(site, a)?;
Ok(CalcValue::text(k::take_left(&text, count)))
}
Used by 3 functions.
right · 5 lines · calc-func/src/catalogue/text_functions.rs on GitHubfn right(site: &Site<'_>, a: &[CalcValue]) -> Step<CalcValue> {
let text = text_arg(site, a, 0)?;
let count = side_count(site, a)?;
Ok(CalcValue::text(k::take_right(&text, count)))
}
Used by 3 functions.
mid · 10 lines · calc-func/src/catalogue/text_functions.rs on GitHub/// Version 1 MID and every MIDB count UTF-16 units (dc-fl2 records individual surrogate halves).
/// Version 2 MID counts each valid surrogate pair once.
fn mid(site: &Site<'_>, a: &[CalcValue], bytes: bool) -> Step<CalcValue> {
let text = text_arg(site, a, 0)?;
let start = num(site, a, 1)?;
let count = num(site, a, 2)?;
let start = k::mid_start(start).map_err(Exit::Error)?;
let count = k::nonnegative_count(count, false).map_err(Exit::Error)?;
Ok(CalcValue::text(k::take_mid(&text, start, count, !bytes && count_surrogate_pairs(site)?)))
}
Used by 2 functions.
start · 11 lines · calc-func/src/catalogue/text_functions.rs on GitHub/// The optional start of FIND and SEARCH: 1 when the call does not reach it or leaves it empty.
fn start(site: &Site<'_>, a: &[CalcValue]) -> Step<usize> {
match a.get(2) {
None => Ok(1),
Some(value) if value.is_missing() => Ok(1),
Some(_) => {
let n = num(site, a, 2)?;
k::positive(n).map_err(Exit::Error)
}
}
}
Used by 8 functions.
find · 6 lines · calc-func/src/catalogue/text_functions.rs on GitHubfn find(site: &Site<'_>, a: &[CalcValue], bytes: bool) -> Step<CalcValue> {
let needle = text_arg(site, a, 0)?;
let hay = text_arg(site, a, 1)?;
let start = start(site, a)?;
out(site, k::find(&needle, &hay, start, !bytes && count_surrogate_pairs(site)?))
}
Used by 2 functions.
search · 6 lines · calc-func/src/catalogue/text_functions.rs on GitHubfn search(site: &Site<'_>, a: &[CalcValue], bytes: bool) -> Step<CalcValue> {
let needle = text_arg(site, a, 0)?;
let hay = text_arg(site, a, 1)?;
let start = start(site, a)?;
out(site, k::search(&needle, &hay, start, !bytes && count_surrogate_pairs(site)?))
}
Used by 2 functions.
replace · 9 lines · calc-func/src/catalogue/text_functions.rs on GitHubfn replace(site: &Site<'_>, a: &[CalcValue], bytes: bool) -> Step<CalcValue> {
let old = text_arg(site, a, 0)?;
let start = num(site, a, 1)?;
let start = k::positive(start).map_err(Exit::Error)?;
let count = num(site, a, 2)?;
let count = k::nonnegative(count).map_err(Exit::Error)?;
let new = text_arg(site, a, 3)?;
capped(k::replace(&old, start, count, &new, !bytes && count_surrogate_pairs(site)?), WorksheetErrorCode::Value)
}
Used by 2 functions.
capped · 7 lines · calc-func/src/catalogue/text_functions.rs on GitHub/// A text result, or `code` when it is longer than a cell holds.
fn capped(text: ExcelText, code: WorksheetErrorCode) -> Step<CalcValue> {
if text.len_utf16_code_units() > EXCEL_TEXT_MAX_UTF16_CODE_UNITS {
return fail(code);
}
Ok(CalcValue::text(text))
}
Used by 3 functions.
cells · 5 lines · calc-func/src/catalogue/text_functions.rs on GitHub/// The cells an argument of CONCAT or TEXTJOIN gives, in row-major order: a reference's cells
/// (a blank cell as Empty) or an array's elements, or the argument itself.
fn cells(site: &Site<'_>, a: &[CalcValue], index: usize, sv: &mut crate::call::EvalServices<'_>) -> Step<Grid> {
grid(site, a, index, sv)
}
Used by 2 functions.
cell_text · 7 lines · calc-func/src/catalogue/text_functions.rs on GitHub/// One cell's text for CONCAT and TEXTJOIN.
fn cell_text(site: &Site<'_>, index: usize, value: &CalcValue) -> Step<Vec<u16>> {
if value.callable_value().is_some() || matches!(value.core_ref(), CoreRef::Array(_) | CoreRef::Reference(_)) {
return Err(site.not_modelled(Some(index)));
}
Ok(site.argument(index, coerce::text(value))?.into_owned())
}
Used by 3 functions.