use std::path::Path;
use crate::format::messages::attribute::AttributeMessage;
use crate::io::locking::FileLocking;
use crate::io::Hdf5Reader;
use crate::io::SwmrWriter as IoSwmrWriter;
use crate::error::Result;
use crate::types::H5Type;
pub struct SwmrFileWriter {
inner: IoSwmrWriter,
}
impl SwmrFileWriter {
pub fn create<P: AsRef<Path>>(path: P) -> Result<Self> {
let inner = IoSwmrWriter::create(path.as_ref())?;
Ok(Self { inner })
}
pub fn create_with_locking<P: AsRef<Path>>(path: P, locking: FileLocking) -> Result<Self> {
let inner = IoSwmrWriter::create_with_locking(path.as_ref(), locking)?;
Ok(Self { inner })
}
pub fn open_append<P: AsRef<Path>>(path: P) -> Result<Self> {
let inner = IoSwmrWriter::open_append(path.as_ref())?;
Ok(Self { inner })
}
pub fn open_append_with_locking<P: AsRef<Path>>(path: P, locking: FileLocking) -> Result<Self> {
let inner = IoSwmrWriter::open_append_with_locking(path.as_ref(), locking)?;
Ok(Self { inner })
}
pub fn dataset_index(&self, name: &str) -> Option<usize> {
self.inner.dataset_index(name)
}
pub fn create_streaming_dataset<T: H5Type>(
&mut self,
name: &str,
frame_dims: &[u64],
) -> Result<usize> {
let datatype = T::hdf5_type();
let idx = self
.inner
.create_streaming_dataset(name, datatype, frame_dims)?;
Ok(idx)
}
pub fn create_streaming_dataset_compressed<T: H5Type>(
&mut self,
name: &str,
frame_dims: &[u64],
pipeline: crate::format::messages::filter::FilterPipeline,
) -> Result<usize> {
let idx = self.inner.create_streaming_dataset_compressed(
name,
T::hdf5_type(),
frame_dims,
pipeline,
)?;
Ok(idx)
}
pub fn create_streaming_dataset_tiled<T: H5Type>(
&mut self,
name: &str,
frame_dims: &[u64],
frame_chunk: &[u64],
) -> Result<usize> {
let idx = self.inner.create_streaming_dataset_tiled(
name,
T::hdf5_type(),
frame_dims,
frame_chunk,
)?;
Ok(idx)
}
pub fn create_streaming_dataset_tiled_compressed<T: H5Type>(
&mut self,
name: &str,
frame_dims: &[u64],
frame_chunk: &[u64],
pipeline: crate::format::messages::filter::FilterPipeline,
) -> Result<usize> {
let idx = self.inner.create_streaming_dataset_tiled_compressed(
name,
T::hdf5_type(),
frame_dims,
frame_chunk,
pipeline,
)?;
Ok(idx)
}
pub fn create_streaming_dataset_chunked<T: H5Type>(
&mut self,
name: &str,
frame_dims: &[u64],
chunk: &[u64],
) -> Result<usize> {
let idx =
self.inner
.create_streaming_dataset_chunked(name, T::hdf5_type(), frame_dims, chunk)?;
Ok(idx)
}
pub fn create_streaming_dataset_chunked_compressed<T: H5Type>(
&mut self,
name: &str,
frame_dims: &[u64],
chunk: &[u64],
pipeline: crate::format::messages::filter::FilterPipeline,
) -> Result<usize> {
let idx = self.inner.create_streaming_dataset_chunked_compressed(
name,
T::hdf5_type(),
frame_dims,
chunk,
pipeline,
)?;
Ok(idx)
}
pub fn create_hard_link(
&mut self,
parent_group_path: &str,
link_name: &str,
target_path: &str,
) -> Result<()> {
self.inner
.writer_mut()
.create_hard_link(parent_group_path, link_name, target_path)?;
Ok(())
}
pub fn create_group(&mut self, parent_group_path: &str, name: &str) -> Result<()> {
self.inner
.writer_mut()
.create_group(parent_group_path, name)?;
Ok(())
}
pub fn set_group_attr_string(
&mut self,
group_path: &str,
name: &str,
value: &str,
) -> Result<()> {
let attr = AttributeMessage::scalar_string(name, value);
if group_path == "/" {
self.inner.writer_mut().add_root_attribute(attr);
} else {
self.inner
.writer_mut()
.add_group_attribute(group_path, attr)?;
}
Ok(())
}
pub fn set_group_attr_numeric<T: H5Type>(
&mut self,
group_path: &str,
name: &str,
value: &T,
) -> Result<()> {
let attr = AttributeMessage::scalar_numeric(name, T::hdf5_type(), scalar_to_bytes(value));
if group_path == "/" {
self.inner.writer_mut().add_root_attribute(attr);
} else {
self.inner
.writer_mut()
.add_group_attribute(group_path, attr)?;
}
Ok(())
}
pub fn write_dataset<T: H5Type>(
&mut self,
name: &str,
dims: &[u64],
data: &[T],
) -> Result<usize> {
let expected: u64 = if dims.is_empty() {
1
} else {
dims.iter().product()
};
if data.len() as u64 != expected {
return Err(crate::error::Hdf5Error::InvalidState(format!(
"write_dataset: data has {} elements but shape {dims:?} needs {expected}",
data.len()
)));
}
let idx = self
.inner
.writer_mut()
.create_dataset(name, T::hdf5_type(), dims)?;
self.inner
.writer_mut()
.write_dataset_raw(idx, slice_to_bytes(data))?;
Ok(idx)
}
pub fn write_string_dataset(&mut self, name: &str, strings: &[&str]) -> Result<usize> {
let idx = self
.inner
.writer_mut()
.create_vlen_string_dataset(name, strings)?;
Ok(idx)
}
pub fn set_dataset_attr_string(
&mut self,
ds_index: usize,
name: &str,
value: &str,
) -> Result<()> {
self.inner
.writer_mut()
.add_dataset_attribute(ds_index, AttributeMessage::scalar_string(name, value))?;
Ok(())
}
pub fn set_dataset_attr_numeric<T: H5Type>(
&mut self,
ds_index: usize,
name: &str,
value: &T,
) -> Result<()> {
let attr = AttributeMessage::scalar_numeric(name, T::hdf5_type(), scalar_to_bytes(value));
self.inner
.writer_mut()
.add_dataset_attribute(ds_index, attr)?;
Ok(())
}
pub fn set_dataset_fill_value<T: H5Type>(&mut self, ds_index: usize, value: &T) -> Result<()> {
self.inner
.writer_mut()
.set_dataset_fill_value(ds_index, scalar_to_bytes(value))?;
Ok(())
}
pub fn assign_dataset_to_group(&mut self, group_path: &str, ds_index: usize) -> Result<()> {
self.inner
.writer_mut()
.assign_dataset_to_group(group_path, ds_index)?;
Ok(())
}
pub fn start_swmr(&mut self) -> Result<()> {
self.inner.start_swmr()?;
Ok(())
}
pub fn append_frame(&mut self, ds_index: usize, data: &[u8]) -> Result<()> {
self.inner.append_frame(ds_index, data)?;
Ok(())
}
pub fn flush(&mut self) -> Result<()> {
self.inner.flush()?;
Ok(())
}
pub fn close(self) -> Result<()> {
self.inner.close()?;
Ok(())
}
}
pub struct SwmrFileReader {
reader: Hdf5Reader,
}
impl SwmrFileReader {
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
let reader = Hdf5Reader::open_swmr(path.as_ref())?;
Ok(Self { reader })
}
pub fn open_with_locking<P: AsRef<Path>>(path: P, locking: FileLocking) -> Result<Self> {
let reader = Hdf5Reader::open_swmr_with_locking(path.as_ref(), locking)?;
Ok(Self { reader })
}
pub fn refresh(&mut self) -> Result<()> {
self.reader.refresh()?;
Ok(())
}
pub fn dataset_names(&self) -> Vec<String> {
self.reader
.dataset_names()
.iter()
.map(|s| s.to_string())
.collect()
}
pub fn dataset_shape(&self, name: &str) -> Result<Vec<u64>> {
Ok(self.reader.dataset_shape(name)?)
}
pub fn read_dataset_raw(&mut self, name: &str) -> Result<Vec<u8>> {
Ok(self.reader.read_dataset_raw(name)?)
}
pub fn read_dataset<T: H5Type>(&mut self, name: &str) -> Result<Vec<T>> {
bytes_to_typed(self.reader.read_dataset_raw(name)?)
}
pub fn read_slice_raw(
&mut self,
name: &str,
starts: &[u64],
counts: &[u64],
) -> Result<Vec<u8>> {
Ok(self.reader.read_slice(name, starts, counts)?)
}
pub fn read_slice<T: H5Type>(
&mut self,
name: &str,
starts: &[u64],
counts: &[u64],
) -> Result<Vec<T>> {
bytes_to_typed(self.reader.read_slice(name, starts, counts)?)
}
pub fn read_vlen_strings(&mut self, name: &str) -> Result<Vec<String>> {
Ok(self.reader.read_vlen_strings(name)?)
}
pub fn dataset_element_size(&self, name: &str) -> Result<usize> {
self.reader
.dataset_info(name)
.map(|i| i.datatype.element_size() as usize)
.ok_or_else(|| crate::error::Hdf5Error::NotFound(name.to_string()))
}
pub fn group_paths(&self) -> Vec<String> {
self.reader.group_paths().iter().cloned().collect()
}
pub fn has_group(&self, group_path: &str) -> bool {
self.reader.has_group(group_path.trim_start_matches('/'))
}
pub fn dataset_attr_names(&self, name: &str) -> Result<Vec<String>> {
Ok(self.reader.dataset_attr_names(name)?)
}
pub fn dataset_attr_string(&mut self, dataset: &str, attr: &str) -> Result<String> {
let a = self.reader.dataset_attr(dataset, attr)?.clone();
Ok(self.reader.attr_string_value(&a)?)
}
pub fn group_attr_names(&self, group_path: &str) -> Vec<String> {
if group_path == "/" {
self.reader.root_attr_names()
} else {
self.reader
.group_attr_names(group_path.trim_start_matches('/'))
}
}
pub fn group_attr_string(&mut self, group_path: &str, attr: &str) -> Result<String> {
let a = if group_path == "/" {
self.reader.root_attr(attr)
} else {
self.reader
.group_attr(group_path.trim_start_matches('/'), attr)
}
.ok_or_else(|| crate::error::Hdf5Error::NotFound(attr.to_string()))?
.clone();
Ok(self.reader.attr_string_value(&a)?)
}
}
fn bytes_to_typed<T: H5Type>(raw: Vec<u8>) -> Result<Vec<T>> {
let es = T::element_size();
if es == 0 || !raw.len().is_multiple_of(es) {
return Err(crate::error::Hdf5Error::TypeMismatch(format!(
"raw data size {} is not a multiple of element size {es}",
raw.len()
)));
}
let count = raw.len() / es;
let mut result = Vec::<T>::with_capacity(count);
unsafe {
std::ptr::copy_nonoverlapping(raw.as_ptr(), result.as_mut_ptr() as *mut u8, raw.len());
result.set_len(count);
}
Ok(result)
}
fn scalar_to_bytes<T: H5Type>(value: &T) -> Vec<u8> {
let es = T::element_size();
unsafe { std::slice::from_raw_parts(value as *const T as *const u8, es) }.to_vec()
}
fn slice_to_bytes<T: H5Type>(data: &[T]) -> &[u8] {
unsafe { std::slice::from_raw_parts(data.as_ptr() as *const u8, std::mem::size_of_val(data)) }
}