Shared Rust kernels
catalogue/host_facts
All modules · quoted at commit 9e1884369a67 of DnaCalc/DnaCalc. Comments are the source's own.
first_cell · 7 lines · calc-func/src/catalogue/host_facts.rs on GitHub/// The first cell of a reference argument.
fn first_cell(site: &Site<'_>, a: &[CalcValue], index: usize) -> Step<CellKey> {
match a[index].core_ref() {
CoreRef::Reference(reference) => Ok(reference.areas()[0].first()),
_ => Err(site.not_modelled(Some(index))),
}
}
Used by 5 functions.
cell_value · 11 lines · calc-func/src/catalogue/host_facts.rs on GitHub/// The value of one cell, read through the services' cell reader.
fn cell_value(site: &Site<'_>, cell: CellKey, index: usize, sv: &mut EvalServices<'_>) -> Step<CalcValue> {
let one = [CalcValue::reference(ReferenceLike::cell(cell))];
let g = grid(site, &one, 0, sv).map_err(|exit| match exit {
Exit::Fault(crate::call::FunctionFault::ReferenceUnreadable { id, .. }) => {
Exit::Fault(crate::call::FunctionFault::ReferenceUnreadable { id, index })
}
other => other,
})?;
Ok(g.cells.into_iter().next().unwrap_or_else(CalcValue::empty))
}
Used by 5 functions.
column_letters · 9 lines · calc-func/src/catalogue/host_facts.rs on GitHubfn column_letters(mut column: u32) -> String {
let mut letters = Vec::new();
while column > 0 {
let rem = (column - 1) % 26;
letters.push((b'A' + rem as u8) as char);
column = (column - 1) / 26;
}
letters.iter().rev().collect()
}
Used by 5 functions.
facts · 10 lines · calc-func/src/catalogue/host_facts.rs on GitHub/// The host's workbook facts, or a refusal of the call naming argument `index`.
fn facts(
site: &Site<'_>,
sv: &mut EvalServices<'_>,
index: Option<usize>,
) -> Step<Arc<dyn WorkbookFacts>> {
sv.host()
.and_then(|host| host.workbook_facts())
.ok_or_else(|| site.not_modelled(index))
}
Used by 5 functions.
qualified_sheet · 19 lines · calc-func/src/catalogue/host_facts.rs on GitHub/// `[file]Sheet` of `sheet`, quoted as a reference names it when it must be
/// (`'[my-book.xlsx]My Sheet'`).
fn qualified_sheet(
site: &Site<'_>,
sheet: SheetId,
sv: &mut EvalServices<'_>,
index: usize,
) -> Step<String> {
let file = facts(site, sv, Some(index))?
.file()
.ok_or_else(|| site.not_modelled(Some(index)))?;
let name = sv
.host()
.and_then(|host| host.sheet_name(sheet))
.ok_or_else(|| site.not_modelled(Some(index)))?;
let text = ExcelText::from_interop_assignment(&format!("[{}]{}", file.name, name));
let quoted = address::quote_sheet_text_if_needed(&text).map_err(Exit::Error)?;
Ok(String::from_utf16_lossy("ed))
}
Used by 5 functions.
cell · 127 lines · calc-func/src/catalogue/host_facts.rs on GitHub/// CELL (dc-uar). The info type is matched without regard to case and is not trimmed
/// (`CELL(" format ",B2)` is #VALUE!). Without a reference CELL reads the active cell of the
/// active sheet, as Excel does when it calculates a workbook it opened (measured: a file saved
/// with Second!D7 active gives `[o.xlsx]Second!$D$7` for `CELL("address")` on Sheet1). The
/// readings behind each type, Excel 16.0.20527 through COM, 2026-10-29 (the dcuar_cell rows):
/// - `address`: `$B$3` on the calling sheet, `[book.xlsx]Sheet2!$B$3` on another, quoted as a
/// reference to it would be.
/// - `filename`: the folder, `[file]` and the sheet's name; empty text for a workbook never
/// saved.
/// - `format`, `color`, `parentheses`: the number format's class ([`cell_info::classify`]).
/// - `prefix`: for a cell holding a text constant, `"` when right aligned, `^` when centred
/// (centre, centre across selection), `\` for fill, and `'` for any other alignment (general,
/// left, justify, distributed); empty text for any other cell (a formula, a number, a logical,
/// an error, a blank cell).
/// - `protect`: 1 for a locked cell, 0 otherwise (hidden does not count).
/// - `width`: the column's width rounded to a whole number of characters, 0 for a hidden column,
/// with whether it is the sheet's default width: the array {width, default}, which a legacy
/// formula intersects to the width.
fn cell(site: &Site<'_>, a: &[CalcValue], sv: &mut EvalServices<'_>) -> Step<CalcValue> {
let info = text_arg(site, a, 0)?.to_string_lossy().to_ascii_lowercase();
let known = [
"address", "row", "col", "contents", "type", "filename", "format", "color",
"parentheses", "prefix", "protect", "width",
];
if !known.contains(&info.as_str()) {
return fail(WorksheetErrorCode::Value);
}
let at = if a.len() < 2 || a[1].is_missing() {
facts(site, sv, None)?
.active_cell()
.ok_or_else(|| site.not_modelled(None))?
} else {
let at = first_cell(site, a, 1)?;
// dc-ylr: Excel gives CELL of a reference to a closed workbook #N/A.
if sv.host().is_some_and(|host| host.is_external_sheet(at.sheet())) {
return fail(WorksheetErrorCode::NA);
}
at
};
let format = |site: &Site<'_>, sv: &mut EvalServices<'_>| -> Step<CellFormatFacts> {
facts(site, sv, Some(1))?
.cell_format(at)
.ok_or_else(|| site.not_modelled(Some(1)))
};
let class = |site: &Site<'_>, sv: &mut EvalServices<'_>| -> Step<cell_info::FormatClass> {
let facts = format(site, sv)?;
let profile = sv
.environment()
.and_then(|environment| environment.profile)
.ok_or_else(|| site.not_modelled(Some(1)))?;
Ok(cell_info::classify(&facts.number_format, facts.builtin, &profile))
};
let text = crate::catalogue::kit::text_value;
match info.as_str() {
"row" => s_number(site, at.row() as f64),
"col" => s_number(site, at.column() as f64),
"address" => {
let caller = sv.host().and_then(|host| host.caller());
let local = format!("${}${}", column_letters(at.column()), at.row());
match caller {
Some(caller) if caller.sheet() == at.sheet() => Ok(text(&local)),
Some(_) => {
let sheet = qualified_sheet(site, at.sheet(), sv, 1)?;
Ok(text(&format!("{sheet}!{local}")))
}
None => Err(site.not_modelled(Some(1))),
}
}
"filename" => {
let file = facts(site, sv, Some(1))?
.file()
.ok_or_else(|| site.not_modelled(Some(1)))?;
let Some(folder) = file.folder else {
return Ok(text(""));
};
let name = sv
.host()
.and_then(|host| host.sheet_name(at.sheet()))
.ok_or_else(|| site.not_modelled(Some(1)))?;
Ok(text(&format!("{folder}[{}]{name}", file.name)))
}
"contents" => cell_value(site, at, 1, sv),
"type" => {
let value = cell_value(site, at, 1, sv)?;
let kind = match value.core_ref() {
CoreRef::Empty | CoreRef::Missing => "b",
CoreRef::Text(_) => "l",
_ => "v",
};
Ok(text(kind))
}
"format" => Ok(text(&class(site, sv)?.code)),
"color" => s_number(site, if class(site, sv)?.color { 1.0 } else { 0.0 }),
"parentheses" => s_number(site, if class(site, sv)?.parentheses { 1.0 } else { 0.0 }),
"protect" => s_number(site, if format(site, sv)?.locked { 1.0 } else { 0.0 }),
"prefix" => {
let formula = sv
.host()
.and_then(|host| host.is_formula(at))
.ok_or_else(|| site.not_modelled(Some(1)))?;
let value = cell_value(site, at, 1, sv)?;
if formula || !matches!(value.core_ref(), CoreRef::Text(_)) {
return Ok(text(""));
}
let prefix = match format(site, sv)?.horizontal {
HorizontalAlignment::Right => "\"",
HorizontalAlignment::Center | HorizontalAlignment::CenterContinuous => "^",
HorizontalAlignment::Fill => "\\",
_ => "'",
};
Ok(text(prefix))
}
"width" => {
let width = facts(site, sv, Some(1))?
.column_width(at.sheet(), at.column())
.ok_or_else(|| site.not_modelled(Some(1)))?;
let rounded = (width.characters + 0.5).floor();
CalcArray::from_rows(vec![vec![
CalcValue::number(rounded),
CalcValue::logical(width.default),
]])
.map(CalcValue::array)
.ok_or_else(|| site.not_modelled(None))
}
_ => Err(site.not_modelled(Some(0))),
}
}
Used by 5 functions.
s_number · 3 lines · calc-func/src/catalogue/host_facts.rs on GitHubfn s_number(site: &Site<'_>, n: f64) -> Step<CalcValue> {
site.number(n)
}
Used by 5 functions.
info · 59 lines · calc-func/src/catalogue/host_facts.rs on GitHub/// INFO (dc-uar). The type is matched without regard to case and is not trimmed. Measured in
/// Excel 16.0.20527 through COM, 2026-10-29: `directory` is the current folder; `numfile` the
/// number of worksheets (a hidden one counts, a chart sheet does not); `origin` `$A:` and the
/// top left cell of the calling sheet's window (`$A:$C$5` for a sheet saved scrolled to C5);
/// `osversion`, `release` and `system` the application's facts (`Windows (64-bit) NT 10.00`,
/// `16.0`, `pcdos`); `recalc` `Automatic` or `Manual` (automatic except tables gives
/// `Automatic`); `memavail`, `memused` and `totmem` are #N/A; any other text is #VALUE!.
fn info(site: &Site<'_>, a: &[CalcValue], sv: &mut EvalServices<'_>) -> Step<CalcValue> {
let kind = text_arg(site, a, 0)?.to_string_lossy().to_ascii_lowercase();
let text = |value: Option<String>| -> Step<CalcValue> {
value
.map(|value| crate::catalogue::kit::text_value(&value))
.ok_or_else(|| site.not_modelled(Some(0)))
};
match kind.as_str() {
"memavail" | "memused" | "totmem" => fail(WorksheetErrorCode::NA),
"numfile" => match sv.host().and_then(|host| host.sheet_count()) {
Some(count) => site.number(f64::from(count)),
None => Err(site.not_modelled(Some(0))),
},
"origin" => {
let sheet = sv
.host()
.and_then(|host| host.caller())
.map(|caller| caller.sheet())
.ok_or_else(|| site.not_modelled(Some(0)))?;
let cell = facts(site, sv, Some(0))?
.top_left_cell(sheet)
.ok_or_else(|| site.not_modelled(Some(0)))?;
text(Some(format!(
"$A:${}${}",
column_letters(cell.column()),
cell.row()
)))
}
"recalc" => {
let mode = facts(site, sv, Some(0))?
.calculation_mode()
.ok_or_else(|| site.not_modelled(Some(0)))?;
let name = match mode {
CalculationMode::Manual => "Manual",
CalculationMode::Automatic | CalculationMode::AutomaticExceptTables => "Automatic",
};
text(Some(name.to_owned()))
}
"directory" | "osversion" | "release" | "system" => {
let application = facts(site, sv, Some(0))?
.application()
.ok_or_else(|| site.not_modelled(Some(0)))?;
text(match kind.as_str() {
"directory" => application.directory,
"osversion" => application.os_version,
"release" => application.release,
_ => application.system,
})
}
_ => fail(WorksheetErrorCode::Value),
}
}
Used by 5 functions.
sheet · 27 lines · calc-func/src/catalogue/host_facts.rs on GitHubfn sheet(site: &Site<'_>, a: &[CalcValue], sv: &mut EvalServices<'_>) -> Step<CalcValue> {
let sheet = if a.is_empty() || a[0].is_missing() {
sv.host().and_then(|host| host.caller()).map(|cell| cell.sheet())
} else {
match a[0].core_ref() {
CoreRef::Reference(reference) => Some(reference.sheet()),
CoreRef::Error(code) => return fail(code),
CoreRef::Text(text) => {
let name = text.to_string_lossy();
match sv.host() {
Some(host) => match host.sheet_named(&name) {
Some(sheet) => Some(sheet),
None if host.sheet_count().is_some() => return fail(WorksheetErrorCode::NA),
None => None,
},
None => None,
}
}
_ => return fail(WorksheetErrorCode::NA),
}
};
let index = sheet.and_then(|sheet| sv.host().and_then(|host| host.sheet_index(sheet)));
match index {
Some(index) => site.number(f64::from(index)),
None => Err(site.not_modelled(Some(0))),
}
}
Used by 5 functions.