use ndarray::{Array, ArrayBase, ArrayD, Data, Dimension, IxDyn};
use crate::convert::TryToUsize;
use crate::error::Error;
use crate::reader::Dataset;
use crate::type_builders::DatasetBuilder;
mod sealed {
pub trait Sealed {}
}
pub trait H5Element: sealed::Sealed + Copy {
#[doc(hidden)]
fn read_from(ds: &Dataset<'_>) -> Result<Vec<Self>, Error>;
#[doc(hidden)]
fn write_into(builder: &mut DatasetBuilder, data: &[Self]);
}
macro_rules! impl_h5_element {
($ty:ty, $read:ident, $write:ident) => {
impl sealed::Sealed for $ty {}
impl H5Element for $ty {
fn read_from(ds: &Dataset<'_>) -> Result<Vec<Self>, Error> {
ds.$read()
}
fn write_into(builder: &mut DatasetBuilder, data: &[Self]) {
builder.$write(data);
}
}
};
}
impl_h5_element!(f32, read_f32, with_f32_data);
impl_h5_element!(f64, read_f64, with_f64_data);
impl_h5_element!(i8, read_i8, with_i8_data);
impl_h5_element!(i16, read_i16, with_i16_data);
impl_h5_element!(i32, read_i32, with_i32_data);
impl_h5_element!(i64, read_i64, with_i64_data);
impl_h5_element!(u8, read_u8, with_u8_data);
impl_h5_element!(u16, read_u16, with_u16_data);
impl_h5_element!(u32, read_u32, with_u32_data);
impl_h5_element!(u64, read_u64, with_u64_data);
impl Dataset<'_> {
pub fn read_array<T: H5Element, D: Dimension>(&self) -> Result<Array<T, D>, Error> {
self.read_array_dyn::<T>()?
.into_dimensionality::<D>()
.map_err(|e| Error::Shape(e.to_string()))
}
pub fn read_array_dyn<T: H5Element>(&self) -> Result<ArrayD<T>, Error> {
let shape: Vec<usize> = self
.shape()?
.iter()
.map(|&d| d.to_usize())
.collect::<Result<Vec<_>, _>>()?;
let data = T::read_from(self)?;
ArrayD::from_shape_vec(IxDyn(&shape), data).map_err(|e| Error::Shape(e.to_string()))
}
}
impl DatasetBuilder {
pub fn with_ndarray<T, S, D>(&mut self, arr: &ArrayBase<S, D>) -> &mut Self
where
T: H5Element,
S: Data<Elem = T>,
D: Dimension,
{
let shape: Vec<u64> = arr.shape().iter().map(|&d| d as u64).collect();
let standard = arr.as_standard_layout();
let flat = standard
.as_slice()
.expect("as_standard_layout yields a contiguous standard-layout array");
T::write_into(self, flat);
self.shape = Some(shape);
self
}
}