use crate::wxf::NumericArrayEnum;
use crate::ByteArray;
mod sealed {
use crate::complex::{Complex32, Complex64};
pub trait Sealed {}
impl Sealed for i8 {}
impl Sealed for i16 {}
impl Sealed for i32 {}
impl Sealed for i64 {}
impl Sealed for u8 {}
impl Sealed for u16 {}
impl Sealed for u32 {}
impl Sealed for u64 {}
impl Sealed for f32 {}
impl Sealed for f64 {}
impl Sealed for Complex32 {}
impl Sealed for Complex64 {}
}
pub trait ArrayElement<Tag: Copy + PartialEq>: Copy + 'static + sealed::Sealed {
const TAG: Tag;
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ArrayBuf<Tag> {
pub(crate) data_type: Tag,
pub(crate) dimensions: Vec<usize>,
pub(crate) bytes: ByteArray,
}
impl<Tag: Copy + PartialEq> ArrayBuf<Tag> {
pub fn new(data_type: Tag, dimensions: Vec<usize>, bytes: ByteArray) -> Self {
ArrayBuf {
data_type,
dimensions,
bytes,
}
}
pub fn data_type(&self) -> Tag {
self.data_type
}
pub fn dimensions(&self) -> &[usize] {
&self.dimensions
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn rank(&self) -> usize {
self.dimensions.len()
}
pub fn element_count(&self) -> usize {
self.dimensions.iter().product()
}
pub fn byte_count(&self) -> usize {
self.bytes.len()
}
pub fn from_slice<T: ArrayElement<Tag>>(dimensions: Vec<usize>, slice: &[T]) -> Self {
assert_eq!(
dimensions.iter().product::<usize>(),
slice.len(),
"ArrayBuf::from_slice: dims product must equal slice length"
);
let bytes: &[u8] = unsafe {
std::slice::from_raw_parts(
slice.as_ptr() as *const u8,
std::mem::size_of_val(slice),
)
};
ArrayBuf::new(T::TAG, dimensions, ByteArray::from(bytes))
}
pub fn try_as_slice<T: ArrayElement<Tag>>(&self) -> Option<&[T]> {
if self.data_type != T::TAG {
return None;
}
let bytes = self.as_bytes();
let elem_size = std::mem::size_of::<T>();
debug_assert_eq!(bytes.len() % elem_size, 0);
if bytes.is_empty() {
return Some(&[]);
}
Some(unsafe {
std::slice::from_raw_parts(
bytes.as_ptr() as *const T,
bytes.len() / elem_size,
)
})
}
}
pub trait NumericArrayRead {
fn data_type(&self) -> NumericArrayEnum;
fn dimensions(&self) -> &[usize];
fn as_bytes(&self) -> &[u8];
fn rank(&self) -> usize {
self.dimensions().len()
}
fn element_count(&self) -> usize {
self.dimensions().iter().product()
}
fn byte_count(&self) -> usize {
self.as_bytes().len()
}
fn element_size(&self) -> usize {
self.data_type().size_in_bytes()
}
fn try_as_slice<T: ArrayElement<NumericArrayEnum>>(&self) -> Option<&[T]> {
if self.data_type() != T::TAG {
return None;
}
let bytes = self.as_bytes();
let elem_size = std::mem::size_of::<T>();
debug_assert_eq!(bytes.len() % elem_size, 0);
Some(unsafe {
std::slice::from_raw_parts(
bytes.as_ptr() as *const T,
bytes.len() / elem_size,
)
})
}
}
impl<Tag: Into<NumericArrayEnum> + Copy + PartialEq> NumericArrayRead for ArrayBuf<Tag> {
fn data_type(&self) -> NumericArrayEnum {
self.data_type.into()
}
fn dimensions(&self) -> &[usize] {
&self.dimensions
}
fn as_bytes(&self) -> &[u8] {
&self.bytes
}
}