use std::collections::HashMap;
use rustyhdf5::AttrValue;
use crate::error::Error;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Dimension {
pub name: String,
pub size: u64,
pub is_unlimited: bool,
}
pub(crate) fn extract_dimensions(
file: &rustyhdf5::File,
group: &rustyhdf5::Group<'_>,
) -> Result<Vec<Dimension>, Error> {
let dataset_names = group.datasets()?;
let mut dims = Vec::new();
let mut seen_dimids: HashMap<i64, usize> = HashMap::new();
for ds_name in &dataset_names {
let ds = group.dataset(ds_name)?;
let attrs = ds.attrs()?;
if !is_dimension_scale(&attrs) {
continue;
}
let shape = ds.shape()?;
let size = shape.first().copied().unwrap_or(0);
let is_unlimited = check_unlimited(file, group, ds_name);
let dimid = get_dimid(&attrs);
let dim = Dimension {
name: ds_name.clone(),
size,
is_unlimited,
};
if let Some(id) = dimid {
seen_dimids.insert(id, dims.len());
}
dims.push(dim);
}
if !seen_dimids.is_empty() {
let mut pairs: Vec<(i64, Dimension)> = Vec::new();
let mut unordered = Vec::new();
for (i, dim) in dims.into_iter().enumerate() {
let id = seen_dimids.iter().find(|(_, idx)| **idx == i).map(|(k, _)| *k);
if let Some(id) = id {
pairs.push((id, dim));
} else {
unordered.push(dim);
}
}
pairs.sort_by_key(|(id, _)| *id);
dims = pairs.into_iter().map(|(_, d)| d).collect();
dims.extend(unordered);
}
Ok(dims)
}
fn is_dimension_scale(attrs: &HashMap<String, AttrValue>) -> bool {
if let Some(AttrValue::String(class)) = attrs.get("CLASS") {
return class == "DIMENSION_SCALE";
}
false
}
fn get_dimid(attrs: &HashMap<String, AttrValue>) -> Option<i64> {
match attrs.get("_Netcdf4Dimid") {
Some(AttrValue::I64(id)) => Some(*id),
Some(AttrValue::U64(id)) => Some(*id as i64),
_ => None,
}
}
fn check_unlimited(
file: &rustyhdf5::File,
group: &rustyhdf5::Group<'_>,
ds_name: &str,
) -> bool {
let sb = file.superblock();
let data = file.as_bytes();
let ds = match group.dataset(ds_name) {
Ok(ds) => ds,
Err(_) => return false,
};
let _ = (sb, data);
check_unlimited_low_level(file, ds_name, &ds)
}
fn check_unlimited_low_level(
file: &rustyhdf5::File,
_ds_name: &str,
_ds: &rustyhdf5::Dataset<'_>,
) -> bool {
let data = file.as_bytes();
let sb = file.superblock();
let _ = (data, sb);
false
}
pub(crate) fn extract_dimensions_from_datasets(
group: &rustyhdf5::Group<'_>,
file: &rustyhdf5::File,
) -> Result<Vec<Dimension>, Error> {
let mut dims = extract_dimensions(file, group)?;
if !dims.is_empty() {
return Ok(dims);
}
let dataset_names = group.datasets()?;
for ds_name in &dataset_names {
let ds = group.dataset(ds_name)?;
let shape = ds.shape()?;
if shape.len() == 1 {
let is_unlimited = check_unlimited(file, group, ds_name);
dims.push(Dimension {
name: ds_name.clone(),
size: shape[0],
is_unlimited,
});
}
}
Ok(dims)
}