use crate::types::{ErrorKind, Value};
pub fn collect_nums(args: &[Value]) -> Vec<f64> {
let mut nums = Vec::new();
collect_nums_into(args, &mut nums);
nums
}
fn collect_nums_into(args: &[Value], out: &mut Vec<f64>) {
for arg in args {
match arg {
Value::Number(n) => out.push(*n),
Value::Date(n) => out.push(*n),
Value::Array(inner) => collect_nums_into(inner, out),
_ => {}
}
}
}
fn collect_nums_into_checked(args: &[Value], out: &mut Vec<f64>) -> Option<Value> {
for arg in args {
match arg {
Value::Number(n) => out.push(*n),
Value::Date(n) => out.push(*n),
Value::Array(inner) => {
if let Some(err) = collect_nums_into_checked(inner, out) {
return Some(err);
}
}
Value::Error(e) => return Some(Value::Error(e.clone())),
_ => {}
}
}
None
}
fn collect_nums_a_into_checked(args: &[Value], out: &mut Vec<f64>) -> Option<Value> {
for arg in args {
match arg {
Value::Number(n) => out.push(*n),
Value::Date(n) => out.push(*n),
Value::Bool(b) => out.push(if *b { 1.0 } else { 0.0 }),
Value::Text(_) => out.push(0.0),
Value::Array(inner) => {
if let Some(err) = collect_nums_a_into_checked(inner, out) {
return Some(err);
}
}
Value::Error(e) => return Some(Value::Error(e.clone())),
Value::Empty => {}
}
}
None
}
pub fn collect_numbers_checked(v: &Value) -> Result<Vec<f64>, Value> {
match v {
Value::Array(arr) => {
let mut nums = Vec::new();
if let Some(err) = collect_nums_into_checked(arr, &mut nums) {
return Err(err);
}
Ok(nums)
}
Value::Number(n) => Ok(vec![*n]),
Value::Error(e) => Err(Value::Error(e.clone())),
_ => Ok(vec![]),
}
}
pub fn collect_nums_a_checked(args: &[Value]) -> Result<Vec<f64>, Value> {
let mut nums = Vec::new();
for arg in args {
match arg {
Value::Number(n) => nums.push(*n),
Value::Date(n) => nums.push(*n),
Value::Bool(b) => nums.push(if *b { 1.0 } else { 0.0 }),
Value::Text(s) => {
let trimmed = s.trim();
if trimmed.is_empty() {
nums.push(0.0);
} else {
match trimmed.parse::<f64>() {
Ok(v) if v.is_finite() => nums.push(v),
_ => return Err(Value::Error(ErrorKind::Value)),
}
}
}
Value::Empty => {}
Value::Array(inner) => {
if let Some(err) = collect_nums_a_into_checked(inner, &mut nums) {
return Err(err);
}
}
Value::Error(e) => return Err(Value::Error(e.clone())),
}
}
Ok(nums)
}
pub fn collect_nums_direct(args: &[Value]) -> Result<Vec<f64>, Value> {
let mut nums = Vec::new();
for arg in args {
match arg {
Value::Number(n) => nums.push(*n),
Value::Date(n) => nums.push(*n),
Value::Bool(b) => nums.push(if *b { 1.0 } else { 0.0 }),
Value::Text(s) => {
let trimmed = s.trim();
if trimmed.is_empty() {
return Err(Value::Error(ErrorKind::Value));
}
match trimmed.parse::<f64>() {
Ok(v) if v.is_finite() => nums.push(v),
_ => return Err(Value::Error(ErrorKind::Value)),
}
}
Value::Empty => {} Value::Array(inner) => {
if let Some(err) = collect_nums_into_checked(inner, &mut nums) {
return Err(err);
}
}
Value::Error(e) => return Err(Value::Error(e.clone())),
}
}
Ok(nums)
}
pub fn collect_nums_a_direct(args: &[Value]) -> Result<Vec<f64>, Value> {
let mut nums = Vec::new();
for arg in args {
match arg {
Value::Number(n) => nums.push(*n),
Value::Date(n) => nums.push(*n),
Value::Bool(b) => nums.push(if *b { 1.0 } else { 0.0 }),
Value::Text(s) => {
let trimmed = s.trim();
if trimmed.is_empty() {
nums.push(0.0);
} else {
match trimmed.parse::<f64>() {
Ok(v) if v.is_finite() => nums.push(v),
_ => return Err(Value::Error(ErrorKind::Value)),
}
}
}
Value::Empty => {} Value::Array(inner) => {
collect_nums_a_into(inner, &mut nums);
}
Value::Error(e) => return Err(Value::Error(e.clone())),
}
}
Ok(nums)
}
pub fn collect_nums_a(args: &[Value]) -> Vec<f64> {
let mut nums = Vec::new();
collect_nums_a_into(args, &mut nums);
nums
}
pub fn collect_nums_a_into(args: &[Value], out: &mut Vec<f64>) {
for arg in args {
match arg {
Value::Number(n) => out.push(*n),
Value::Date(n) => out.push(*n),
Value::Bool(b) => out.push(if *b { 1.0 } else { 0.0 }),
Value::Text(_) => out.push(0.0),
Value::Array(inner) => collect_nums_a_into(inner, out),
Value::Empty => {}
Value::Error(_) => {}
}
}
}
pub fn collect_paired(x_arg: &Value, y_arg: &Value) -> Result<(Vec<f64>, Vec<f64>), Value> {
let xs_raw = flatten_to_values(x_arg);
let ys_raw = flatten_to_values(y_arg);
if xs_raw.is_empty() || ys_raw.is_empty() {
return Err(Value::Error(ErrorKind::Ref));
}
if xs_raw.len() != ys_raw.len() {
return Err(Value::Error(ErrorKind::NA));
}
let mut xs = Vec::new();
let mut ys = Vec::new();
for (x, y) in xs_raw.iter().zip(ys_raw.iter()) {
if let Value::Error(e) = x { return Err(Value::Error(e.clone())); }
if let Value::Error(e) = y { return Err(Value::Error(e.clone())); }
if let (Value::Number(xn), Value::Number(yn)) = (x, y) {
xs.push(*xn);
ys.push(*yn);
}
}
Ok((xs, ys))
}
fn flatten_to_values(v: &Value) -> Vec<Value> {
match v {
Value::Array(inner) => {
let mut out = Vec::new();
flatten_array_into(inner, &mut out);
out
}
other => vec![other.clone()],
}
}
fn flatten_array_into(arr: &[Value], out: &mut Vec<Value>) {
for v in arr {
match v {
Value::Array(inner) => flatten_array_into(inner, out),
other => out.push(other.clone()),
}
}
}