use crate::types::{ErrorKind, Value};
pub fn maxa_fn(args: &[Value]) -> Value {
if args.is_empty() {
return Value::Error(ErrorKind::NA);
}
let mut result: Option<f64> = None;
let mut skipped_sparkline = false;
for arg in args {
match arg {
Value::Sparkline(_) => skipped_sparkline = true,
Value::Number(n) => {
result = Some(result.map_or(*n, |cur: f64| cur.max(*n)));
}
Value::Bool(b) => {
let n = if *b { 1.0 } else { 0.0 };
result = Some(result.map_or(n, |cur: f64| cur.max(n)));
}
Value::Text(_) => return Value::Error(ErrorKind::Value),
Value::Empty => {}
Value::Array(inner) => {
if inner.is_empty() {
return Value::Error(ErrorKind::Ref);
}
if let Err(e) = fold_array_max(inner, &mut result, &mut skipped_sparkline) {
return e;
}
}
Value::Error(e) => return Value::Error(e.clone()),
Value::ErrorMsg(e, m) => return Value::ErrorMsg(e.clone(), m.clone()),
_ => {}
}
}
match result {
Some(n) => Value::Number(n),
None if skipped_sparkline => Value::Number(0.0),
None => Value::Error(ErrorKind::NA),
}
}
fn fold_array_max(
arr: &[Value],
result: &mut Option<f64>,
skipped_sparkline: &mut bool,
) -> Result<(), Value> {
for v in arr {
let n = match v {
Value::Sparkline(_) => {
*skipped_sparkline = true;
continue;
}
Value::Number(n) => *n,
Value::Bool(b) => if *b { 1.0 } else { 0.0 },
Value::Text(_) => 0.0,
Value::Empty => continue,
Value::Array(inner) => {
fold_array_max(inner, result, skipped_sparkline)?;
continue;
}
Value::Error(e) => return Err(Value::Error(e.clone())),
Value::ErrorMsg(e, m) => return Err(Value::ErrorMsg(e.clone(), m.clone())),
_ => continue,
};
*result = Some(result.map_or(n, |cur: f64| cur.max(n)));
}
Ok(())
}
#[cfg(test)]
mod tests;