mod conversions;
#[cfg(feature = "cube")]
use crate::Cube;
#[cfg(feature = "matrix")]
use crate::Matrix;
#[cfg(feature = "ndarray")]
use crate::NdArray;
#[cfg(all(feature = "ndarray", feature = "views"))]
use crate::NdArrayV;
#[cfg(feature = "scalar_type")]
use crate::Scalar;
#[cfg(all(feature = "ndarray", feature = "chunked"))]
use crate::SuperNdArray;
#[cfg(all(feature = "ndarray", feature = "chunked", feature = "views"))]
use crate::SuperNdArrayV;
#[cfg(feature = "xarray")]
use crate::XArray;
use crate::{Array, FieldArray, Table, traits::custom_value::CustomValue};
use std::sync::Arc;
#[cfg(feature = "chunked")]
use crate::{SuperArray, SuperTable};
#[cfg(feature = "views")]
use crate::{ArrayV, TableV};
#[cfg(all(feature = "chunked", feature = "views"))]
use crate::{SuperArrayV, SuperTableV};
mod impls;
#[derive(Debug, Clone)]
pub enum Value {
#[cfg(feature = "scalar_type")]
Scalar(Scalar),
Array(Arc<Array>),
#[cfg(feature = "views")]
ArrayView(Arc<ArrayV>),
FieldArray(Arc<FieldArray>),
Table(Arc<Table>),
#[cfg(feature = "views")]
TableView(Arc<TableV>),
#[cfg(feature = "chunked")]
SuperArray(Arc<SuperArray>),
#[cfg(all(feature = "chunked", feature = "views"))]
SuperArrayView(Arc<SuperArrayV>),
#[cfg(feature = "chunked")]
SuperTable(Arc<SuperTable>),
#[cfg(all(feature = "chunked", feature = "views"))]
SuperTableView(Arc<SuperTableV>),
#[cfg(feature = "matrix")]
Matrix(Arc<Matrix>),
#[cfg(feature = "ndarray")]
NdArray(Arc<NdArray<f64>>),
#[cfg(all(feature = "ndarray", feature = "views"))]
NdArrayView(Arc<NdArrayV<f64>>),
#[cfg(all(feature = "ndarray", feature = "chunked"))]
SuperNdArray(Arc<SuperNdArray<f64>>),
#[cfg(all(feature = "ndarray", feature = "chunked", feature = "views"))]
SuperNdArrayView(Arc<SuperNdArrayV<f64>>),
#[cfg(feature = "xarray")]
XArray(Arc<XArray<f64>>),
#[cfg(feature = "cube")]
Cube(Arc<Cube>),
VecValue(Arc<Vec<Value>>),
BoxValue(Box<Value>),
ArcValue(Arc<Value>),
Tuple2(Arc<(Value, Value)>),
Tuple3(Arc<(Value, Value, Value)>),
Tuple4(Arc<(Value, Value, Value, Value)>),
Tuple5(Arc<(Value, Value, Value, Value, Value)>),
Tuple6(Arc<(Value, Value, Value, Value, Value, Value)>),
Custom(Arc<dyn CustomValue>),
}
impl Value {
#[inline]
pub fn len(&self) -> usize {
match self {
#[cfg(feature = "scalar_type")]
Value::Scalar(_) => 1,
Value::Table(t) => t.n_rows,
#[cfg(feature = "views")]
Value::TableView(tv) => tv.len,
Value::Array(a) => a.len(),
#[cfg(feature = "views")]
Value::ArrayView(av) => av.len(),
Value::FieldArray(fa) => fa.array.len(),
#[cfg(feature = "chunked")]
Value::SuperArray(sa) => sa.len(),
#[cfg(all(feature = "chunked", feature = "views"))]
Value::SuperArrayView(sav) => sav.len(),
#[cfg(feature = "chunked")]
Value::SuperTable(st) => st.len(),
#[cfg(all(feature = "chunked", feature = "views"))]
Value::SuperTableView(stv) => stv.len,
#[cfg(feature = "matrix")]
Value::Matrix(m) => m.len(),
#[cfg(feature = "ndarray")]
Value::NdArray(nd) => nd.shape()[0],
#[cfg(all(feature = "ndarray", feature = "views"))]
Value::NdArrayView(v) => v.shape()[0],
#[cfg(all(feature = "ndarray", feature = "chunked"))]
Value::SuperNdArray(snd) => snd.n_obs(),
#[cfg(all(feature = "ndarray", feature = "chunked", feature = "views"))]
Value::SuperNdArrayView(v) => v.n_obs(),
#[cfg(feature = "xarray")]
Value::XArray(xa) => xa.shape()[0],
#[cfg(feature = "cube")]
Value::Cube(c) => c.len(),
Value::VecValue(vv) => vv.iter().map(|x| x.len()).sum(),
Value::BoxValue(bv) => bv.len(),
Value::ArcValue(av) => av.len(),
Value::Tuple2(t2) => t2.0.len() + t2.1.len(),
Value::Tuple3(t3) => t3.0.len() + t3.1.len() + t3.2.len(),
Value::Tuple4(t4) => t4.0.len() + t4.1.len() + t4.2.len() + t4.3.len(),
Value::Tuple5(t5) => t5.0.len() + t5.1.len() + t5.2.len() + t5.3.len() + t5.4.len(),
Value::Tuple6(t6) => {
t6.0.len() + t6.1.len() + t6.2.len() + t6.3.len() + t6.4.len() + t6.5.len()
}
Value::Custom(_cv) => panic!("Length is not implemented for custom value type."),
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[cfg(feature = "views")]
pub fn slice(&self, offset: usize, length: usize) -> Value {
match self {
#[cfg(feature = "scalar_type")]
Value::Scalar(s) => Value::Scalar(s.clone()),
Value::Table(t) => Value::TableView(Arc::new(t.slice(offset, length))),
Value::TableView(tv) => Value::TableView(Arc::new(tv.from_self(offset, length))),
Value::Array(a) => {
Value::ArrayView(Arc::new(ArrayV::new((**a).clone(), offset, length)))
}
Value::ArrayView(av) => Value::ArrayView(Arc::new(av.slice(offset, length))),
Value::FieldArray(fa) => {
Value::ArrayView(Arc::new(ArrayV::new(fa.array.clone(), offset, length)))
}
#[cfg(feature = "chunked")]
Value::SuperArray(sa) => Value::SuperArrayView(Arc::new(sa.slice(offset, length))),
#[cfg(all(feature = "chunked", feature = "views"))]
Value::SuperArrayView(sav) => {
Value::SuperArrayView(Arc::new(sav.slice(offset, length)))
}
#[cfg(feature = "chunked")]
Value::SuperTable(st) => Value::SuperTableView(Arc::new(st.view(offset, length))),
#[cfg(all(feature = "chunked", feature = "views"))]
Value::SuperTableView(stv) => {
Value::SuperTableView(Arc::new(stv.slice(offset, length)))
}
#[cfg(feature = "matrix")]
Value::Matrix(_) => unimplemented!("Matrix slicing"),
#[cfg(feature = "ndarray")]
Value::NdArray(nd) => {
assert!(
offset + length <= nd.shape()[0],
"Value::slice: window {}..{} out of bounds for axis 0 (size {})",
offset, offset + length, nd.shape()[0]
);
let mut window_shape = vec![length];
window_shape.extend_from_slice(&nd.shape()[1..]);
Value::NdArrayView(Arc::new(NdArrayV::new(
nd.as_ref().clone(),
offset * nd.strides()[0],
&window_shape,
nd.strides(),
)))
}
#[cfg(all(feature = "ndarray", feature = "views"))]
Value::NdArrayView(v) => {
assert!(
offset + length <= v.shape()[0],
"Value::slice: window {}..{} out of bounds for axis 0 (size {})",
offset, offset + length, v.shape()[0]
);
let mut window_shape = vec![length];
window_shape.extend_from_slice(&v.shape()[1..]);
Value::NdArrayView(Arc::new(NdArrayV::new(
v.source.clone(),
v.offset + offset * v.strides()[0],
&window_shape,
v.strides(),
)))
}
#[cfg(all(feature = "ndarray", feature = "chunked"))]
Value::SuperNdArray(snd) => {
Value::SuperNdArrayView(Arc::new(snd.slice(offset, length)))
}
#[cfg(all(feature = "ndarray", feature = "chunked", feature = "views"))]
Value::SuperNdArrayView(v) => {
Value::SuperNdArrayView(Arc::new(v.slice(offset, length)))
}
#[cfg(all(feature = "xarray", feature = "select"))]
Value::XArray(xa) => {
let range = offset..offset + length;
let dim0 = xa.dim_names()[0].to_string();
Value::XArray(Arc::new(xa.select(&[(dim0.as_str(), &range)])))
}
#[cfg(all(feature = "xarray", not(feature = "select")))]
Value::XArray(_) => unimplemented!("XArray slicing requires the select feature"),
#[cfg(feature = "cube")]
Value::Cube(_) => unimplemented!("Cube slicing"),
Value::VecValue(v) => {
let end = (offset + length).min(v.len());
Value::VecValue(Arc::new(v[offset..end].to_vec()))
}
Value::BoxValue(bv) => bv.slice(offset, length),
Value::ArcValue(av) => av.slice(offset, length),
Value::Tuple2(t) => Value::Tuple2(Arc::new((
t.0.slice(offset, length),
t.1.slice(offset, length),
))),
Value::Tuple3(t) => Value::Tuple3(Arc::new((
t.0.slice(offset, length),
t.1.slice(offset, length),
t.2.slice(offset, length),
))),
Value::Tuple4(t) => Value::Tuple4(Arc::new((
t.0.slice(offset, length),
t.1.slice(offset, length),
t.2.slice(offset, length),
t.3.slice(offset, length),
))),
Value::Tuple5(t) => Value::Tuple5(Arc::new((
t.0.slice(offset, length),
t.1.slice(offset, length),
t.2.slice(offset, length),
t.3.slice(offset, length),
t.4.slice(offset, length),
))),
Value::Tuple6(t) => Value::Tuple6(Arc::new((
t.0.slice(offset, length),
t.1.slice(offset, length),
t.2.slice(offset, length),
t.3.slice(offset, length),
t.4.slice(offset, length),
t.5.slice(offset, length),
))),
Value::Custom(_) => panic!("Slicing is not implemented for custom value types."),
}
}
pub fn arity(&self) -> usize {
match self {
Value::Tuple2(_) => 2,
Value::Tuple3(_) => 3,
Value::Tuple4(_) => 4,
Value::Tuple5(_) => 5,
Value::Tuple6(_) => 6,
_ => 1,
}
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use super::*;
use crate::{
Array, ArrayV, ArrowType, Field, FieldArray, IntegerArray, MaskedArray, NumericArray, Table,
};
fn seq_array(n: usize) -> Array {
let mut arr = IntegerArray::<i64>::default();
for i in 0..n {
arr.push(i as i64);
}
Array::NumericArray(NumericArray::Int64(Arc::new(arr)))
}
#[cfg(feature = "views")]
#[test]
fn len_of_an_array_view_counts_the_window() {
let view = ArrayV::new(seq_array(100), 30, 10);
let value = Value::ArrayView(Arc::new(view));
assert_eq!(value.len(), 10, "the window, not the backing array");
}
#[cfg(feature = "views")]
#[test]
fn len_agrees_across_the_view_variants() {
let array = Value::ArrayView(Arc::new(ArrayV::new(seq_array(100), 30, 10)));
let mut table = Table::new("t".to_string(), None);
table.add_col(FieldArray::new(
Field::new("v", ArrowType::Int64, false, None),
seq_array(100),
));
let table = Value::Table(Arc::new(table)).slice(30, 10);
assert_eq!(array.len(), table.len());
}
#[cfg(feature = "views")]
#[test]
fn len_bounds_a_slice_of_the_same_value() {
let value = Value::ArrayView(Arc::new(ArrayV::new(seq_array(100), 30, 10)));
let whole = value.slice(0, value.len());
assert_eq!(whole.len(), 10);
}
}