formualizer-workbook 0.5.3

Ergonomic workbook API over the Formualizer engine (sheets, loaders, staging, undo/redo)
Documentation
use formualizer_common::LiteralValue;
use formualizer_common::error::{ExcelError, ExcelErrorKind};
use formualizer_workbook::{CustomFnOptions, Workbook};
use std::sync::Arc;

fn as_f64(value: &LiteralValue) -> f64 {
    match value {
        LiteralValue::Int(v) => *v as f64,
        LiteralValue::Number(v) => *v,
        _ => 0.0,
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut wb = Workbook::new();
    wb.add_sheet("Sheet1")?;

    wb.set_values(
        "Sheet1",
        1,
        1,
        &[
            vec![LiteralValue::Number(10.0), LiteralValue::Number(20.0)],
            vec![LiteralValue::Number(30.0), LiteralValue::Number(40.0)],
        ],
    )?;

    wb.register_custom_function(
        "range_total",
        CustomFnOptions {
            min_args: 1,
            max_args: Some(1),
            ..Default::default()
        },
        Arc::new(
            |args: &[LiteralValue]| -> Result<LiteralValue, ExcelError> {
                let LiteralValue::Array(rows) = &args[0] else {
                    return Err(
                        ExcelError::new(ExcelErrorKind::Value).with_message("expected range input")
                    );
                };

                let total = rows.iter().flatten().map(as_f64).sum::<f64>();
                Ok(LiteralValue::Number(total))
            },
        ),
    )?;

    wb.set_formula("Sheet1", 1, 3, "=RANGE_TOTAL(A1:B2)")?;

    let value = wb.evaluate_cell("Sheet1", 1, 3)?;
    println!("RANGE_TOTAL(A1:B2) = {value:?}");

    println!("Registered functions: {:?}", wb.list_custom_functions());
    wb.unregister_custom_function("range_total")?;

    Ok(())
}