Reputation: 1977
Given an hdf5 Dataset, there is the is_scalar method to check if it is a scalar.
However, when I read that scalar, I need to specify the type I wish to read that scalar into as in the code below.
let ds: Dataset = group.handler
.dataset(dataset_name.as_ref())
.unwrap();
if ds.is_scalar() {
let x: hdf5::types::VarLenUnicode = ds.read_scalar();
}
In this example above I specified that I wish to read the scalar into the hdf5::types::VarLenUnicode
type.
This works fine when I know precisely what type to expect.
In some other circumstances however, I do not have the type information of the hdf5 Dataset in advance.
Depending on the datatype, I wish to process the Dataset differently. Is there a way of checking the datatype of the scalar before reading it?
What would be an idiomatic way of reading an hdf5 Dataset that could contain either a string or a float?
Similarly, is it possible to read and cast the hdf5 dataset into a string even if it contains a float?
Upvotes: 1
Views: 336
Reputation: 1977
Here is a working solution that starts with the to_descriptor() method, eggyal posted on comments.
After getting the TypeDescriptor
value, we need to handle every possible case (the Rust way).
match ds_type.to_descriptor().unwrap() {
hdf5::types::TypeDescriptor::Float(_) => {
self.show_dataset::<f64>(&ds, dataset, ctx, &mut is_open);
}
hdf5::types::TypeDescriptor::VarLenUnicode => {
self.show_dataset::<hdf5::types::VarLenUnicode>(
&ds,
dataset,
ctx,
&mut is_open,
);
}
hdf5::types::TypeDescriptor::Integer(_) => {
self.show_dataset::<i64>(&ds, dataset, ctx, &mut is_open);
}
hdf5::types::TypeDescriptor::Unsigned(_) => {
self.show_dataset::<u64>(&ds, dataset, ctx, &mut is_open);
}
hdf5::types::TypeDescriptor::Boolean => {
self.show_dataset::<bool>(&ds, dataset, ctx, &mut is_open);
}
hdf5::types::TypeDescriptor::Enum(_) => todo!(),
hdf5::types::TypeDescriptor::Compound(_) => todo!(),
hdf5::types::TypeDescriptor::FixedArray(_, _) => todo!(),
hdf5::types::TypeDescriptor::FixedAscii(_) => todo!(),
hdf5::types::TypeDescriptor::FixedUnicode(_) => todo!(),
hdf5::types::TypeDescriptor::VarLenArray(_) => todo!(),
hdf5::types::TypeDescriptor::VarLenAscii => {
self.show_dataset::<hdf5::types::VarLenAscii>(
&ds,
dataset,
ctx,
&mut is_open,
);
}
}
Later in the processing, in case of a scalar I just had to display the contents of the scalar types via the std::fmt::Display
. I used generic types there to avoid code duplication in processing different types.
In the case of a non-scalar (vector), I used read_raw
to load it.
fn show_dataset<T: hdf5::H5Type + std::fmt::Display>(
&mut self,
ds: &hdf5::Dataset,
dataset: &str,
ctx: &egui::Context,
is_open: &mut bool,
) {
if ds.is_scalar() {
let x_data: T = ds.read_scalar().unwrap();
Window::new(dataset.to_owned())
.open(is_open)
.vscroll(true)
.resizable(true)
.default_height(300.0)
.show(ctx, |ui| {
ui.label(format!("{}", x_data));
});
} else {
let x_data: Vec<T> = ds.read_raw().unwrap();
let mut table_box = Box::<super::table::TableWindow<T>>::default();
table_box.set_name(dataset.to_owned());
table_box.set_data(x_data);
table_box.show(ctx, is_open);
}
}
There is a caveat in this solution though.
As you probably have already noticed, these types below are not handled. In my application, those types are not needed to be handled but in general I do not know how these types could possibly be handled.
hdf5::types::TypeDescriptor::FixedArray(_, _) => todo!(),
hdf5::types::TypeDescriptor::FixedAscii(_) => todo!(),
hdf5::types::TypeDescriptor::FixedUnicode(_) => todo!(),
Upvotes: 1