Guides
Custom Functions (Rust, Python, JS)
Register workbook-local callbacks with consistent semantics across Rust, Python, and JS/WASM.
Formualizer exposes the same custom-function model in all runtimes: register a workbook-local callback, call it from formulas, and unregister when done.
Semantics that are the same across runtimes
- Function names are case-insensitive and canonicalized to uppercase (
my_fn,MY_FN,My_Fnall map to one entry). - Resolution is workbook-local first, then global built-ins.
- Built-in override is blocked by default; opt in with
allow_override_builtin(Rust/Python) orallowOverrideBuiltin(JS). - Arity is validated before callback execution (
min_args/max_argsstyle options). - Range arguments are materialized as 2D arrays (
LiteralValue::Arrayin Rust, nested lists in Python, nested arrays in JS). - Returning an array spills into the grid using normal dynamic-array behavior.
Register and call a custom function
Register a callback, then use it in a formula
use formualizer_common::LiteralValue;use formualizer_workbook::{CustomFnOptions, Workbook};use std::sync::Arc;let mut wb = Workbook::new();wb.add_sheet("Sheet1")?;wb.set_values( "Sheet1", 1, 1, &[ vec![LiteralValue::Number(1.0), LiteralValue::Number(2.0)], vec![LiteralValue::Number(3.0), LiteralValue::Number(4.0)], ],)?;wb.register_custom_function( "range_total", CustomFnOptions { min_args: 1, max_args: Some(1), ..Default::default() }, Arc::new(|args: &[LiteralValue]| { let total = match &args[0] { LiteralValue::Array(rows) => rows.iter().flatten().fold(0.0, |acc, v| { acc + match v { LiteralValue::Number(n) => *n, LiteralValue::Int(i) => *i as f64, _ => 0.0, } }), _ => 0.0, }; Ok(LiteralValue::Number(total)) }),)?;wb.set_formula("Sheet1", 1, 3, "=RANGE_TOTAL(A1:B2)")?;assert_eq!(wb.evaluate_cell("Sheet1", 1, 3)?, LiteralValue::Number(10.0));Quick verification commands
cargo run -p formualizer-workbook --example custom_function_registration
python bindings/python/examples/custom_function_registration.py
cd bindings/wasm && npm run build && node examples/custom-function-registration.mjs