From ca10fab2f665475bbbe818b569cb88ff239929bf Mon Sep 17 00:00:00 2001 From: Magnus Ulimoen Date: Thu, 3 Jun 2021 00:00:45 +0200 Subject: [PATCH 01/23] Add more iterators on Group --- hdf5-sys/src/h5o.rs | 18 ++-- src/hl/group.rs | 224 ++++++++++++++++++++++++++++++++++++++++---- src/lib.rs | 1 + 3 files changed, 216 insertions(+), 27 deletions(-) diff --git a/hdf5-sys/src/h5o.rs b/hdf5-sys/src/h5o.rs index d51ad1342..eb7602855 100644 --- a/hdf5-sys/src/h5o.rs +++ b/hdf5-sys/src/h5o.rs @@ -370,15 +370,15 @@ impl Default for H5O_token_t { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct H5O_info2_t { - fileno: c_ulong, - token: H5O_token_t, - type_: H5O_type_t, - rc: c_uint, - atime: time_t, - mtime: time_t, - ctime: time_t, - btime: time_t, - num_attrs: hsize_t, + pub fileno: c_ulong, + pub token: H5O_token_t, + pub type_: H5O_type_t, + pub rc: c_uint, + pub atime: time_t, + pub mtime: time_t, + pub ctime: time_t, + pub btime: time_t, + pub num_attrs: hsize_t, } #[cfg(hdf5_1_12_0)] diff --git a/src/hl/group.rs b/src/hl/group.rs index 4682672d7..31abf8966 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -10,6 +10,7 @@ use hdf5_sys::{ H5L_info_t, H5L_iterate_t, H5Lcreate_external, H5Lcreate_hard, H5Lcreate_soft, H5Ldelete, H5Lexists, H5Literate, H5Lmove, H5L_SAME_LOC, }, + h5o::H5O_type_t::{self, H5O_TYPE_DATASET, H5O_TYPE_GROUP, H5O_TYPE_NAMED_DATATYPE}, h5p::{H5Pcreate, H5Pset_create_intermediate_group}, }; @@ -212,37 +213,196 @@ impl Group { let name = to_cstring(name)?; Dataset::from_id(h5try!(H5Dopen2(self.id(), name.as_ptr(), H5P_DEFAULT))) } +} - /// Returns names of all the members in the group, non-recursively. - pub fn member_names(&self) -> Result> { - extern "C" fn members_callback( - _id: hid_t, name: *const c_char, _info: *const H5L_info_t, op_data: *mut c_void, - ) -> herr_t { - panic::catch_unwind(|| { - let other_data: &mut Vec = unsafe { &mut *(op_data.cast::>()) }; +pub enum TraversalOrder { + Lexicographic, + Creation, +} + +impl From for H5_index_t { + fn from(v: TraversalOrder) -> Self { + use hdf5_sys::h5::{H5_INDEX_CRT_ORDER, H5_INDEX_NAME}; + match v { + TraversalOrder::Lexicographic => H5_INDEX_NAME, + TraversalOrder::Creation => H5_INDEX_CRT_ORDER, + } + } +} + +pub enum IterationOrder { + Increasing, + Decreasing, + Native, +} - other_data.push(string_from_cstr(name)); +impl From for H5_iter_order_t { + fn from(v: IterationOrder) -> Self { + use hdf5_sys::h5::{H5_ITER_DEC, H5_ITER_INC, H5_ITER_NATIVE}; + match v { + IterationOrder::Increasing => H5_ITER_INC, + IterationOrder::Decreasing => H5_ITER_DEC, + IterationOrder::Native => H5_ITER_NATIVE, + } + } +} - 0 // Continue iteration +/// Iteration methods +impl Group { + /// Visits all objects in the group + pub fn iter_visit( + &self, mut op: F, mut val: G, order: (IterationOrder, TraversalOrder), + ) -> Result + where + F: Fn(&Self, &std::ffi::CStr, &H5L_info_t, &mut G) -> bool, + { + /// Struct used to pass a tuple + struct Vtable<'a, F, D> { + f: &'a mut F, + d: &'a mut D, + } + // Maps a closure to a C callback + // + // This function will be called multiple times, but never concurrently + extern "C" fn callback( + id: hid_t, name: *const c_char, info: *const H5L_info_t, op_data: *mut c_void, + ) -> herr_t + where + F: FnMut(&Group, &std::ffi::CStr, &H5L_info_t, &mut G) -> bool, + { + panic::catch_unwind(|| { + let vtable = op_data.cast::>(); + let vtable = unsafe { vtable.as_mut().expect("op_data is always non-null") }; + let name = unsafe { std::ffi::CStr::from_ptr(name) }; + let info = unsafe { info.as_ref().unwrap() }; + let handle = Handle::try_new(id).unwrap(); + handle.incref(); + let group = Group::from_handle(handle); + if (vtable.f)(&group, name, info, vtable.d) { + 0 + } else { + 1 + } }) .unwrap_or(-1) } - let callback_fn: H5L_iterate_t = Some(members_callback); - let iteration_position: *mut hsize_t = &mut { 0_u64 }; - let mut result: Vec = Vec::new(); - let other_data: *mut c_void = (&mut result as *mut Vec).cast::(); + let callback_fn: H5L_iterate_t = Some(callback::); + let iter_pos: *mut hsize_t = &mut 0_u64; + + // Store our references on the heap + let mut vtable = Vtable { f: &mut op, d: &mut val }; + let other_data = (&mut vtable as *mut Vtable<_, _>).cast::(); h5call!(H5Literate( self.id(), - H5_index_t::H5_INDEX_NAME, - H5_iter_order_t::H5_ITER_INC, - iteration_position, + order.1.into(), + order.0.into(), + iter_pos, callback_fn, other_data - ))?; + )) + .map(|_| val) + } + + fn get_all_of_type(&self, typ: H5O_type_t) -> Result> { + #[cfg(not(hdf5_1_10_3))] + use hdf5_sys::h5o::{H5Oget_info_by_name as H5Oget_info_by_name1, H5Oopen_by_addr}; + #[cfg(all(hdf5_1_10_3, not(hdf5_1_12_0)))] + use hdf5_sys::h5o::{H5Oget_info_by_name2, H5Oopen_by_addr, H5O_INFO_BASIC}; + #[cfg(hdf5_1_12_0)] + use hdf5_sys::h5o::{H5Oget_info_by_name3, H5Oopen_by_token, H5O_INFO_BASIC}; + + let objects = vec![]; + + self.iter_visit( + |group, name, _info, objects| { + let mut infobuf = std::mem::MaybeUninit::uninit(); + #[cfg(hdf5_1_12_0)] + if h5call!(H5Oget_info_by_name3( + group.id(), + name.as_ptr(), + infobuf.as_mut_ptr(), + H5O_INFO_BASIC, + H5P_DEFAULT + )) + .is_err() + { + return true; + }; + #[cfg(all(hdf5_1_10_3, not(hdf5_1_12_0)))] + if h5call!(H5Oget_info_by_name2( + group.id(), + name.as_ptr(), + infobuf.as_mut_ptr(), + H5O_INFO_BASIC, + H5P_DEFAULT + )) + .is_err() + { + return true; + }; + #[cfg(not(hdf5_1_10_3))] + if h5call!(H5Oget_info_by_name1( + group.id(), + name.as_ptr(), + infobuf.as_mut_ptr(), + H5P_DEFAULT + )) + .is_err() + { + return true; + }; + let infobuf = unsafe { infobuf.assume_init() }; + if infobuf.type_ == typ { + #[cfg(hdf5_1_12_0)] + if let Ok(id) = h5call!(H5Oopen_by_token(group.id(), infobuf.token)) { + if let Ok(handle) = Handle::try_new(id) { + objects.push(handle); + } + } + #[cfg(not(hdf5_1_12_0))] + if let Ok(id) = h5call!(H5Oopen_by_addr(group.id(), infobuf.addr)) { + if let Ok(handle) = Handle::try_new(id) { + objects.push(handle); + } + } + } + true + }, + objects, + (IterationOrder::Native, TraversalOrder::Lexicographic), + ) + } + + /// Returns all groups in the group, non-recursively + pub fn groups(&self) -> Result> { + self.get_all_of_type(H5O_TYPE_GROUP) + .map(|vec| vec.into_iter().map(Self::from_handle).collect()) + } + + /// Returns all datasets in the group, non-recursively + pub fn datasets(&self) -> Result> { + self.get_all_of_type(H5O_TYPE_DATASET) + .map(|vec| vec.into_iter().map(Dataset::from_handle).collect()) + } + + /// Returns all named types in the group, non-recursively + pub fn datatypes(&self) -> Result> { + self.get_all_of_type(H5O_TYPE_NAMED_DATATYPE) + .map(|vec| vec.into_iter().map(Datatype::from_handle).collect()) + } - Ok(result) + /// Returns the names of all objects in the group, non-recursively. + pub fn member_names(&self) -> Result> { + self.iter_visit( + |_, name, _, names| { + names.push(name.to_str().unwrap().to_owned()); + true + }, + vec![], + (IterationOrder::Native, TraversalOrder::Lexicographic), + ) } } @@ -471,4 +631,32 @@ pub mod tests { assert_eq!(dset2.read_scalar::().unwrap(), 13); }) } + + #[test] + pub fn test_iterators() { + with_tmp_file(|file| { + file.create_group("a").unwrap(); + file.create_group("b").unwrap(); + let group_a = file.group("a").unwrap(); + let _group_b = file.group("b").unwrap(); + file.new_dataset::().shape((10, 20)).create("a/foo").unwrap(); + file.new_dataset::().shape((10, 20)).create("a/123").unwrap(); + file.new_dataset::().shape((10, 20)).create("a/bar").unwrap(); + + let groups = file.groups().unwrap(); + assert_eq!(groups.len(), 2); + for group in groups { + assert!(matches!(group.name().as_ref(), "/a" | "/b")); + } + + let datasets = file.datasets().unwrap(); + assert_eq!(datasets.len(), 0); + + let datasets = group_a.datasets().unwrap(); + assert_eq!(datasets.len(), 3); + for dataset in datasets { + assert!(matches!(dataset.name().as_ref(), "/a/foo" | "/a/123" | "/a/bar")); + } + }) + } } diff --git a/src/lib.rs b/src/lib.rs index 24bec1640..f7d8eb832 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ #![cfg_attr(feature = "cargo-clippy", allow(clippy::unnecessary_unwrap))] #![cfg_attr(feature = "cargo-clippy", allow(clippy::unnecessary_wraps))] #![cfg_attr(feature = "cargo-clippy", allow(clippy::upper_case_acronyms))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::missing_panics_doc))] #![cfg_attr(all(feature = "cargo-clippy", test), allow(clippy::cyclomatic_complexity))] #![cfg_attr(not(test), allow(dead_code))] From baab13f9f87dbe2c138645ea92000c152cbcdea5 Mon Sep 17 00:00:00 2001 From: Magnus Ulimoen Date: Wed, 6 Oct 2021 19:38:42 +0000 Subject: [PATCH 02/23] Prefer rename of hdf5-sys items --- hdf5-sys/src/h5o.rs | 17 +++++++++++++---- src/hl/group.rs | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/hdf5-sys/src/h5o.rs b/hdf5-sys/src/h5o.rs index eb7602855..4d3b46d62 100644 --- a/hdf5-sys/src/h5o.rs +++ b/hdf5-sys/src/h5o.rs @@ -9,6 +9,11 @@ pub use { }; #[cfg(hdf5_1_12_0)] pub use {H5O_info2_t as H5O_info_t, H5O_iterate2_t as H5O_iterate_t}; +#[cfg(not(hdf5_1_10_3))] +pub use { + H5Oget_info_by_idx1 as H5Oget_info_by_idx, H5Oget_info_by_name1 as H5Oget_info_by_name, + H5Ovisit1 as H5Ovisit, H5Ovisit_by_name1 as H5Ovisit_by_name, +}; use crate::internal_prelude::*; @@ -202,18 +207,22 @@ pub type H5O_mcdt_search_cb_t = #[cfg(not(hdf5_1_10_3))] extern "C" { pub fn H5Oget_info(loc_id: hid_t, oinfo: *mut H5O_info1_t) -> herr_t; - pub fn H5Oget_info_by_name( + #[link_name = "H5Oget_info_by_name"] + pub fn H5Oget_info_by_name1( loc_id: hid_t, name: *const c_char, oinfo: *mut H5O_info1_t, lapl_id: hid_t, ) -> herr_t; - pub fn H5Oget_info_by_idx( + #[link_name = "H5Oget_info_by_idx"] + pub fn H5Oget_info_by_idx1( loc_id: hid_t, group_name: *const c_char, idx_type: H5_index_t, order: H5_iter_order_t, n: hsize_t, oinfo: *mut H5O_info1_t, lapl_id: hid_t, ) -> herr_t; - pub fn H5Ovisit( + #[link_name = "H5Ovisit"] + pub fn H5Ovisit1( obj_id: hid_t, idx_type: H5_index_t, order: H5_iter_order_t, op: H5O_iterate1_t, op_data: *mut c_void, ) -> herr_t; - pub fn H5Ovisit_by_name( + #[link_name = "H5Ovisit_by_name"] + pub fn H5Ovisit_by_name1( loc_id: hid_t, obj_name: *const c_char, idx_type: H5_index_t, order: H5_iter_order_t, op: H5O_iterate1_t, op_data: *mut c_void, lapl_id: hid_t, ) -> herr_t; diff --git a/src/hl/group.rs b/src/hl/group.rs index 31abf8966..34042dd00 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -307,7 +307,7 @@ impl Group { fn get_all_of_type(&self, typ: H5O_type_t) -> Result> { #[cfg(not(hdf5_1_10_3))] - use hdf5_sys::h5o::{H5Oget_info_by_name as H5Oget_info_by_name1, H5Oopen_by_addr}; + use hdf5_sys::h5o::{H5Oget_info_by_name1, H5Oopen_by_addr}; #[cfg(all(hdf5_1_10_3, not(hdf5_1_12_0)))] use hdf5_sys::h5o::{H5Oget_info_by_name2, H5Oopen_by_addr, H5O_INFO_BASIC}; #[cfg(hdf5_1_12_0)] From edb8ff19191deefc59c3201fc7541d82d8d185b4 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Thu, 7 Oct 2021 11:20:20 +0100 Subject: [PATCH 03/23] Add common traits to {Traversal,Iteration}Order --- src/hl/group.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hl/group.rs b/src/hl/group.rs index 34042dd00..dc66c7ca2 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -215,6 +215,7 @@ impl Group { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum TraversalOrder { Lexicographic, Creation, @@ -230,6 +231,7 @@ impl From for H5_index_t { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum IterationOrder { Increasing, Decreasing, From 573a4172dcdfdddcc52ac1a10774aa460c795019 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Thu, 7 Oct 2021 11:47:37 +0100 Subject: [PATCH 04/23] Add LinkType/LinkInfo, update iter_visit signature --- src/hl/group.rs | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/src/hl/group.rs b/src/hl/group.rs index dc66c7ca2..284fb8677 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -7,11 +7,12 @@ use hdf5_sys::{ h5d::H5Dopen2, h5g::{H5G_info_t, H5Gcreate2, H5Gget_info, H5Gopen2}, h5l::{ - H5L_info_t, H5L_iterate_t, H5Lcreate_external, H5Lcreate_hard, H5Lcreate_soft, H5Ldelete, - H5Lexists, H5Literate, H5Lmove, H5L_SAME_LOC, + H5L_info_t, H5L_iterate_t, H5L_type_t, H5Lcreate_external, H5Lcreate_hard, H5Lcreate_soft, + H5Ldelete, H5Lexists, H5Literate, H5Lmove, H5L_SAME_LOC, }, h5o::H5O_type_t::{self, H5O_TYPE_DATASET, H5O_TYPE_GROUP, H5O_TYPE_NAMED_DATATYPE}, h5p::{H5Pcreate, H5Pset_create_intermediate_group}, + h5t::H5T_cset_t, }; use crate::globals::H5P_LINK_CREATE; @@ -249,6 +250,39 @@ impl From for H5_iter_order_t { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum LinkType { + Hard, + Soft, + External, +} + +impl From for LinkType { + fn from(link_type: H5L_type_t) -> Self { + match link_type { + H5L_type_t::H5L_TYPE_HARD => Self::Hard, + H5L_type_t::H5L_TYPE_SOFT => Self::Soft, + _ => Self::External, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct LinkInfo { + link_type: LinkType, + creation_order: Option, + is_utf8: bool, +} + +impl From<&H5L_info_t> for LinkInfo { + fn from(link: &H5L_info_t) -> Self { + let link_type = link.type_.into(); + let creation_order = if link.corder_valid == 1 { Some(link.corder) } else { None }; + let is_utf8 = link.cset == H5T_cset_t::H5T_CSET_UTF8; + Self { link_type, creation_order, is_utf8 } + } +} + /// Iteration methods impl Group { /// Visits all objects in the group @@ -256,7 +290,7 @@ impl Group { &self, mut op: F, mut val: G, order: (IterationOrder, TraversalOrder), ) -> Result where - F: Fn(&Self, &std::ffi::CStr, &H5L_info_t, &mut G) -> bool, + F: Fn(&Self, &std::ffi::CStr, LinkInfo, &mut G) -> bool, { /// Struct used to pass a tuple struct Vtable<'a, F, D> { @@ -270,7 +304,7 @@ impl Group { id: hid_t, name: *const c_char, info: *const H5L_info_t, op_data: *mut c_void, ) -> herr_t where - F: FnMut(&Group, &std::ffi::CStr, &H5L_info_t, &mut G) -> bool, + F: FnMut(&Group, &std::ffi::CStr, LinkInfo, &mut G) -> bool, { panic::catch_unwind(|| { let vtable = op_data.cast::>(); @@ -280,7 +314,7 @@ impl Group { let handle = Handle::try_new(id).unwrap(); handle.incref(); let group = Group::from_handle(handle); - if (vtable.f)(&group, name, info, vtable.d) { + if (vtable.f)(&group, name, info.into(), vtable.d) { 0 } else { 1 From 075efb33a75632de3de17665a9e0c1fdbd821e60 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Thu, 7 Oct 2021 11:58:41 +0100 Subject: [PATCH 05/23] Clean up iter_visit function signature --- src/hl/group.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/hl/group.rs b/src/hl/group.rs index 284fb8677..91d113eb7 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -287,7 +287,8 @@ impl From<&H5L_info_t> for LinkInfo { impl Group { /// Visits all objects in the group pub fn iter_visit( - &self, mut op: F, mut val: G, order: (IterationOrder, TraversalOrder), + &self, iteration_order: IterationOrder, traversal_order: TraversalOrder, mut val: G, + mut op: F, ) -> Result where F: Fn(&Self, &std::ffi::CStr, LinkInfo, &mut G) -> bool, @@ -332,8 +333,8 @@ impl Group { h5call!(H5Literate( self.id(), - order.1.into(), - order.0.into(), + traversal_order.into(), + iteration_order.into(), iter_pos, callback_fn, other_data @@ -349,9 +350,10 @@ impl Group { #[cfg(hdf5_1_12_0)] use hdf5_sys::h5o::{H5Oget_info_by_name3, H5Oopen_by_token, H5O_INFO_BASIC}; - let objects = vec![]; - self.iter_visit( + IterationOrder::Native, + TraversalOrder::Lexicographic, + vec![], |group, name, _info, objects| { let mut infobuf = std::mem::MaybeUninit::uninit(); #[cfg(hdf5_1_12_0)] @@ -406,8 +408,6 @@ impl Group { } true }, - objects, - (IterationOrder::Native, TraversalOrder::Lexicographic), ) } @@ -432,12 +432,13 @@ impl Group { /// Returns the names of all objects in the group, non-recursively. pub fn member_names(&self) -> Result> { self.iter_visit( + IterationOrder::Native, + TraversalOrder::Lexicographic, + vec![], |_, name, _, names| { names.push(name.to_str().unwrap().to_owned()); true }, - vec![], - (IterationOrder::Native, TraversalOrder::Lexicographic), ) } } From 6bbea30cec1bf821f978630c0ccbf7f1ac8accb2 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Mon, 11 Oct 2021 12:10:19 +0100 Subject: [PATCH 06/23] hdf5_sys: add PartialEq/Eq to H5O_token_t --- hdf5-sys/src/h5o.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hdf5-sys/src/h5o.rs b/hdf5-sys/src/h5o.rs index 4d3b46d62..aa459e9db 100644 --- a/hdf5-sys/src/h5o.rs +++ b/hdf5-sys/src/h5o.rs @@ -362,7 +362,7 @@ extern "C" { pub const H5O_MAX_TOKEN_SIZE: usize = 16; #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg(hdf5_1_12_0)] pub struct H5O_token_t { __data: [u8; H5O_MAX_TOKEN_SIZE], From cfa77881a0280a03eba4888c4bd37b7222501090 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Mon, 11 Oct 2021 12:16:16 +0100 Subject: [PATCH 07/23] Add Location{Type,Info,Token} + conversion traits --- src/hl/location.rs | 85 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/src/hl/location.rs b/src/hl/location.rs index 14e93289a..a49f909d8 100644 --- a/src/hl/location.rs +++ b/src/hl/location.rs @@ -4,11 +4,15 @@ use std::ptr; #[allow(deprecated)] use hdf5_sys::h5o::H5Oset_comment; +#[cfg(hdf5_1_12_0)] +use hdf5_sys::h5o::{H5O_info2_t, H5O_token_t}; +#[cfg(not(hdf5_1_12_0))] +use hdf5_sys::{h5::haddr_t, h5o::H5O_info1_t}; use hdf5_sys::{ h5a::H5Aopen, h5f::H5Fget_name, h5i::{H5Iget_file_id, H5Iget_name}, - h5o::H5Oget_comment, + h5o::{H5O_type_t, H5Oget_comment}, }; use crate::internal_prelude::*; @@ -113,6 +117,85 @@ impl Location { } } +#[cfg(hdf5_1_12_0)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct LocationToken(H5O_token_t); + +#[cfg(not(hdf5_1_12_0))] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct LocationToken(haddr_t); + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum LocationType { + Group, + Dataset, + NamedDatatype, + #[cfg(hdf5_1_12_0)] + TypeMap, +} + +impl From for LocationType { + fn from(loc_type: H5O_type_t) -> Self { + // we're assuming here that if a C API call returns H5O_TYPE_UNKNOWN (-1), then + // an error has occured anyway and has been pushed on the error stack so we'll + // catch it, and the value of -1 will never reach this conversion function + match loc_type { + H5O_type_t::H5O_TYPE_DATASET => Self::Dataset, + H5O_type_t::H5O_TYPE_NAMED_DATATYPE => Self::NamedDatatype, + #[cfg(hdf5_1_12_0)] + H5O_type_t::H5O_TYPE_MAP => Self::TypeMap, + _ => Self::Group, // see the comment above + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct LocationInfo { + pub fileno: u64, + pub token: LocationToken, + pub loc_type: LocationType, + pub refcount: usize, + pub atime: i64, + pub mtime: i64, + pub ctime: i64, + pub btime: i64, + pub num_attrs: usize, +} + +#[cfg(not(hdf5_1_12_0))] +impl From for LocationInfo { + fn from(info: H5O_info1_t) -> Self { + Self { + fileno: info.fileno as _, + token: LocationToken(info.addr), + loc_type: info.type_.into(), + refcount: info.rc as _, + atime: info.atime as _, + mtime: info.mtime as _, + ctime: info.ctime as _, + btime: info.btime as _, + num_attrs: info.num_attrs as _, + } + } +} + +#[cfg(hdf5_1_12_0)] +impl From for LocationInfo { + fn from(info: H5O_info2_t) -> Self { + Self { + fileno: info.fileno as _, + token: LocationToken(info.token), + loc_type: info.type_.into(), + refcount: info.rc as _, + atime: info.atime as _, + mtime: info.mtime as _, + ctime: info.ctime as _, + btime: info.btime as _, + num_attrs: info.num_attrs as _, + } + } +} + #[cfg(test)] pub mod tests { use crate::internal_prelude::*; From 99926001adaed7d2729983afe322f6742ed152b3 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Mon, 11 Oct 2021 12:17:12 +0100 Subject: [PATCH 08/23] Re-export new location types in the crate --- src/hl.rs | 2 +- src/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hl.rs b/src/hl.rs index 4f0201611..3748fcead 100644 --- a/src/hl.rs +++ b/src/hl.rs @@ -25,7 +25,7 @@ pub use self::{ datatype::{Conversion, Datatype}, file::{File, FileBuilder, OpenMode}, group::Group, - location::Location, + location::{Location, LocationInfo, LocationToken, LocationType}, object::Object, plist::PropertyList, }; diff --git a/src/lib.rs b/src/lib.rs index f7d8eb832..6bd4b1e03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,7 +38,8 @@ mod export { Attribute, AttributeBuilder, AttributeBuilderData, AttributeBuilderEmpty, AttributeBuilderEmptyShape, Container, Conversion, Dataset, DatasetBuilder, DatasetBuilderData, DatasetBuilderEmpty, DatasetBuilderEmptyShape, Dataspace, Datatype, - File, FileBuilder, Group, Location, Object, PropertyList, Reader, Writer, + File, FileBuilder, Group, Location, LocationInfo, LocationToken, LocationType, Object, + PropertyList, Reader, Writer, }, }; From d5082bdb90ad3bd63af36becc6aa68944a8e9f41 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Mon, 11 Oct 2021 12:18:48 +0100 Subject: [PATCH 09/23] Add Location:{get_info_by_name,open_by_token} etc --- src/hl/location.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/src/hl/location.rs b/src/hl/location.rs index a49f909d8..2ca4851fb 100644 --- a/src/hl/location.rs +++ b/src/hl/location.rs @@ -1,13 +1,22 @@ use std::fmt::{self, Debug}; +use std::mem::MaybeUninit; use std::ops::Deref; use std::ptr; #[allow(deprecated)] use hdf5_sys::h5o::H5Oset_comment; +#[cfg(hdf5_1_10_3)] +use hdf5_sys::h5o::H5O_INFO_BASIC; #[cfg(hdf5_1_12_0)] -use hdf5_sys::h5o::{H5O_info2_t, H5O_token_t}; +use hdf5_sys::h5o::{ + H5O_info2_t, H5O_token_t, H5Oget_info3, H5Oget_info_by_name3, H5Oopen_by_token, +}; +#[cfg(not(hdf5_1_10_3))] +use hdf5_sys::h5o::{H5Oget_info1, H5Oget_info_by_name1}; +#[cfg(all(hdf5_1_10_3, not(hdf5_1_12_0)))] +use hdf5_sys::h5o::{H5Oget_info2, H5Oget_info_by_name2}; #[cfg(not(hdf5_1_12_0))] -use hdf5_sys::{h5::haddr_t, h5o::H5O_info1_t}; +use hdf5_sys::{h5::haddr_t, h5o::H5O_info1_t, h5o::H5Oopen_by_addr}; use hdf5_sys::{ h5a::H5Aopen, h5f::H5Fget_name, @@ -115,6 +124,23 @@ impl Location { pub fn attr_names(&self) -> Result> { Attribute::attr_names(self) } + + pub fn get_info(&self) -> Result { + H5O_get_info(self.id()) + } + + pub fn loc_type(&self) -> Result { + Ok(self.get_info()?.loc_type) + } + + pub fn get_info_by_name(&self, name: &str) -> Result { + let name = to_cstring(name)?; + H5O_get_info_by_name(self.id(), name.as_ptr()) + } + + pub fn open_by_token(&self, token: LocationToken) -> Result { + H5O_open_by_token(self.id(), token) + } } #[cfg(hdf5_1_12_0)] @@ -196,6 +222,46 @@ impl From for LocationInfo { } } +#[allow(non_snake_case)] +fn H5O_get_info(loc_id: hid_t) -> Result { + let mut info_buf = MaybeUninit::uninit(); + let info_ptr = info_buf.as_mut_ptr(); + #[cfg(hdf5_1_12_0)] + h5call!(H5Oget_info3(loc_id, info_ptr, H5O_INFO_BASIC))?; + #[cfg(all(hdf5_1_10_3, not(hdf5_1_12_0)))] + h5call!(H5Oget_info2(loc_id, info_ptr, H5O_INFO_BASIC))?; + #[cfg(not(hdf5_1_10_3))] + h5call!(H5Oget_info1(loc_id, info_ptr))?; + let info = unsafe { info_buf.assume_init() }; + Ok(info.into()) +} + +#[allow(non_snake_case)] +fn H5O_get_info_by_name(loc_id: hid_t, name: *const c_char) -> Result { + let mut info_buf = MaybeUninit::uninit(); + let info_ptr = info_buf.as_mut_ptr(); + #[cfg(hdf5_1_12_0)] + h5call!(H5Oget_info_by_name3(loc_id, name, info_ptr, H5O_INFO_BASIC, H5P_DEFAULT))?; + #[cfg(all(hdf5_1_10_3, not(hdf5_1_12_0)))] + h5call!(H5Oget_info_by_name2(loc_id, name, info_ptr, H5O_INFO_BASIC, H5P_DEFAULT))?; + #[cfg(not(hdf5_1_10_3))] + h5call!(H5Oget_info_by_name1(loc_id, name, info_ptr, H5P_DEFAULT))?; + let info = unsafe { info_buf.assume_init() }; + Ok(info.into()) +} + +#[allow(non_snake_case)] +fn H5O_open_by_token(loc_id: hid_t, token: LocationToken) -> Result { + #[cfg(not(hdf5_1_12_0))] + { + Location::from_id(h5call!(H5Oopen_by_addr(loc_id, token.0))?) + } + #[cfg(hdf5_1_12_0)] + { + Location::from_id(h5call!(H5Oopen_by_token(loc_id, token.0))) + } +} + #[cfg(test)] pub mod tests { use crate::internal_prelude::*; From afa5b9578859b4b19b56ecec5522a3ea366eca7a Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Mon, 11 Oct 2021 12:20:05 +0100 Subject: [PATCH 10/23] Group iter: use new loc methods, &str for names --- src/hl/group.rs | 91 ++++++++++++------------------------------------- 1 file changed, 22 insertions(+), 69 deletions(-) diff --git a/src/hl/group.rs b/src/hl/group.rs index 91d113eb7..11631182b 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -10,13 +10,13 @@ use hdf5_sys::{ H5L_info_t, H5L_iterate_t, H5L_type_t, H5Lcreate_external, H5Lcreate_hard, H5Lcreate_soft, H5Ldelete, H5Lexists, H5Literate, H5Lmove, H5L_SAME_LOC, }, - h5o::H5O_type_t::{self, H5O_TYPE_DATASET, H5O_TYPE_GROUP, H5O_TYPE_NAMED_DATATYPE}, h5p::{H5Pcreate, H5Pset_create_intermediate_group}, h5t::H5T_cset_t, }; use crate::globals::H5P_LINK_CREATE; use crate::internal_prelude::*; +use crate::{Location, LocationType}; /// Represents the HDF5 group object. #[repr(transparent)] @@ -291,7 +291,7 @@ impl Group { mut op: F, ) -> Result where - F: Fn(&Self, &std::ffi::CStr, LinkInfo, &mut G) -> bool, + F: Fn(&Self, &str, LinkInfo, &mut G) -> bool, { /// Struct used to pass a tuple struct Vtable<'a, F, D> { @@ -305,7 +305,7 @@ impl Group { id: hid_t, name: *const c_char, info: *const H5L_info_t, op_data: *mut c_void, ) -> herr_t where - F: FnMut(&Group, &std::ffi::CStr, LinkInfo, &mut G) -> bool, + F: FnMut(&Group, &str, LinkInfo, &mut G) -> bool, { panic::catch_unwind(|| { let vtable = op_data.cast::>(); @@ -315,7 +315,7 @@ impl Group { let handle = Handle::try_new(id).unwrap(); handle.incref(); let group = Group::from_handle(handle); - if (vtable.f)(&group, name, info.into(), vtable.d) { + if (vtable.f)(&group, name.to_string_lossy().as_ref(), info.into(), vtable.d) { 0 } else { 1 @@ -342,91 +342,44 @@ impl Group { .map(|_| val) } - fn get_all_of_type(&self, typ: H5O_type_t) -> Result> { - #[cfg(not(hdf5_1_10_3))] - use hdf5_sys::h5o::{H5Oget_info_by_name1, H5Oopen_by_addr}; - #[cfg(all(hdf5_1_10_3, not(hdf5_1_12_0)))] - use hdf5_sys::h5o::{H5Oget_info_by_name2, H5Oopen_by_addr, H5O_INFO_BASIC}; - #[cfg(hdf5_1_12_0)] - use hdf5_sys::h5o::{H5Oget_info_by_name3, H5Oopen_by_token, H5O_INFO_BASIC}; - + fn get_all_of_type(&self, loc_type: LocationType) -> Result> { self.iter_visit( IterationOrder::Native, TraversalOrder::Lexicographic, vec![], |group, name, _info, objects| { - let mut infobuf = std::mem::MaybeUninit::uninit(); - #[cfg(hdf5_1_12_0)] - if h5call!(H5Oget_info_by_name3( - group.id(), - name.as_ptr(), - infobuf.as_mut_ptr(), - H5O_INFO_BASIC, - H5P_DEFAULT - )) - .is_err() - { - return true; - }; - #[cfg(all(hdf5_1_10_3, not(hdf5_1_12_0)))] - if h5call!(H5Oget_info_by_name2( - group.id(), - name.as_ptr(), - infobuf.as_mut_ptr(), - H5O_INFO_BASIC, - H5P_DEFAULT - )) - .is_err() - { - return true; - }; - #[cfg(not(hdf5_1_10_3))] - if h5call!(H5Oget_info_by_name1( - group.id(), - name.as_ptr(), - infobuf.as_mut_ptr(), - H5P_DEFAULT - )) - .is_err() - { - return true; - }; - let infobuf = unsafe { infobuf.assume_init() }; - if infobuf.type_ == typ { - #[cfg(hdf5_1_12_0)] - if let Ok(id) = h5call!(H5Oopen_by_token(group.id(), infobuf.token)) { - if let Ok(handle) = Handle::try_new(id) { - objects.push(handle); - } - } - #[cfg(not(hdf5_1_12_0))] - if let Ok(id) = h5call!(H5Oopen_by_addr(group.id(), infobuf.addr)) { - if let Ok(handle) = Handle::try_new(id) { - objects.push(handle); + // TODO: pass &str here + if let Ok(info) = group.get_info_by_name(name) { + if info.loc_type == loc_type { + if let Ok(loc) = group.open_by_token(info.token) { + objects.push(loc); + return true; // ok, object extracted and pushed } + } else { + return true; // ok, object is of another type, skipped } } - true + false // an error occured somewhere along the way }, ) } /// Returns all groups in the group, non-recursively pub fn groups(&self) -> Result> { - self.get_all_of_type(H5O_TYPE_GROUP) - .map(|vec| vec.into_iter().map(Self::from_handle).collect()) + self.get_all_of_type(LocationType::Group) + .map(|vec| vec.into_iter().map(|obj| unsafe { obj.cast() }).collect()) } /// Returns all datasets in the group, non-recursively pub fn datasets(&self) -> Result> { - self.get_all_of_type(H5O_TYPE_DATASET) - .map(|vec| vec.into_iter().map(Dataset::from_handle).collect()) + self.get_all_of_type(LocationType::Dataset) + .map(|vec| vec.into_iter().map(|obj| unsafe { obj.cast() }).collect()) } /// Returns all named types in the group, non-recursively - pub fn datatypes(&self) -> Result> { - self.get_all_of_type(H5O_TYPE_NAMED_DATATYPE) - .map(|vec| vec.into_iter().map(Datatype::from_handle).collect()) + pub fn named_datatypes(&self) -> Result> { + self.get_all_of_type(LocationType::NamedDatatype) + .map(|vec| vec.into_iter().map(|obj| unsafe { obj.cast() }).collect()) } /// Returns the names of all objects in the group, non-recursively. @@ -436,7 +389,7 @@ impl Group { TraversalOrder::Lexicographic, vec![], |_, name, _, names| { - names.push(name.to_str().unwrap().to_owned()); + names.push(name.to_owned()); true }, ) From 514abbc1fcb5c810704b66b5daa55b75e422d2e6 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Mon, 11 Oct 2021 12:23:57 +0100 Subject: [PATCH 11/23] Impl Default for IterationOrder/TraversalOrder --- src/hl/group.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/hl/group.rs b/src/hl/group.rs index 11631182b..8a67e7da7 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -222,6 +222,12 @@ pub enum TraversalOrder { Creation, } +impl Default for TraversalOrder { + fn default() -> Self { + TraversalOrder::Lexicographic + } +} + impl From for H5_index_t { fn from(v: TraversalOrder) -> Self { use hdf5_sys::h5::{H5_INDEX_CRT_ORDER, H5_INDEX_NAME}; @@ -239,6 +245,12 @@ pub enum IterationOrder { Native, } +impl Default for IterationOrder { + fn default() -> Self { + IterationOrder::Native + } +} + impl From for H5_iter_order_t { fn from(v: IterationOrder) -> Self { use hdf5_sys::h5::{H5_ITER_DEC, H5_ITER_INC, H5_ITER_NATIVE}; From 89b3e455e9b72f9a19aa2c6313ee9f4a0e078999 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Mon, 11 Oct 2021 12:24:20 +0100 Subject: [PATCH 12/23] Add Group::iter_visit_default --- src/hl/group.rs | 50 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/hl/group.rs b/src/hl/group.rs index 8a67e7da7..50ec2190c 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -354,26 +354,29 @@ impl Group { .map(|_| val) } + /// Visits all objects in the group using default iteration/traversal order. + pub fn iter_visit_default(&self, val: G, op: F) -> Result + where + F: Fn(&Self, &str, LinkInfo, &mut G) -> bool, + { + self.iter_visit(IterationOrder::default(), TraversalOrder::default(), val, op) + } + fn get_all_of_type(&self, loc_type: LocationType) -> Result> { - self.iter_visit( - IterationOrder::Native, - TraversalOrder::Lexicographic, - vec![], - |group, name, _info, objects| { - // TODO: pass &str here - if let Ok(info) = group.get_info_by_name(name) { - if info.loc_type == loc_type { - if let Ok(loc) = group.open_by_token(info.token) { - objects.push(loc); - return true; // ok, object extracted and pushed - } - } else { - return true; // ok, object is of another type, skipped + self.iter_visit_default(vec![], |group, name, _info, objects| { + // TODO: pass &str here + if let Ok(info) = group.get_info_by_name(name) { + if info.loc_type == loc_type { + if let Ok(loc) = group.open_by_token(info.token) { + objects.push(loc); + return true; // ok, object extracted and pushed } + } else { + return true; // ok, object is of another type, skipped } - false // an error occured somewhere along the way - }, - ) + } + false // an error occured somewhere along the way + }) } /// Returns all groups in the group, non-recursively @@ -396,15 +399,10 @@ impl Group { /// Returns the names of all objects in the group, non-recursively. pub fn member_names(&self) -> Result> { - self.iter_visit( - IterationOrder::Native, - TraversalOrder::Lexicographic, - vec![], - |_, name, _, names| { - names.push(name.to_owned()); - true - }, - ) + self.iter_visit_default(vec![], |_, name, _, names| { + names.push(name.to_owned()); + true + }) } } From 9de1b20fec7c1b98e2fa79ecf8f43edcca2f5e8f Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Mon, 11 Oct 2021 12:26:21 +0100 Subject: [PATCH 13/23] Rename TraversalOrder::Lexicographic -> 'Name' --- src/hl/group.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hl/group.rs b/src/hl/group.rs index 50ec2190c..db5843ea8 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -218,13 +218,13 @@ impl Group { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum TraversalOrder { - Lexicographic, + Name, Creation, } impl Default for TraversalOrder { fn default() -> Self { - TraversalOrder::Lexicographic + TraversalOrder::Name } } @@ -232,7 +232,7 @@ impl From for H5_index_t { fn from(v: TraversalOrder) -> Self { use hdf5_sys::h5::{H5_INDEX_CRT_ORDER, H5_INDEX_NAME}; match v { - TraversalOrder::Lexicographic => H5_INDEX_NAME, + TraversalOrder::Name => H5_INDEX_NAME, TraversalOrder::Creation => H5_INDEX_CRT_ORDER, } } From 537077d20bd1d9eb14cba040cd5c6537c71d3ca5 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Mon, 11 Oct 2021 12:27:33 +0100 Subject: [PATCH 14/23] (Remove a few unneeded imports) --- src/hl/group.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/hl/group.rs b/src/hl/group.rs index db5843ea8..4b48be0b5 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -230,10 +230,9 @@ impl Default for TraversalOrder { impl From for H5_index_t { fn from(v: TraversalOrder) -> Self { - use hdf5_sys::h5::{H5_INDEX_CRT_ORDER, H5_INDEX_NAME}; match v { - TraversalOrder::Name => H5_INDEX_NAME, - TraversalOrder::Creation => H5_INDEX_CRT_ORDER, + TraversalOrder::Name => H5_index_t::H5_INDEX_NAME, + TraversalOrder::Creation => H5_index_t::H5_INDEX_CRT_ORDER, } } } @@ -253,11 +252,10 @@ impl Default for IterationOrder { impl From for H5_iter_order_t { fn from(v: IterationOrder) -> Self { - use hdf5_sys::h5::{H5_ITER_DEC, H5_ITER_INC, H5_ITER_NATIVE}; match v { - IterationOrder::Increasing => H5_ITER_INC, - IterationOrder::Decreasing => H5_ITER_DEC, - IterationOrder::Native => H5_ITER_NATIVE, + IterationOrder::Increasing => H5_iter_order_t::H5_ITER_INC, + IterationOrder::Decreasing => H5_iter_order_t::H5_ITER_DEC, + IterationOrder::Native => H5_iter_order_t::H5_ITER_NATIVE, } } } From 2115383696c2a2cb5b8eca22f3eab1f3bca9c8d1 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Mon, 11 Oct 2021 12:29:21 +0100 Subject: [PATCH 15/23] Re-export Link{Info,Type}, make fields pub --- src/hl.rs | 2 +- src/hl/group.rs | 6 +++--- src/lib.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hl.rs b/src/hl.rs index 3748fcead..3c5268b48 100644 --- a/src/hl.rs +++ b/src/hl.rs @@ -24,7 +24,7 @@ pub use self::{ dataspace::Dataspace, datatype::{Conversion, Datatype}, file::{File, FileBuilder, OpenMode}, - group::Group, + group::{Group, LinkInfo, LinkType}, location::{Location, LocationInfo, LocationToken, LocationType}, object::Object, plist::PropertyList, diff --git a/src/hl/group.rs b/src/hl/group.rs index 4b48be0b5..39362d800 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -279,9 +279,9 @@ impl From for LinkType { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct LinkInfo { - link_type: LinkType, - creation_order: Option, - is_utf8: bool, + pub link_type: LinkType, + pub creation_order: Option, + pub is_utf8: bool, } impl From<&H5L_info_t> for LinkInfo { diff --git a/src/lib.rs b/src/lib.rs index 6bd4b1e03..41616e69f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,8 +38,8 @@ mod export { Attribute, AttributeBuilder, AttributeBuilderData, AttributeBuilderEmpty, AttributeBuilderEmptyShape, Container, Conversion, Dataset, DatasetBuilder, DatasetBuilderData, DatasetBuilderEmpty, DatasetBuilderEmptyShape, Dataspace, Datatype, - File, FileBuilder, Group, Location, LocationInfo, LocationToken, LocationType, Object, - PropertyList, Reader, Writer, + File, FileBuilder, Group, LinkInfo, LinkType, Location, LocationInfo, LocationToken, + LocationType, Object, PropertyList, Reader, Writer, }, }; From ce48e1d70d536cc49ff899d0f9bca3a3cb86fd15 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Mon, 11 Oct 2021 12:32:00 +0100 Subject: [PATCH 16/23] Group::Iter_visit: replace unwraps with expects --- src/hl/group.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hl/group.rs b/src/hl/group.rs index 39362d800..041a80888 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -319,10 +319,10 @@ impl Group { { panic::catch_unwind(|| { let vtable = op_data.cast::>(); - let vtable = unsafe { vtable.as_mut().expect("op_data is always non-null") }; + let vtable = unsafe { vtable.as_mut().expect("iter_visit: null op_data ptr") }; let name = unsafe { std::ffi::CStr::from_ptr(name) }; - let info = unsafe { info.as_ref().unwrap() }; - let handle = Handle::try_new(id).unwrap(); + let info = unsafe { info.as_ref().expect("iter_vist: null info ptr") }; + let handle = Handle::try_new(id).expect("iter_visit: unable to create a handle"); handle.incref(); let group = Group::from_handle(handle); if (vtable.f)(&group, name.to_string_lossy().as_ref(), info.into(), vtable.d) { From 4ba1386818e83c6eb8ea8f91dc8f6e7e9fe800cd Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Mon, 11 Oct 2021 12:36:18 +0100 Subject: [PATCH 17/23] Group::Iter_visit: also check for null name ptr --- src/hl/group.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hl/group.rs b/src/hl/group.rs index 041a80888..cb764fa3f 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -320,6 +320,7 @@ impl Group { panic::catch_unwind(|| { let vtable = op_data.cast::>(); let vtable = unsafe { vtable.as_mut().expect("iter_visit: null op_data ptr") }; + unsafe { name.as_ref().expect("iter_visit: null name ptr") }; let name = unsafe { std::ffi::CStr::from_ptr(name) }; let info = unsafe { info.as_ref().expect("iter_vist: null info ptr") }; let handle = Handle::try_new(id).expect("iter_visit: unable to create a handle"); From b5a760eeff508adf0ba4a07ef406e020c9c78031 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Mon, 11 Oct 2021 12:41:44 +0100 Subject: [PATCH 18/23] (Remove now-redundant todo comment) --- src/hl/group.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hl/group.rs b/src/hl/group.rs index cb764fa3f..f60e5d64d 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -363,7 +363,6 @@ impl Group { fn get_all_of_type(&self, loc_type: LocationType) -> Result> { self.iter_visit_default(vec![], |group, name, _info, objects| { - // TODO: pass &str here if let Ok(info) = group.get_info_by_name(name) { if info.loc_type == loc_type { if let Ok(loc) = group.open_by_token(info.token) { From e5e56a7fdccfa1fd54030a158de080ffa84e8844 Mon Sep 17 00:00:00 2001 From: Magnus Ulimoen Date: Mon, 11 Oct 2021 16:42:55 +0000 Subject: [PATCH 19/23] Clippy lint --- src/hl/group.rs | 14 +++++++------- src/hl/location.rs | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/hl/group.rs b/src/hl/group.rs index f60e5d64d..7bb759690 100644 --- a/src/hl/group.rs +++ b/src/hl/group.rs @@ -224,15 +224,15 @@ pub enum TraversalOrder { impl Default for TraversalOrder { fn default() -> Self { - TraversalOrder::Name + Self::Name } } impl From for H5_index_t { fn from(v: TraversalOrder) -> Self { match v { - TraversalOrder::Name => H5_index_t::H5_INDEX_NAME, - TraversalOrder::Creation => H5_index_t::H5_INDEX_CRT_ORDER, + TraversalOrder::Name => Self::H5_INDEX_NAME, + TraversalOrder::Creation => Self::H5_INDEX_CRT_ORDER, } } } @@ -246,16 +246,16 @@ pub enum IterationOrder { impl Default for IterationOrder { fn default() -> Self { - IterationOrder::Native + Self::Native } } impl From for H5_iter_order_t { fn from(v: IterationOrder) -> Self { match v { - IterationOrder::Increasing => H5_iter_order_t::H5_ITER_INC, - IterationOrder::Decreasing => H5_iter_order_t::H5_ITER_DEC, - IterationOrder::Native => H5_iter_order_t::H5_ITER_NATIVE, + IterationOrder::Increasing => Self::H5_ITER_INC, + IterationOrder::Decreasing => Self::H5_ITER_DEC, + IterationOrder::Native => Self::H5_ITER_NATIVE, } } } diff --git a/src/hl/location.rs b/src/hl/location.rs index 2ca4851fb..52800c3d2 100644 --- a/src/hl/location.rs +++ b/src/hl/location.rs @@ -138,7 +138,7 @@ impl Location { H5O_get_info_by_name(self.id(), name.as_ptr()) } - pub fn open_by_token(&self, token: LocationToken) -> Result { + pub fn open_by_token(&self, token: LocationToken) -> Result { H5O_open_by_token(self.id(), token) } } From 7103de9bd986406fe5274eed1b2b830ce5ae82fa Mon Sep 17 00:00:00 2001 From: Magnus Ulimoen Date: Mon, 11 Oct 2021 16:45:00 +0000 Subject: [PATCH 20/23] Fix early return --- src/hl/location.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hl/location.rs b/src/hl/location.rs index 52800c3d2..08ba0cf81 100644 --- a/src/hl/location.rs +++ b/src/hl/location.rs @@ -258,7 +258,7 @@ fn H5O_open_by_token(loc_id: hid_t, token: LocationToken) -> Result { } #[cfg(hdf5_1_12_0)] { - Location::from_id(h5call!(H5Oopen_by_token(loc_id, token.0))) + Location::from_id(h5call!(H5Oopen_by_token(loc_id, token.0))?) } } From 312fac40bca8fef5551383c4fe1bb4c491fedb90 Mon Sep 17 00:00:00 2001 From: Magnus Ulimoen Date: Mon, 11 Oct 2021 16:50:57 +0000 Subject: [PATCH 21/23] Adjust import of H5Oget_info --- hdf5-sys/src/h5o.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hdf5-sys/src/h5o.rs b/hdf5-sys/src/h5o.rs index aa459e9db..0a54cc1b7 100644 --- a/hdf5-sys/src/h5o.rs +++ b/hdf5-sys/src/h5o.rs @@ -11,8 +11,9 @@ pub use { pub use {H5O_info2_t as H5O_info_t, H5O_iterate2_t as H5O_iterate_t}; #[cfg(not(hdf5_1_10_3))] pub use { - H5Oget_info_by_idx1 as H5Oget_info_by_idx, H5Oget_info_by_name1 as H5Oget_info_by_name, - H5Ovisit1 as H5Ovisit, H5Ovisit_by_name1 as H5Ovisit_by_name, + H5Oget_info1 as H5Oget_info, H5Oget_info_by_idx1 as H5Oget_info_by_idx, + H5Oget_info_by_name1 as H5Oget_info_by_name, H5Ovisit1 as H5Ovisit, + H5Ovisit_by_name1 as H5Ovisit_by_name, }; use crate::internal_prelude::*; @@ -206,7 +207,8 @@ pub type H5O_mcdt_search_cb_t = #[cfg(not(hdf5_1_10_3))] extern "C" { - pub fn H5Oget_info(loc_id: hid_t, oinfo: *mut H5O_info1_t) -> herr_t; + #[link_name = "H5Oget_info"] + pub fn H5Oget_info1(loc_id: hid_t, oinfo: *mut H5O_info1_t) -> herr_t; #[link_name = "H5Oget_info_by_name"] pub fn H5Oget_info_by_name1( loc_id: hid_t, name: *const c_char, oinfo: *mut H5O_info1_t, lapl_id: hid_t, From 2f7cc24e2bcaf6fab19be46c165bfd6299488356 Mon Sep 17 00:00:00 2001 From: Magnus Ulimoen Date: Mon, 11 Oct 2021 17:02:21 +0000 Subject: [PATCH 22/23] Document additions in CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8cbbcc06..14c046cc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,8 @@ but must read the entire attribute at once). - Added support in `hdf5-sys` for the new functions in `hdf5` `1.10.6` and `1.10.7`. - Added support for creating external links on a `Group` with `link_external`. +- Added `Location` methods: `get_info`, `get_info_by_name`, `loc_type`, and `open_by_token`. +- Added `Group` methods: `iter_visit`, `iter_visit_default`, `get_all_of_type`, `datasets`, `groups`, and `named_datatypes`. ### Changed From 05477f0bcddf4e0e0da8e4527aaf6151f33bd46a Mon Sep 17 00:00:00 2001 From: Magnus Ulimoen Date: Mon, 11 Oct 2021 17:44:15 +0000 Subject: [PATCH 23/23] Add tests for Location Info --- src/hl/location.rs | 52 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/hl/location.rs b/src/hl/location.rs index 08ba0cf81..4e25bae54 100644 --- a/src/hl/location.rs +++ b/src/hl/location.rs @@ -176,16 +176,22 @@ impl From for LocationType { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] +/// Information about a [`Location`] pub struct LocationInfo { pub fileno: u64, pub token: LocationToken, pub loc_type: LocationType, pub refcount: usize, - pub atime: i64, - pub mtime: i64, - pub ctime: i64, - pub btime: i64, - pub num_attrs: usize, + /// Not available when requesting only basic info + atime: i64, + /// Not available when requesting only basic info + mtime: i64, + /// Not available when requesting only basic info + ctime: i64, + /// Not available when requesting only basic info + btime: i64, + /// Not available when requesting only basic info + num_attrs: usize, } #[cfg(not(hdf5_1_12_0))] @@ -298,4 +304,40 @@ pub mod tests { assert!(file.comment().is_none()); }) } + + #[test] + pub fn test_location_info() { + with_tmp_file(|file| { + let token; + { + let group = file.create_group("group").unwrap(); + let info = group.get_info().unwrap(); + assert_eq!(info.refcount, 1); + assert_eq!(info.loc_type, LocationType::Group); + token = info.token; + } + let group = file.open_by_token(token).unwrap(); + assert_eq!(group.name(), "/group"); + let token; + { + let var = file.new_dataset::().create("var").unwrap(); + var.new_attr::().create("attr").unwrap(); + let info = var.get_info().unwrap(); + assert_eq!(info.refcount, 1); + assert_eq!(info.loc_type, LocationType::Dataset); + token = info.token; + } + let var = file.open_by_token(token).unwrap(); + assert_eq!(var.name(), "/var"); + + let info = file.get_info_by_name("group").unwrap(); + let group = file.open_by_token(info.token).unwrap(); + assert_eq!(group.name(), "/group"); + let info = file.get_info_by_name("var").unwrap(); + let var = file.open_by_token(info.token).unwrap(); + assert_eq!(var.name(), "/var"); + + assert!(file.get_info_by_name("gibberish").is_err()); + }) + } }