use crate::types::{ErrorKind, Value};
pub fn max_fn(args: &[Value]) -> Value {
if args.is_empty() {
return Value::Error(ErrorKind::NA);
}
if let Some(r) = super::stat_helpers::zoned_extreme(args, false) {
return r;
}
let mut result: Option<f64> = None;
let mut had_array = false;
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(s) => {
let trimmed = s.trim();
match trimmed.parse::<f64>() {
Ok(v) if v.is_finite() => {
result = Some(result.map_or(v, |cur: f64| cur.max(v)));
}
_ => return Value::Error(ErrorKind::Value),
}
}
Value::Empty => {}
Value::Array(elems) => {
had_array = true;
if elems.is_empty() {
return Value::Error(ErrorKind::Ref);
}
if let Err(e) = max_array_into(elems, &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()),
_ => {}
}
}
if skipped_sparkline && result.is_none() {
return Value::Number(0.0);
}
if had_array && result.is_none() {
return Value::Error(ErrorKind::Ref);
}
Value::Number(result.unwrap_or(0.0))
}
fn max_array_into(
elems: &[Value],
result: &mut Option<f64>,
skipped_sparkline: &mut bool,
) -> Result<(), Value> {
for elem in elems {
match elem {
Value::Number(n) => {
*result = Some(result.map_or(*n, |cur: f64| cur.max(*n)));
}
Value::Sparkline(_) => *skipped_sparkline = true,
Value::Error(e) => return Err(Value::Error(e.clone())),
Value::ErrorMsg(e, m) => return Err(Value::ErrorMsg(e.clone(), m.clone())),
Value::Array(inner) => max_array_into(inner, result, skipped_sparkline)?,
_ => {}
}
}
Ok(())
}
#[cfg(test)]
mod tests;