Shared Rust kernels

catalogue/information

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

unary · 17 lines · calc-func/src/catalogue/information.rs on GitHub
/// An eager named call of one argument.
const fn unary(
    id: FunctionId,
    spelling: &'static str,
    parameters: &'static [Parameter],
    kernel: EagerKernel,
) -> CatalogueEntry {
    CatalogueEntry {
        id,
        spelling,
        notation: Notation::Call,
        arity: CallableArityShape::exact(1),
        parameters,
        demand: ArgumentDemand::Eager,
        kernel: Kernel::Eager(kernel),
    }
}

Used by 15 functions.

scalar · 11 lines · calc-func/src/catalogue/information.rs on GitHub
/// The argument's worksheet value, or the refusal of a value no kernel here reads: an omitted
/// argument, an array (lifted or intersected by array evaluation), a callable and a number that is
/// not finite (see the module documentation).
fn scalar<'v>(site: &Site<'_>, value: &'v CalcValue) -> Step<CoreRef<'v>> {
    match value.core_ref() {
        _ if value.callable_value().is_some() => Err(site.not_modelled(Some(0))),
        CoreRef::Missing | CoreRef::Array(_) => Err(site.not_modelled(Some(0))),
        CoreRef::Number(n) if !n.is_finite() && !value.is_excel_overflow() => Err(site.not_modelled(Some(0))),
        core => Ok(core),
    }
}

Used by 15 functions.

known · 5 lines · calc-func/src/catalogue/information.rs on GitHub
/// The argument's worksheet value as [`scalar`] reads it; #BLOCKED! and #CONNECT! are errors like
/// any other (see the module documentation).
fn known<'v>(site: &Site<'_>, value: &'v CalcValue) -> Step<CoreRef<'v>> {
    scalar(site, value)
}

Used by 15 functions.

predicate · 13 lines · calc-func/src/catalogue/information.rs on GitHub
/// An IS predicate: `holds` applied to the argument's value as `read` gives it, which is not
/// converted (a number held as text is text, as Microsoft's IS functions page states). The caller
/// has dereferenced a reference to one cell, so a blank cell arrives as the empty value.
fn predicate(
    id: FunctionId,
    arguments: &[CalcValue],
    services: &EvalServices<'_>,
    read: Read,
    holds: fn(CoreRef<'_>) -> bool,
) -> Result<CalcValue, FunctionFault> {
    let site = Site::new(id, services);
    Site::finish(read(&site, &arguments[0]).map(|core| CalcValue::logical(holds(core))))
}

Used by 8 functions.

each · 27 lines · calc-func/src/catalogue/information.rs on GitHub
/// `apply` to the argument, or to each element of an array argument, giving the array of the
/// results with each element's error in its place (see the module documentation). An element
/// whose result is refused refuses the call.
fn each(
    site: &Site<'_>,
    argument: &CalcValue,
    services: &mut EvalServices<'_>,
    apply: fn(&Site<'_>, &CalcValue, &mut EvalServices<'_>) -> Step<CalcValue>,
) -> Step<CalcValue> {
    let CoreRef::Array(array) = argument.core_ref() else {
        return apply(site, argument, services);
    };
    if argument.callable_value().is_some() {
        return Err(site.not_modelled(Some(0)));
    }
    let mut cells = Vec::with_capacity(array.cell_count());
    for element in array.iter_row_major() {
        cells.push(match apply(site, element, services) {
            Ok(value) => value,
            Err(Exit::Error(code)) => CalcValue::error(code),
            Err(fault) => return Err(fault),
        });
    }
    CalcArray::new(array.shape(), cells)
        .map(CalcValue::array)
        .ok_or_else(|| site.not_modelled(Some(0)))
}

Used by 15 functions.

odd · 24 lines · calc-func/src/catalogue/information.rs on GitHub
/// Whether the argument of ISEVEN or ISODD is odd. A reference to one cell is read as the cell's
/// value; a reference of several areas is #VALUE!, and so is a range of several cells, in a legacy
/// formula placed within the range's rows (no intersection) and in a dynamic-array formula (no
/// lifting) alike.
/// The value is read as a number through worksheet coercion, number text included (Excel reads
/// text such as "2" and "1e3" both typed and in a cell), except that a logical is #VALUE!, typed
/// or in a cell, as Microsoft's page says of a value that is not numeric; a blank cell is 0 and an
/// error is the result. The magnitude plus [`PARITY_TOLERANCE`] is an arithmetic site, which
/// rounds; its truncation toward zero and the remainder by 2 are exact. Every binary64 of 2^53 or
/// more is an even integer.
fn odd(site: &Site<'_>, argument: &CalcValue, services: &mut EvalServices<'_>) -> Step<bool> {
    let value = match argument.core_ref() {
        CoreRef::Reference(reference) => match one_cell(reference) {
            Some(area) => referenced(site, area, services)?,
            None => return Err(Exit::Error(WorksheetErrorCode::Value)),
        },
        _ => argument.clone(),
    };
    let number = match scalar(site, &value)? {
        CoreRef::Logical(_) => return Err(Exit::Error(WorksheetErrorCode::Value)),
        _ => site.number_argument(0, &value)?,
    };
    Ok(site.add(number.abs(), PARITY_TOLERANCE)?.trunc() % 2.0 != 0.0)
}

Used by 2 functions.

n · 11 lines · calc-func/src/catalogue/information.rs on GitHub
/// N: a number as it is, TRUE as 1 and FALSE as 0, an error as itself, and anything else, text
/// and a blank cell among them, as 0 (Microsoft's page; a date is a number here). A reference is
/// read at the first cell of its first area, of any size: Excel loads a range given to N without
/// `@`, and reads its first cell in a legacy formula placed within the range's rows and in a
/// dynamic-array formula alike. A number Excel's handling of which is not modelled (a subnormal)
/// is refused, as the number rule refuses one, and so are #BLOCKED! and #CONNECT! (see
/// [`known`]).
fn n(arguments: &[CalcValue], services: &mut EvalServices<'_>) -> Result<CalcValue, FunctionFault> {
    let site = Site::new(N, services);
    Site::finish(each(&site, &arguments[0], services, n_of))
}

Used by 15 functions.

n_of · 22 lines · calc-func/src/catalogue/information.rs on GitHub
/// N of one argument or array element.
fn n_of(site: &Site<'_>, argument: &CalcValue, services: &mut EvalServices<'_>) -> Step<CalcValue> {
    let value = match argument.core_ref() {
        CoreRef::Reference(reference) => {
            let first = GridArea::cell(reference.areas()[0].first());
            referenced(site, first, services)?
        }
        _ => argument.clone(),
    };
    known(site, &value).and_then(|core| match core {
        CoreRef::Number(_) if value.is_excel_overflow() => Ok(value.clone()),
        CoreRef::Number(x) => site
            .argument(0, coerce::operand(x))
            .and_then(|x| site.number(x)),
        CoreRef::Logical(b) => Ok(CalcValue::number(if b { 1.0 } else { 0.0 })),
        CoreRef::Error(code) => Err(Exit::Error(code)),
        CoreRef::Text(_) | CoreRef::Empty => Ok(CalcValue::number(0.0)),
        CoreRef::Missing | CoreRef::Array(_) | CoreRef::Reference(_) => {
            Err(site.not_modelled(Some(0)))
        }
    })
}

Used by 15 functions.

one_cell · 7 lines · calc-func/src/catalogue/information.rs on GitHub
/// The one area of `reference` when it is a single cell.
fn one_cell(reference: &ReferenceLike) -> Option<GridArea> {
    match reference.areas() {
        [area] if area.cell_count() == 1 => Some(*area),
        _ => None,
    }
}

Used by 3 functions.

referenced · 17 lines · calc-func/src/catalogue/information.rs on GitHub
/// The value of the cell `area` names, as the services' cell reader supplies it: the empty value
/// for a cell it does not visit. The reference is argument 0.
fn referenced(site: &Site<'_>, area: GridArea, services: &mut EvalServices<'_>) -> Step<CalcValue> {
    let cells = reader(site, services, 0)?;
    let mut value = CalcValue::empty();
    read_reference(
        site,
        cells,
        &ReferenceLike::area(area),
        0,
        &mut |_, _, held| {
            value = held.clone();
            Ok(())
        },
    )?;
    Ok(value)
}

Used by 15 functions.