use ndarr as nd;
use ndarr::IntoDimension;
use ndarr::ShapeBuilder;
use num_complex::Complex;
use std::convert::TryInto;
#[derive(Debug)]
pub enum Error {
ShapeError,
TypeError,
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Error::ShapeError => write!(f, "Array shapes do not match"),
Error::TypeError => write!(f, "Array types are not compatible"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
macro_rules! dynamic_conversions {
( $num:ty, $variant:ident ) => {
impl<'me> TryInto<nd::ArrayViewD<'me, $num>> for &'me crate::Array {
type Error = Error;
fn try_into(self) -> Result<nd::ArrayViewD<'me, $num>, Self::Error> {
match self.data() {
crate::NumericData::$variant {
ref real,
imag: None,
} => {
let dimension: nd::IxDyn = self.size().clone().into_dimension();
nd::ArrayView::from_shape(dimension.set_f(true), real)
.map_err(|_err| Error::ShapeError)
}
_ => Err(Error::TypeError),
}
}
}
impl TryInto<nd::ArrayD<$num>> for &crate::Array {
type Error = Error;
fn try_into(self) -> Result<nd::ArrayD<$num>, Self::Error> {
match self.data() {
crate::NumericData::$variant {
ref real,
imag: None,
} => {
let dimension: nd::IxDyn = self.size().clone().into_dimension();
nd::Array::from_shape_vec(dimension.set_f(true), real.clone())
.map_err(|_err| Error::ShapeError)
}
_ => Err(Error::TypeError),
}
}
}
impl TryInto<nd::ArrayD<Complex<$num>>> for &crate::Array {
type Error = Error;
fn try_into(self) -> Result<nd::ArrayD<Complex<$num>>, Self::Error> {
match self.data() {
crate::NumericData::$variant {
ref real,
imag: Some(ref imag),
} => {
let dimension: nd::IxDyn = self.size().clone().into_dimension();
let values = real
.iter()
.zip(imag.iter())
.map(|(&re, &im)| Complex::new(re, im))
.collect();
nd::Array::from_shape_vec(dimension.set_f(true), values)
.map_err(|_err| Error::ShapeError)
}
_ => Err(Error::TypeError),
}
}
}
};
}
macro_rules! static_conversions_n {
( $num:ty, $variant:ident, $ndims:literal ) => {
impl<'me> TryInto<nd::ArrayView<'me, $num, nd::Dim<[nd::Ix; $ndims]>>>
for &'me crate::Array
{
type Error = Error;
fn try_into(
self,
) -> Result<nd::ArrayView<'me, $num, nd::Dim<[nd::Ix; $ndims]>>, Self::Error> {
let size = self.size();
if size.len() != $ndims {
return Err(Error::ShapeError);
}
let mut shape = [0; $ndims];
shape.copy_from_slice(size);
match self.data() {
crate::NumericData::$variant {
ref real,
imag: None,
} => {
let dimension: nd::Dim<[nd::Ix; $ndims]> = shape.into_dimension();
nd::ArrayView::from_shape(dimension.set_f(true), real)
.map_err(|_err| Error::ShapeError)
}
_ => Err(Error::TypeError),
}
}
}
impl TryInto<nd::Array<$num, nd::Dim<[nd::Ix; $ndims]>>> for &crate::Array {
type Error = Error;
fn try_into(self) -> Result<nd::Array<$num, nd::Dim<[nd::Ix; $ndims]>>, Self::Error> {
let size = self.size();
if size.len() != $ndims {
return Err(Error::ShapeError);
}
let mut shape = [0; $ndims];
shape.copy_from_slice(size);
match self.data() {
crate::NumericData::$variant {
ref real,
imag: None,
} => {
let dimension: nd::Dim<[nd::Ix; $ndims]> = shape.into_dimension();
nd::Array::from_shape_vec(dimension.set_f(true), real.clone())
.map_err(|_err| Error::ShapeError)
}
_ => Err(Error::TypeError),
}
}
}
impl TryInto<nd::Array<Complex<$num>, nd::Dim<[nd::Ix; $ndims]>>> for &crate::Array {
type Error = Error;
fn try_into(
self,
) -> Result<nd::Array<Complex<$num>, nd::Dim<[nd::Ix; $ndims]>>, Self::Error> {
let size = self.size();
if size.len() != $ndims {
return Err(Error::ShapeError);
}
let mut shape = [0; $ndims];
shape.copy_from_slice(size);
match self.data() {
crate::NumericData::$variant {
ref real,
imag: Some(ref imag),
} => {
let dimension: nd::Dim<[nd::Ix; $ndims]> = shape.into_dimension();
let values = real
.iter()
.zip(imag.iter())
.map(|(&re, &im)| Complex::new(re, im))
.collect();
nd::Array::from_shape_vec(dimension.set_f(true), values)
.map_err(|_err| Error::ShapeError)
}
_ => Err(Error::TypeError),
}
}
}
};
}
macro_rules! static_conversions {
( $num:ty, $variant:ident ) => {
static_conversions_n!($num, $variant, 2);
static_conversions_n!($num, $variant, 3);
static_conversions_n!($num, $variant, 4);
static_conversions_n!($num, $variant, 5);
static_conversions_n!($num, $variant, 6);
};
}
macro_rules! all_conversions {
( $num:ty, $variant:ident ) => {
dynamic_conversions!($num, $variant);
static_conversions!($num, $variant);
};
}
all_conversions!(f64, Double);
all_conversions!(f32, Single);
all_conversions!(i64, Int64);
all_conversions!(u64, UInt64);
all_conversions!(i32, Int32);
all_conversions!(u32, UInt32);
all_conversions!(i16, Int16);
all_conversions!(u16, UInt16);
all_conversions!(i8, Int8);
all_conversions!(u8, UInt8);