Skip to main content

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

1use crate::eval::coercion::to_number;
2use crate::eval::evaluate_expr;
3use crate::eval::functions::{check_arity_len, EvalCtx};
4use crate::parser::ast::Expr;
5use crate::types::{ErrorKind, Value};
6
7/// `RANDARRAY([rows], [cols], [min], [max], [integer])`
8///
9/// Returns an array of random numbers.
10/// With no args: returns a single random number (equivalent to RAND()).
11/// With rows/cols: returns a nested 2D array (rows × cols).
12/// Uses a per-cell PRF key when available; falls back to SystemTime.
13pub fn randarray_lazy(args: &[Expr], ctx: &mut EvalCtx<'_>) -> Value {
14    if args.is_empty() {
15        return Value::Number(ctx.ctx.draw_rand(0));
16    }
17    if let Some(err) = check_arity_len(args.len(), 1, 5) {
18        return err;
19    }
20    let rows_val = evaluate_expr(&args[0], ctx);
21    let rows = match to_number(rows_val) {
22        Err(e) => return e,
23        Ok(v) => v,
24    };
25    if rows <= 0.0 {
26        return Value::Error(ErrorKind::Num);
27    }
28    let rows = rows as usize;
29    let cols = if args.len() >= 2 {
30        let cv = evaluate_expr(&args[1], ctx);
31        match to_number(cv) {
32            Err(e) => return e,
33            Ok(v) => {
34                if v <= 0.0 {
35                    return Value::Error(ErrorKind::Num);
36                }
37                v as usize
38            }
39        }
40    } else {
41        1
42    };
43    let total = rows * cols;
44    let nums = ctx.ctx.draw_rand_n(total);
45    let outer: Vec<Value> = (0..rows)
46        .map(|r| Value::Array((0..cols).map(|c| Value::Number(nums[r * cols + c])).collect()))
47        .collect();
48    Value::Array(outer)
49}
50
51#[cfg(test)]
52mod tests;