Shared Rust kernels

catalogue/logical

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

logicals · 18 lines · calc-func/src/catalogue/logical.rs on GitHub
/// An eager named call that takes 1 to `most` logicals, values or references, the last parameter
/// repeating.
const fn logicals(
    id: FunctionId,
    spelling: &'static str,
    most: usize,
    kernel: EagerKernel,
) -> CatalogueEntry {
    CatalogueEntry {
        id,
        spelling,
        notation: Notation::Call,
        arity: CallableArityShape::range(1, most),
        parameters: LOGICALS,
        demand: ArgumentDemand::Eager,
        kernel: Kernel::Eager(kernel),
    }
}

Used by 3 functions.

constant · 12 lines · calc-func/src/catalogue/logical.rs on GitHub
/// An eager named call that takes no argument.
const fn constant(id: FunctionId, spelling: &'static str, kernel: EagerKernel) -> CatalogueEntry {
    CatalogueEntry {
        id,
        spelling,
        notation: Notation::Call,
        arity: CallableArityShape::exact(0),
        parameters: &[],
        demand: ArgumentDemand::Eager,
        kernel: Kernel::Eager(kernel),
    }
}

Used by 2 functions.

decide · 17 lines · calc-func/src/catalogue/logical.rs on GitHub
/// The result of the entry `id` on `arguments`: the first error met in the reading order, #VALUE!
/// when no logical is read, and otherwise the logical `rule` gives the tally.
fn decide(
    id: FunctionId,
    arguments: &[CalcValue],
    services: &mut EvalServices<'_>,
    rule: fn(&Tally) -> bool,
) -> Result<CalcValue, FunctionFault> {
    let site = Site::new(id, services);
    Site::finish(tally(&site, arguments, services).and_then(|tally| {
        if tally.logicals == 0 {
            Err(Exit::Error(WorksheetErrorCode::Value))
        } else {
            Ok(CalcValue::logical(rule(&tally)))
        }
    }))
}

Used by 3 functions.

tally · 37 lines · calc-func/src/catalogue/logical.rs on GitHub
/// Reads every argument in the two passes of the module documentation and counts the logicals;
/// stops at the first error or refusal.
fn tally(site: &Site<'_>, arguments: &[CalcValue], services: &mut EvalServices<'_>) -> Step<Tally> {
    let mut tally = Tally::default();
    let mut take = |logical: Option<bool>| {
        if let Some(logical) = logical {
            tally.logicals += 1;
            tally.trues += u64::from(logical);
        }
    };
    for (index, argument) in arguments.iter().enumerate() {
        if !matches!(
            argument.core_ref(),
            CoreRef::Reference(_) | CoreRef::Array(_)
        ) {
            take(direct(site, index, argument)?);
        }
    }
    for (index, argument) in arguments.iter().enumerate() {
        match argument.core_ref() {
            CoreRef::Reference(reference) => {
                let cells = reader(site, services, index)?;
                read_reference(site, cells, reference, index, &mut |_, _, value| {
                    take(held(site, index, value)?);
                    Ok(())
                })?;
            }
            CoreRef::Array(array) => {
                for element in array.iter_row_major() {
                    take(held(site, index, element)?);
                }
            }
            _ => {}
        }
    }
    Ok(tally)
}

Used by 3 functions.

direct · 14 lines · calc-func/src/catalogue/logical.rs on GitHub
/// A direct argument, at `index`, as a logical, or `None` when it is skipped.
fn direct(site: &Site<'_>, index: usize, value: &CalcValue) -> Step<Option<bool>> {
    not_callable(site, index, value)?;
    match value.core_ref() {
        CoreRef::Number(n) => site
            .argument(index, coerce::operand(n))
            .map(|n| Some(n != 0.0)),
        CoreRef::Logical(b) => Ok(Some(b)),
        CoreRef::Text(text) => Ok(coerce::spelled_logical(text)),
        CoreRef::Missing | CoreRef::Empty => Ok(Some(false)),
        CoreRef::Error(code) => Err(Exit::Error(code)),
        CoreRef::Array(_) | CoreRef::Reference(_) => Err(site.not_modelled(Some(index))),
    }
}

Used by 3 functions.

held · 14 lines · calc-func/src/catalogue/logical.rs on GitHub
/// A value that a reference or an array at `index` holds, as a logical, or `None` when it is
/// skipped.
fn held(site: &Site<'_>, index: usize, value: &CalcValue) -> Step<Option<bool>> {
    not_callable(site, index, value)?;
    match value.core_ref() {
        CoreRef::Number(n) => site
            .argument(index, coerce::operand(n))
            .map(|n| Some(n != 0.0)),
        CoreRef::Logical(b) => Ok(Some(b)),
        CoreRef::Text(_) | CoreRef::Empty | CoreRef::Missing => Ok(None),
        CoreRef::Error(code) => Err(Exit::Error(code)),
        CoreRef::Array(_) | CoreRef::Reference(_) => Err(site.not_modelled(Some(index))),
    }
}

Used by 3 functions.

not_callable · 9 lines · calc-func/src/catalogue/logical.rs on GitHub
/// Refuses a callable at `index` as not modelled: its worksheet-visible core is #CALC!, but it is
/// no worksheet error until it reaches a cell.
fn not_callable(site: &Site<'_>, index: usize, value: &CalcValue) -> Step<()> {
    if value.callable_value().is_some() {
        Err(site.not_modelled(Some(index)))
    } else {
        Ok(())
    }
}

Used by 4 functions.