Skip to main content

truecalc_core/eval/functions/math/sequence/
mod.rs

1use crate::eval::coercion::to_number;
2use crate::eval::functions::check_arity;
3use crate::types::{ErrorKind, Value};
4
5/// `SEQUENCE(rows, [cols], [start], [step])`
6///
7/// Returns an array of sequential numbers.
8/// Default: cols=1, start=1, step=1.
9/// Always returns a nested 2-D `Array` of `rows` row-arrays, each with `cols`
10/// elements, matching Google Sheets orientation: `SEQUENCE(N)` / `SEQUENCE(N,1)`
11/// is an N-row × 1-column column vector (`[[1],[2],[3]]`), not a 1×N row.
12pub fn sequence_fn(args: &[Value]) -> Value {
13    if args.is_empty() {
14        // GS: SEQUENCE() with no args -> #REF!
15        return Value::Error(ErrorKind::Ref);
16    }
17    if let Some(err) = check_arity(args, 1, 4) {
18        return err;
19    }
20    let rows = match to_number(args[0].clone()) {
21        Err(e) => return e,
22        Ok(v) => v as usize,
23    };
24    let cols = if args.len() >= 2 {
25        match to_number(args[1].clone()) {
26            Err(e) => return e,
27            Ok(v) => v as usize,
28        }
29    } else {
30        1
31    };
32    let start = if args.len() >= 3 {
33        match to_number(args[2].clone()) {
34            Err(e) => return e,
35            Ok(v) => v,
36        }
37    } else {
38        1.0
39    };
40    let step = if args.len() >= 4 {
41        match to_number(args[3].clone()) {
42            Err(e) => return e,
43            Ok(v) => v,
44        }
45    } else {
46        1.0
47    };
48
49    if rows == 0 || cols == 0 {
50        return Value::Error(ErrorKind::Num);
51    }
52
53    // Row-major nested 2-D array. A single column (cols == 1) yields a column
54    // vector `[[v], [v], ...]`; a single row (rows == 1) yields `[[v, v, ...]]`.
55    let outer: Vec<Value> = (0..rows)
56        .map(|r| {
57            let row: Vec<Value> = (0..cols)
58                .map(|c| Value::Number(start + step * (r * cols + c) as f64))
59                .collect();
60            Value::Array(row)
61        })
62        .collect();
63    Value::Array(outer)
64}
65
66#[cfg(test)]
67mod tests;