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 GitHub
fn 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 GitHub
fn 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 GitHub
fn 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 GitHub
fn 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 GitHub
fn 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.