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