Shared Rust kernels

ported/engineering_radix_family

All modules · quoted at commit 9e1884369a67 of DnaCalc/DnaCalc. Comments are the source's own.

upper_ascii_digit_value · 7 lines · calc-func/src/ported/engineering_radix_family.rs on GitHub
fn upper_ascii_digit_value(ch: char) -> Option<u32> {
    match ch {
        '0'..='9' => Some((ch as u8 - b'0') as u32),
        'A'..='Z' => Some((ch as u8 - b'A') as u32 + 10),
        _ => None,
    }
}

Used by 9 functions.

normalize_radix_text · 3 lines · calc-func/src/ported/engineering_radix_family.rs on GitHub
fn normalize_radix_text(text: &str) -> String {
    text.to_ascii_uppercase()
}

Used by 9 functions.

parse_radix_text · 32 lines · calc-func/src/ported/engineering_radix_family.rs on GitHub
fn parse_radix_text(text: &str, source: RadixSpec) -> Result<i64, WorksheetErrorCode> {
    let normalized = normalize_radix_text(text);
    if normalized.is_empty() {
        return Ok(0);
    }
    if normalized.len() > source.max_chars {
        return Err(WorksheetErrorCode::Num);
    }

    let mut raw: u64 = 0;
    for ch in normalized.chars() {
        let Some(digit) = upper_ascii_digit_value(ch) else {
            return Err(WorksheetErrorCode::Num);
        };
        if digit >= source.radix {
            return Err(WorksheetErrorCode::Num);
        }
        raw = raw
            .checked_mul(source.radix as u64)
            .and_then(|value| value.checked_add(digit as u64))
            .ok_or(WorksheetErrorCode::Num)?;
    }

    if normalized.len() == source.max_chars {
        let sign_mask = 1_u64 << (source.bits - 1);
        if raw & sign_mask != 0 {
            return Ok(raw as i64 - (1_i64 << source.bits));
        }
    }

    Ok(raw as i64)
}

Used by 9 functions.

normalize_places · 13 lines · calc-func/src/ported/engineering_radix_family.rs on GitHub
pub(crate) fn normalize_places(places: Option<f64>) -> Result<Option<usize>, WorksheetErrorCode> {
    match places {
        None => Ok(None),
        Some(raw) => {
            let truncated = raw.trunc();
            if !raw.is_finite() || !(1.0..=10.0).contains(&truncated) {
                Err(WorksheetErrorCode::Num)
            } else {
                Ok(Some(truncated as usize))
            }
        }
    }
}

Used by 9 functions.

min_signed_value · 3 lines · calc-func/src/ported/engineering_radix_family.rs on GitHub
fn min_signed_value(spec: RadixSpec) -> i64 {
    -(1_i64 << (spec.bits - 1))
}

Used by 9 functions.

max_signed_value · 3 lines · calc-func/src/ported/engineering_radix_family.rs on GitHub
fn max_signed_value(spec: RadixSpec) -> i64 {
    (1_i64 << (spec.bits - 1)) - 1
}

Used by 9 functions.

encode_signed_value · 35 lines · calc-func/src/ported/engineering_radix_family.rs on GitHub
fn encode_signed_value(
    value: i64,
    target: RadixSpec,
    places: Option<f64>,
) -> Result<ExcelText, WorksheetErrorCode> {
    if value < min_signed_value(target) || value > max_signed_value(target) {
        return Err(WorksheetErrorCode::Num);
    }

    // Excel validates an explicitly supplied width even when a negative value
    // always publishes its full ten-character two's-complement encoding.
    let places = normalize_places(places)?;

    if value < 0 {
        let raw = ((1_i128 << target.bits) + i128::from(value)) as f64;
        return base_kernel(raw, target.radix as f64, Some(target.max_chars as f64));
    }

    let digits = base_kernel(value as f64, target.radix as f64, None)?;
    let digits_string = digits.to_string_lossy();

    match places {
        Some(min_length) => {
            if digits_string.len() > min_length {
                Err(WorksheetErrorCode::Num)
            } else {
                let padded = format!("{digits_string:0>width$}", width = min_length);
                Ok(ExcelText::from_utf16_code_units(
                    padded.encode_utf16().collect(),
                ))
            }
        }
        None => Ok(digits),
    }
}

Used by 9 functions.

trunc_i64 · 3 lines · calc-func/src/ported/engineering_radix_family.rs on GitHub
fn trunc_i64(number: f64) -> i64 {
    number.trunc() as i64
}

Used by 3 functions.

dec_to_target_kernel · 7 lines · calc-func/src/ported/engineering_radix_family.rs on GitHub
pub(crate) fn dec_to_target_kernel(
    number: f64,
    places: Option<f64>,
    target: RadixSpec,
) -> Result<ExcelText, WorksheetErrorCode> {
    encode_signed_value(trunc_i64(number), target, places)
}

Used by 3 functions.

source_to_decimal_kernel · 6 lines · calc-func/src/ported/engineering_radix_family.rs on GitHub
pub(crate) fn source_to_decimal_kernel(
    source_text: &str,
    source: RadixSpec,
) -> Result<f64, WorksheetErrorCode> {
    parse_radix_text(source_text, source).map(|value| value as f64)
}

Used by 3 functions.

source_to_target_kernel · 9 lines · calc-func/src/ported/engineering_radix_family.rs on GitHub
pub(crate) fn source_to_target_kernel(
    source_text: &str,
    places: Option<f64>,
    source: RadixSpec,
    target: RadixSpec,
) -> Result<ExcelText, WorksheetErrorCode> {
    let decimal = parse_radix_text(source_text, source)?;
    encode_signed_value(decimal, target, places)
}

Used by 6 functions.