#![allow(dead_code)]
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq)]
pub enum Hdf5Error {
NotFound(String),
AlreadyExists(String),
HyperslabOutOfRange {
dim: usize,
start: usize,
count: usize,
size: usize,
},
ShapeMismatch {
expected: Vec<usize>,
got: Vec<usize>,
},
FileLocked,
LinkTargetNotFound(String),
Generic(String),
}
impl std::fmt::Display for Hdf5Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Hdf5Error::NotFound(p) => write!(f, "HDF5: not found: {p}"),
Hdf5Error::AlreadyExists(p) => write!(f, "HDF5: already exists: {p}"),
Hdf5Error::HyperslabOutOfRange {
dim,
start,
count,
size,
} => write!(
f,
"HDF5: hyperslab out of range: dim={dim} start={start} count={count} size={size}"
),
Hdf5Error::ShapeMismatch { expected, got } => {
write!(
f,
"HDF5: shape mismatch: expected {expected:?}, got {got:?}"
)
}
Hdf5Error::FileLocked => write!(f, "HDF5: file is locked"),
Hdf5Error::LinkTargetNotFound(t) => {
write!(f, "HDF5: link target not found: {t}")
}
Hdf5Error::Generic(msg) => write!(f, "HDF5: {msg}"),
}
}
}
pub type Hdf5Result<T> = Result<T, Hdf5Error>;
#[derive(Debug, Clone, PartialEq)]
pub enum Hdf5Dtype {
Float32,
Float64,
Int32,
Uint8,
VlenString,
Compound(Vec<(String, Hdf5Dtype)>),
Named {
name: String,
base: Box<Hdf5Dtype>,
},
}
impl Hdf5Dtype {
pub fn element_size(&self) -> usize {
match self {
Hdf5Dtype::Float32 => 4,
Hdf5Dtype::Float64 => 8,
Hdf5Dtype::Int32 => 4,
Hdf5Dtype::Uint8 => 1,
Hdf5Dtype::VlenString => 0,
Hdf5Dtype::Compound(fields) => fields.iter().map(|(_, dt)| dt.element_size()).sum(),
Hdf5Dtype::Named { base, .. } => base.element_size(),
}
}
}
#[derive(Debug, Clone)]
pub struct ChunkLayout {
pub chunk_shape: Vec<usize>,
pub gzip_level: u8,
}
impl ChunkLayout {
pub fn new(chunk_shape: Vec<usize>, gzip_level: u8) -> Self {
Self {
chunk_shape,
gzip_level: gzip_level.min(9),
}
}
pub fn chunk_volume(&self) -> usize {
self.chunk_shape.iter().product()
}
}
#[derive(Debug, Clone)]
pub struct Hyperslab {
pub start: Vec<usize>,
pub count: Vec<usize>,
}
impl Hyperslab {
pub fn new(start: Vec<usize>, count: Vec<usize>) -> Self {
assert_eq!(
start.len(),
count.len(),
"Hyperslab: start and count must have equal rank"
);
Self { start, count }
}
pub fn volume(&self) -> usize {
self.count.iter().product()
}
pub fn validate(&self, shape: &[usize]) -> Hdf5Result<()> {
if self.start.len() != shape.len() {
return Err(Hdf5Error::Generic(format!(
"Hyperslab rank {} != dataset rank {}",
self.start.len(),
shape.len()
)));
}
for (dim, (&s, (&c, &sz))) in self
.start
.iter()
.zip(self.count.iter().zip(shape.iter()))
.enumerate()
{
if s + c > sz {
return Err(Hdf5Error::HyperslabOutOfRange {
dim,
start: s,
count: c,
size: sz,
});
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum AttrValue {
Float64(f64),
Float32(f32),
Int32(i32),
String(String),
ArrayF64(Vec<f64>),
ArrayF32(Vec<f32>),
ArrayI32(Vec<i32>),
}
#[derive(Debug, Clone)]
pub enum DataStorage {
Float32(Vec<f32>),
Float64(Vec<f64>),
Int32(Vec<i32>),
Uint8(Vec<u8>),
VlenString(Vec<String>),
Compound(Vec<HashMap<String, f64>>),
}
impl DataStorage {
pub fn len(&self) -> usize {
match self {
DataStorage::Float32(v) => v.len(),
DataStorage::Float64(v) => v.len(),
DataStorage::Int32(v) => v.len(),
DataStorage::Uint8(v) => v.len(),
DataStorage::VlenString(v) => v.len(),
DataStorage::Compound(v) => v.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[derive(Debug, Clone)]
pub enum Hdf5Link {
Soft(String),
Hard(String),
}
#[derive(Debug, Clone)]
pub struct ExternalRef {
pub filename: String,
pub dataset_path: String,
pub byte_offset: u64,
}
#[derive(Debug, Clone)]
pub struct DimScale {
pub scale_dataset: String,
pub axis: usize,
pub label: String,
}
#[derive(Debug, Clone)]
pub struct CollectiveIoMeta {
pub n_ranks: usize,
pub root_rank: usize,
pub total_bytes: u64,
pub wall_time_s: f64,
}
#[derive(Debug, Clone, PartialEq)]
pub enum LockState {
Unlocked,
WriteLocked {
owner_id: u64,
},
ReadLocked {
n_readers: usize,
},
}
#[derive(Debug, Clone)]
pub struct ParallelHdf5Meta {
pub n_ranks: usize,
pub rank_byte_counts: Vec<u64>,
pub collective_metadata: bool,
pub lock_held: bool,
}
impl ParallelHdf5Meta {
pub fn new(n_ranks: usize) -> Self {
Self {
n_ranks,
rank_byte_counts: vec![0; n_ranks],
collective_metadata: true,
lock_held: false,
}
}
pub fn record_rank_bytes(&mut self, rank: usize, bytes: u64) {
if rank < self.n_ranks {
self.rank_byte_counts[rank] = bytes;
}
}
pub fn total_bytes(&self) -> u64 {
self.rank_byte_counts.iter().sum()
}
}