use paste::paste;
use std::fmt::{Debug, Display};
use std::ops;
use crate::check_same_fields;
use crate::interface::index::Index;
use crate::interface::types::array::ArrayType;
use crate::interface::types::cell_array::CellArray;
use crate::interface::types::compressed_array::CompressedArray;
use crate::interface::types::matlab_types::{MatlabType, MatlabTypeMarker};
use crate::interface::types::numeric_array::NumericArray;
use crate::interface::types::sparse_array::SparseArray;
use crate::interface::types::structure::Structure;
use crate::interface::types::structure_array::StructureArray;
use crate::parser::v7::types::compressed_array::CompressedArray7;
use crate::parser::v7::variable7::MatVariable7;
#[derive(Debug, Clone)]
pub enum MatVariable {
NumericArray(NumericArray),
SparseArray(SparseArray),
StructureArray(StructureArray),
CellArray(CellArray),
Structure(Structure),
Null,
Compressed(CompressedArray),
Unsupported,
}
impl MatVariable {
pub fn dim(&self) -> Vec<usize> {
match self {
MatVariable::NumericArray(val) => val.dim.clone(),
MatVariable::CellArray(val) => val.dim.clone(),
MatVariable::Structure(_) => vec![1, 1],
MatVariable::StructureArray(val) => val.dim.clone(),
MatVariable::SparseArray(val) => val.dim.clone(),
_ => unimplemented!(),
}
}
pub fn numeric_type(&self) -> Option<&MatlabType> {
match self {
MatVariable::NumericArray(val) => Some(val.numeric_type()),
MatVariable::SparseArray(val) => Some(val.numeric_type()),
_ => None,
}
}
pub fn fieldnames(&self) -> Option<Vec<String>> {
match self {
MatVariable::Structure(val) => Some(val.fieldnames()),
MatVariable::StructureArray(val) => Some(val.fieldnames()),
_ => None,
}
}
pub fn is_complex(&self) -> Option<bool> {
match self {
MatVariable::NumericArray(val) => Some(val.is_complex()),
MatVariable::SparseArray(val) => Some(val.is_complex()),
_ => None,
}
}
pub fn to_scalar<T: MatlabTypeMarker>(&self) -> Option<T> {
match self {
MatVariable::NumericArray(val) => val.real_to_scalar(),
_ => None,
}
}
pub fn comp_to_scalar<T: MatlabTypeMarker>(&self) -> Option<T> {
match self {
MatVariable::NumericArray(val) => val.comp_to_scalar(),
_ => None,
}
}
pub fn to_vec<T: MatlabTypeMarker>(&self) -> Option<Vec<T>> {
match self {
MatVariable::NumericArray(val) => val.real_to_vec(),
_ => None,
}
}
pub fn comp_to_vec<T: MatlabTypeMarker>(&self) -> Option<Vec<T>> {
match self {
MatVariable::NumericArray(val) => val.comp_to_vec(),
_ => None,
}
}
pub fn to_sparse(self) -> Option<MatVariable> {
match self {
MatVariable::NumericArray(val) => val.to_sparse(),
_ => None,
}
}
pub fn iter(&self) -> MatVariableIterator<'_> {
MatVariableIterator::new(self)
}
}
macro_rules! impl_MatVariable_to {
($($ret: ty),*) => {
paste! {
$(
#[doc = concat!("If [`MatVariable`] is of type [`MatVariable::NumericArray`], returns copied `", stringify!($ret),"`. Otherwise, returns [`None`].")]
pub fn [<to_ $ret>](&self) -> Option<$ret> {
match self {
MatVariable::NumericArray(val) if val.is_scalar() => val.real_to_scalar(),
_ => None,
}
}
)*
}
};
}
macro_rules! impl_MatVariable_comp_to {
($($ret: ty),*) => {
paste! {
$(
#[doc = concat!("If [`MatVariable`] is of type [`MatVariable::NumericArray`], returns copied `", stringify!($ret),"`. Otherwise, returns [`None`].")]
pub fn [<comp_to_ $ret>](&self) -> Option<$ret> {
match self {
MatVariable::NumericArray(val) if val.is_scalar() => val.comp_to_scalar(),
_ => None,
}
}
)*
}
};
}
macro_rules! impl_MatVariable_to_vec {
($($ret: ty),*) => {
paste! {
$(
#[doc = concat!("If [`MatVariable`] is of type [`MatVariable::NumericArray`], returns cloned `Vec<", stringify!($ret),">`. Otherwise, returns [`None`].")]
pub fn [<to_vec_ $ret>](&self) -> Option<Vec<$ret>> {
match self {
MatVariable::NumericArray(val) => val.real_to_vec::<$ret>(),
_ => None,
}
}
)*
}
};
}
macro_rules! impl_MatVariable_comp_to_vec {
($($ret: ty),*) => {
paste! {
$(
#[doc = concat!("If [`MatVariable`] is of type [`MatVariable::NumericArray`], returns complex part as cloned `Vec<", stringify!($ret),">`. Otherwise, returns [`None`].")]
pub fn [<comp_to_vec_ $ret>](&self) -> Option<Vec<$ret>> {
match self {
MatVariable::NumericArray(val) => val.comp_to_vec::<$ret>(),
_ => None,
}
}
)*
}
};
}
impl MatVariable {
impl_MatVariable_to!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, char, bool);
impl_MatVariable_comp_to!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, char, bool);
impl_MatVariable_to_vec!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, char, bool);
impl_MatVariable_comp_to_vec!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, char, bool);
}
pub trait OwnedIndex<Idx> {
type Output;
fn elem(&self, index: Idx) -> Self::Output;
}
static NULL: MatVariable = MatVariable::Null;
impl<T> OwnedIndex<T> for MatVariable
where
T: Index,
{
type Output = MatVariable;
fn elem(&self, index: T) -> Self::Output {
index.index_into_clone(self).unwrap_or(NULL.clone())
}
}
impl<T> ops::Index<T> for MatVariable
where
T: Index,
{
type Output = MatVariable;
fn index(&self, index: T) -> &Self::Output {
index.index_into_ref(self).unwrap_or(&NULL)
}
}
pub struct MatVariableIterator<'a> {
var: &'a MatVariable,
count: usize,
}
impl<'a> MatVariableIterator<'a> {
fn new(var: &'a MatVariable) -> Self {
Self { var, count: 0 }
}
}
impl<'a> Iterator for MatVariableIterator<'a> {
type Item = MatVariable;
fn next(&mut self) -> Option<Self::Item> {
match self.var {
MatVariable::NumericArray(v) => {
let ret = if self.count < v.value.len() {
Some(v.get_clone_colmaj(self.count).unwrap())
} else {
None
};
self.count += 1;
ret
}
_ => todo!(),
}
}
}
pub struct MatVariableIntoIterator {
var: MatVariable,
count: usize,
}
impl Iterator for MatVariableIntoIterator {
type Item = MatVariable;
fn next(&mut self) -> Option<Self::Item> {
match &self.var {
MatVariable::NumericArray(v) => {
let ret = if self.count < v.value.len() {
Some(v.get_clone_colmaj(self.count).unwrap())
} else {
None
};
self.count += 1;
ret
}
_ => todo!(),
}
}
}
impl IntoIterator for MatVariable {
type Item = MatVariable;
type IntoIter = MatVariableIntoIterator;
fn into_iter(self) -> Self::IntoIter {
match &self {
MatVariable::NumericArray(_) => MatVariableIntoIterator { var: self, count: 0 },
_ => todo!(),
}
}
}
impl From<&str> for MatVariable {
fn from(value: &str) -> Self {
MatVariable::NumericArray(NumericArray::from(value))
}
}
impl<T> From<Vec<T>> for MatVariable
where
T: MatlabTypeMarker,
{
fn from(value: Vec<T>) -> Self {
MatVariable::NumericArray(
NumericArray::new(vec![1, value.len()], MatlabType::from(value), None)
.expect("Could not create NumericArray."),
)
}
}
impl<T> From<Vec<(T, T)>> for MatVariable
where
T: MatlabTypeMarker,
{
fn from(value: Vec<(T, T)>) -> Self {
let real = value.iter().map(|x| x.0).collect::<Vec<T>>();
let comp = value.iter().map(|x| x.1).collect::<Vec<T>>();
MatVariable::NumericArray(
NumericArray::new(
vec![1, value.len()],
MatlabType::from(real),
Some(MatlabType::from(comp)),
)
.expect("Could not create NumericArray."),
)
}
}
impl<T> From<T> for MatVariable
where
T: MatlabTypeMarker,
{
fn from(value: T) -> Self {
MatVariable::NumericArray(
NumericArray::new(vec![1, 1], MatlabType::from(vec![value]), None)
.expect("Could not create NumericArray."),
)
}
}
impl<T> From<(T, T)> for MatVariable
where
T: MatlabTypeMarker,
{
fn from(value: (T, T)) -> Self {
MatVariable::NumericArray(
NumericArray::new(
vec![1, 1],
MatlabType::from(vec![value.0]),
Some(MatlabType::from(vec![value.1])),
)
.expect("Could not create NumericArray."),
)
}
}
impl From<Vec<MatVariable>> for MatVariable {
fn from(value: Vec<MatVariable>) -> Self {
if value.iter().all(|x| matches!(x, MatVariable::Structure(_))) && check_same_fields(&value) {
MatVariable::StructureArray(StructureArray::from_structures(vec![1, value.len()], value))
} else {
MatVariable::CellArray(CellArray::new(vec![1, value.len()], value).unwrap())
}
}
}
impl From<MatVariable7> for MatVariable {
fn from(value: MatVariable7) -> Self {
match value {
MatVariable7::Compressed(v) => MatVariable::from(v),
MatVariable7::Numeric(v) => MatVariable::NumericArray(NumericArray::from(v)),
MatVariable7::Cell(v) => MatVariable::CellArray(CellArray::from(v)),
MatVariable7::Structure(v) => MatVariable::Structure(Structure::from(v)),
MatVariable7::StructureArray(v) => MatVariable::StructureArray(StructureArray::from(v)),
MatVariable7::Sparse(v) => MatVariable::SparseArray(SparseArray::from(v)),
MatVariable7::ObjectMCOS(_) => MatVariable::Unsupported,
MatVariable7::ObjectHandle(_) => MatVariable::Unsupported,
MatVariable7::Empty(_) => MatVariable::NumericArray(
NumericArray::new(vec![0, 0], MatlabType::new(), None)
.expect("Could not create NumericArray."),
),
}
}
}
impl From<CompressedArray7> for MatVariable {
fn from(value: CompressedArray7) -> Self {
match value.value() {
MatVariable7::Compressed(v) => MatVariable::from(v),
MatVariable7::Numeric(v) => MatVariable::NumericArray(NumericArray::from(v)),
MatVariable7::Cell(v) => MatVariable::CellArray(CellArray::from(v)),
MatVariable7::Structure(v) => MatVariable::Structure(Structure::from(v)),
MatVariable7::StructureArray(v) => MatVariable::StructureArray(StructureArray::from(v)),
MatVariable7::Sparse(v) => MatVariable::SparseArray(SparseArray::from(v)),
MatVariable7::ObjectMCOS(_) => MatVariable::Unsupported,
MatVariable7::ObjectHandle(_) => MatVariable::Unsupported,
MatVariable7::Empty(_) => MatVariable::NumericArray(
NumericArray::new(vec![0, 0], MatlabType::new(), None)
.expect("Could not create NumericArray."),
),
}
}
}
impl Display for MatVariable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MatVariable::NumericArray(v) => write!(f, "{}", v),
MatVariable::CellArray(_v) => todo!(),
MatVariable::Structure(_v) => todo!(),
MatVariable::StructureArray(_v) => todo!(),
MatVariable::SparseArray(v) => write!(f, "{}", v),
MatVariable::Null => todo!(),
MatVariable::Compressed(_v) => todo!(),
MatVariable::Unsupported => todo!(),
}
}
}
#[allow(unused)]
impl PartialEq for MatVariable {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::NumericArray(l0), Self::NumericArray(r0)) => l0 == r0,
(Self::CellArray(l0), Self::CellArray(r0)) => todo!(),
(Self::Structure(l0), Self::Structure(r0)) => todo!(),
(Self::StructureArray(l0), Self::StructureArray(r0)) => todo!(),
(Self::SparseArray(l0), Self::SparseArray(r0)) => todo!(),
(Self::Compressed(l0), Self::Compressed(r0)) => todo!(),
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn print_variable_size() {
println!("MatVariable size: {}", size_of::<MatVariable>());
}
}