use crate::data_read;
use crate::datatype::Datatype;
use crate::edit::AppendBuilder;
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]);
#[doc(hidden)]
fn append_into(builder: &mut AppendBuilder, data: &[Self]);
#[doc(hidden)]
fn fill_bytes(self) -> Vec<u8>;
#[doc(hidden)]
fn convert_raw(raw: &[u8], dt: &Datatype) -> Result<Vec<Self>, Error>;
}
macro_rules! impl_h5_element {
($ty:ty, $read:ident, $write:ident, $append:ident, |$raw:ident, $dt:ident| $convert:expr) => {
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);
}
fn append_into(builder: &mut AppendBuilder, data: &[Self]) {
builder.$append(data);
}
fn fill_bytes(self) -> Vec<u8> {
self.to_le_bytes().to_vec()
}
fn convert_raw($raw: &[u8], $dt: &Datatype) -> Result<Vec<Self>, Error> {
$convert
}
}
};
}
impl_h5_element!(f32, read_f32, with_f32_data, append_f32, |raw, dt| Ok(
data_read::read_as_f32(raw, dt)?
));
impl_h5_element!(f64, read_f64, with_f64_data, append_f64, |raw, dt| Ok(
data_read::read_as_f64(raw, dt)?
));
impl_h5_element!(i8, read_i8, with_i8_data, append_i8, |raw, dt| {
let _ = dt;
#[expect(
clippy::cast_possible_wrap,
reason = "reinterprets each stored byte as the signed i8 requested, matching read_i8"
)]
Ok(raw.iter().map(|&b| b as i8).collect())
});
impl_h5_element!(i16, read_i16, with_i16_data, append_i16, |raw, dt| Ok(
data_read::read_as_i16(raw, dt)?
));
impl_h5_element!(i32, read_i32, with_i32_data, append_i32, |raw, dt| Ok(
data_read::read_as_i32(raw, dt)?
));
impl_h5_element!(i64, read_i64, with_i64_data, append_i64, |raw, dt| Ok(
data_read::read_as_i64(raw, dt)?
));
impl_h5_element!(u8, read_u8, with_u8_data, append_u8, |raw, dt| {
let _ = dt;
Ok(raw.to_vec())
});
impl_h5_element!(u16, read_u16, with_u16_data, append_u16, |raw, dt| Ok(
data_read::read_as_u16(raw, dt)?
));
impl_h5_element!(u32, read_u32, with_u32_data, append_u32, |raw, dt| Ok(
data_read::read_as_u32(raw, dt)?
));
impl_h5_element!(u64, read_u64, with_u64_data, append_u64, |raw, dt| Ok(
data_read::read_as_u64(raw, dt)?
));
impl DatasetBuilder {
pub fn with_data<T: H5Element>(&mut self, data: &[T]) -> &mut Self {
T::write_into(self, data);
self
}
pub fn with_fill_value<T: H5Element>(&mut self, value: T) -> &mut Self {
self.fill = Some(T::fill_bytes(value));
self
}
}
impl Dataset {
pub fn read<T: H5Element>(&self) -> Result<Vec<T>, Error> {
T::read_from(self)
}
pub fn fill_value<T: H5Element>(&self) -> Result<Option<T>, Error> {
let Some(bytes) = self.defined_fill_bytes()? else {
return Ok(None);
};
let dt = self.datatype()?;
Ok(T::convert_raw(&bytes, &dt)?.into_iter().next())
}
}