use super::error::CalcError;
#[derive(Debug, Clone, PartialEq)]
pub struct ArrayCell {
buf: Vec<f64>,
num_el: Option<i64>,
}
impl ArrayCell {
pub fn new(mut buf: Vec<f64>, array_size: usize) -> Self {
buf.resize(array_size, 0.0);
ArrayCell { buf, num_el: None }
}
pub fn from_scalar(v: f64, array_size: usize) -> Self {
let fill = if v.is_nan() { 0.0 } else { v };
ArrayCell {
buf: vec![fill; array_size],
num_el: None,
}
}
pub fn buf(&self) -> &[f64] {
&self.buf
}
pub fn buf_mut(&mut self) -> &mut [f64] {
&mut self.buf
}
pub fn into_buf(self) -> Vec<f64> {
self.buf
}
pub fn last_el(&self) -> i64 {
match self.num_el {
Some(n) => n - 1,
None => self.buf.len() as i64 - 1,
}
}
pub fn span(&self) -> i64 {
1 + self.last_el()
}
pub fn window(&self) -> &[f64] {
&self.buf[..self.window_len()]
}
pub fn window_mut(&mut self) -> &mut [f64] {
let n = self.window_len();
&mut self.buf[..n]
}
fn window_len(&self) -> usize {
self.span().clamp(0, self.buf.len() as i64) as usize
}
pub fn clear_outside_window(&mut self) {
let n = self.window_len();
self.buf[n..].fill(0.0);
}
pub fn set_num_el(&mut self, n: i64) {
self.num_el = if n == -1 || n == self.buf.len() as i64 {
None
} else {
Some(n)
};
}
pub fn map(mut self, f: impl Fn(f64) -> f64) -> Self {
for v in &mut self.buf {
*v = f(*v);
}
self
}
}
impl From<Vec<f64>> for ArrayCell {
fn from(buf: Vec<f64>) -> Self {
ArrayCell { buf, num_el: None }
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ArrayStackValue {
Double(f64),
Array(ArrayCell),
}
impl ArrayStackValue {
pub fn array(buf: Vec<f64>) -> Self {
ArrayStackValue::Array(ArrayCell::from(buf))
}
pub fn is_double(&self) -> bool {
matches!(self, ArrayStackValue::Double(_))
}
pub fn is_array(&self) -> bool {
matches!(self, ArrayStackValue::Array(_))
}
pub fn as_f64(&self) -> Result<f64, CalcError> {
match self {
ArrayStackValue::Double(v) => Ok(*v),
ArrayStackValue::Array(a) => Ok(a.buf().first().copied().unwrap_or(0.0)),
}
}
pub fn as_cell(&self) -> Result<&ArrayCell, CalcError> {
match self {
ArrayStackValue::Array(a) => Ok(a),
ArrayStackValue::Double(_) => Err(CalcError::TypeMismatch),
}
}
pub fn into_cell(self, array_size: usize) -> ArrayCell {
match self {
ArrayStackValue::Double(v) => ArrayCell::from_scalar(v, array_size),
ArrayStackValue::Array(a) => a,
}
}
pub fn to_array(self, array_size: usize) -> Vec<f64> {
self.into_cell(array_size).into_buf()
}
pub fn elements(&self) -> impl Iterator<Item = f64> + '_ {
let (scalar, arr) = match self {
ArrayStackValue::Double(v) => (Some(*v), [].as_slice()),
ArrayStackValue::Array(a) => (None, a.buf()),
};
scalar.into_iter().chain(arr.iter().copied())
}
pub fn map<F: Fn(f64) -> f64>(self, f: F) -> ArrayStackValue {
match self {
ArrayStackValue::Double(v) => ArrayStackValue::Double(f(v)),
ArrayStackValue::Array(a) => ArrayStackValue::Array(a.map(f)),
}
}
}
pub fn zip_map<F: Fn(f64, f64) -> f64>(
a: ArrayStackValue,
b: ArrayStackValue,
f: F,
) -> ArrayStackValue {
match (a, b) {
(ArrayStackValue::Double(x), ArrayStackValue::Double(y)) => {
ArrayStackValue::Double(f(x, y))
}
(ArrayStackValue::Array(cell), ArrayStackValue::Double(scalar)) => {
ArrayStackValue::Array(cell.map(|x| f(x, scalar)))
}
(left, ArrayStackValue::Array(right)) => {
let mut cell = left.into_cell(right.buf().len());
for (x, y) in cell.buf_mut().iter_mut().zip(right.buf()) {
*x = f(*x, *y);
}
ArrayStackValue::Array(cell)
}
}
}