formualizer_eval/
broadcast.rs

1use formualizer_common::{ExcelError, ExcelErrorKind};
2
3pub type Shape2D = (usize, usize);
4
5pub fn broadcast_shape(shapes: &[Shape2D]) -> Result<Shape2D, ExcelError> {
6    if shapes.is_empty() {
7        return Ok((1, 1));
8    }
9    let mut rows = 1usize;
10    let mut cols = 1usize;
11    for &(r, c) in shapes {
12        rows = broadcast_dim(rows, r)?;
13        cols = broadcast_dim(cols, c)?;
14    }
15    Ok((rows, cols))
16}
17
18fn broadcast_dim(a: usize, b: usize) -> Result<usize, ExcelError> {
19    if a == b || a == 1 {
20        return Ok(b.max(a));
21    }
22    if b == 1 {
23        return Ok(a.max(b));
24    }
25    Err(ExcelError::new(ExcelErrorKind::Value).with_message(format!(
26        "Incompatible dimensions for broadcasting: {a} vs {b}"
27    )))
28}
29
30#[inline]
31pub fn project_index(idx: (usize, usize), shape: Shape2D) -> (usize, usize) {
32    let (r, c) = shape;
33    let rr = if r == 1 { 0 } else { idx.0 };
34    let cc = if c == 1 { 0 } else { idx.1 };
35    (rr, cc)
36}