use super::funejson::Value; /// [min, max] of a series, skipping gaps (`None`); `None` when nothing is left. /// /// # Panics /// Panics on a value that is not finite. pub fn extent(values: &[Option]) -> Option> { let mut range: Option<(f64, f64)> = None; for v in values.iter().flatten() { if !v.is_finite() { panic!("values must be finite numbers or null, received {}", v); } range = Some(match range { None => (*v, *v), Some((lo, hi)) => (if *v < lo { *v } else { lo }, if *v > hi { *v } else { hi }), }); } range.map(|(lo, hi)| vec![lo, hi]) } pub fn fune_vector(args: &[Value]) -> Value { // A value the typed signature cannot hold (text, true) is refused with the // wording TypeScript and Python use, rather than read as 0. let values: Vec> = args[0] .as_arr() .iter() .map(|v| match v { Value::Null => None, Value::Int(_) | Value::Float(_) => Some(v.as_f64()), _ => panic!("values must be finite numbers or null, received a value that is not a number"), }) .collect(); match extent(&values) { Some(r) => Value::Arr(r.into_iter().map(Value::Float).collect()), None => Value::Null, } }