Skip to content

Commit

Permalink
Goodbye trait-based inheritance, hello Deref
Browse files Browse the repository at this point in the history
  • Loading branch information
aldanor committed Nov 18, 2018
1 parent 02237ea commit 53eff4f
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 227 deletions.
33 changes: 21 additions & 12 deletions hdf5-rs/src/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::default::Default;
use libhdf5_sys::{
h5d::H5Dopen2,
h5g::{H5G_info_t, H5Gcreate2, H5Gget_info, H5Gopen2},
h5i::{H5I_FILE, H5I_GROUP},
h5l::{H5Lcreate_hard, H5Lcreate_soft, H5Ldelete, H5Lmove, H5L_SAME_LOC},
h5p::{H5Pcreate, H5Pset_create_intermediate_group},
};
Expand All @@ -22,20 +23,24 @@ fn make_lcpl() -> Result<PropertyList> {
})
}

define_object_type!(Container: Location, "container", |id_type| id_type == H5I_FILE
|| id_type == H5I_GROUP);

/// A trait for HDF5 objects that can contain other objects (file, group).
pub trait Container: Location {
impl Container {
/// Returns the number of objects in the container (or 0 if the container is invalid).
fn len(&self) -> u64 {
pub fn len(&self) -> u64 {
group_info(self.id()).map(|info| info.nlinks).unwrap_or(0)
}

/// Returns true if the container has no linked objects (or if the container is invalid).
fn is_empty(&self) -> bool {
pub fn is_empty(&self) -> bool {
self.len() == 0
}

/// Create a new group in a file or group.
fn create_group(&self, name: &str) -> Result<Group> {
pub fn create_group(&self, name: &str) -> Result<Group> {
// TODO: &mut self?
h5lock!({
let lcpl = make_lcpl()?;
let name = to_cstring(name)?;
Expand All @@ -50,13 +55,14 @@ pub trait Container: Location {
}

/// Opens an existing group in a file or group.
fn group(&self, name: &str) -> Result<Group> {
pub fn group(&self, name: &str) -> Result<Group> {
let name = to_cstring(name)?;
Group::from_id(h5try!(H5Gopen2(self.id(), name.as_ptr(), H5P_DEFAULT)))
}

/// Creates a soft link. Note: `src` and `dst` are relative to the current object.
fn link_soft(&self, src: &str, dst: &str) -> Result<()> {
pub fn link_soft(&self, src: &str, dst: &str) -> Result<()> {
// TODO: &mut self?
h5lock!({
let lcpl = make_lcpl()?;
let src = to_cstring(src)?;
Expand All @@ -67,7 +73,8 @@ pub trait Container: Location {
}

/// Creates a hard link. Note: `src` and `dst` are relative to the current object.
fn link_hard(&self, src: &str, dst: &str) -> Result<()> {
pub fn link_hard(&self, src: &str, dst: &str) -> Result<()> {
// TODO: &mut self?
let src = to_cstring(src)?;
let dst = to_cstring(dst)?;
h5call!(H5Lcreate_hard(
Expand All @@ -82,7 +89,8 @@ pub trait Container: Location {
}

/// Relinks an object. Note: `name` and `path` are relative to the current object.
fn relink(&self, name: &str, path: &str) -> Result<()> {
pub fn relink(&self, name: &str, path: &str) -> Result<()> {
// TODO: &mut self?
let name = to_cstring(name)?;
let path = to_cstring(path)?;
h5call!(H5Lmove(
Expand All @@ -97,18 +105,19 @@ pub trait Container: Location {
}

/// Removes a link to an object from this file or group.
fn unlink(&self, name: &str) -> Result<()> {
pub fn unlink(&self, name: &str) -> Result<()> {
// TODO: &mut self?
let name = to_cstring(name)?;
h5call!(H5Ldelete(self.id(), name.as_ptr(), H5P_DEFAULT)).and(Ok(()))
}

/// Instantiates a new dataset builder.
fn new_dataset<T: H5Type>(&self) -> DatasetBuilder<T> {
DatasetBuilder::<T>::new::<Self>(self)
pub fn new_dataset<T: H5Type>(&self) -> DatasetBuilder<T> {
DatasetBuilder::<T>::new(self)
}

/// Opens an existing dataset in the file or group.
fn dataset(&self, name: &str) -> Result<Dataset> {
pub fn dataset(&self, name: &str) -> Result<Dataset> {
let name = to_cstring(name)?;
Dataset::from_id(h5try!(H5Dopen2(self.id(), name.as_ptr(), H5P_DEFAULT)))
}
Expand Down
30 changes: 3 additions & 27 deletions hdf5-rs/src/dataset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use libhdf5_sys::{
H5D_fill_value_t, H5D_layout_t, H5Dcreate2, H5Dcreate_anon, H5Dget_create_plist,
H5Dget_offset, H5Dget_space, H5Dget_storage_size, H5Dget_type, H5D_FILL_TIME_ALLOC,
},
h5i::H5I_DATASET,
h5p::{
H5Pcreate, H5Pfill_value_defined, H5Pget_chunk, H5Pget_fill_value, H5Pget_layout,
H5Pget_obj_track_times, H5Pset_chunk, H5Pset_create_intermediate_group, H5Pset_fill_time,
Expand All @@ -27,32 +28,7 @@ pub enum Chunk {
}

/// Represents the HDF5 dataset object.
pub struct Dataset {
handle: Handle,
}

#[doc(hidden)]
impl ID for Dataset {
fn id(&self) -> hid_t {
self.handle.id()
}
}

#[doc(hidden)]
impl FromID for Dataset {
fn from_id(id: hid_t) -> Result<Dataset> {
h5lock!({
match get_id_type(id) {
H5I_DATASET => Ok(Dataset { handle: Handle::new(id)? }),
_ => Err(From::from(format!("Invalid dataset id: {}", id))),
}
})
}
}

impl Object for Dataset {}

impl Location for Dataset {}
define_object_type!(Dataset: Location, "dataset", |id_type| id_type == H5I_DATASET);

impl Dataset {
/// Returns the shape of the dataset.
Expand Down Expand Up @@ -201,7 +177,7 @@ pub struct DatasetBuilder<T> {

impl<T: H5Type> DatasetBuilder<T> {
/// Create a new dataset builder and bind it to the parent container.
pub fn new<C: Container>(parent: &C) -> DatasetBuilder<T> {
pub fn new(parent: &Container) -> DatasetBuilder<T> {
h5lock!({
// Store the reference to the parent handle and try to increase its reference count.
let handle = Handle::new(parent.id());
Expand Down
39 changes: 11 additions & 28 deletions hdf5-rs/src/datatype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ use std::fmt;
use hdf5_types::{
CompoundField, CompoundType, EnumMember, EnumType, FloatSize, H5Type, IntSize, TypeDescriptor,
};
use libhdf5_sys::h5t::{
H5T_class_t, H5T_cset_t, H5T_str_t, H5Tarray_create2, H5Tcopy, H5Tcreate, H5Tenum_create,
H5Tenum_insert, H5Tequal, H5Tget_array_dims2, H5Tget_array_ndims, H5Tget_class, H5Tget_cset,
H5Tget_member_name, H5Tget_member_offset, H5Tget_member_type, H5Tget_member_value,
H5Tget_nmembers, H5Tget_sign, H5Tget_size, H5Tget_super, H5Tinsert, H5Tis_variable_str,
H5Tset_cset, H5Tset_size, H5Tset_strpad, H5Tvlen_create, H5T_VARIABLE,
use libhdf5_sys::{
h5i::H5I_DATATYPE,
h5t::{
H5T_class_t, H5T_cset_t, H5T_str_t, H5Tarray_create2, H5Tcopy, H5Tcreate, H5Tenum_create,
H5Tenum_insert, H5Tequal, H5Tget_array_dims2, H5Tget_array_ndims, H5Tget_class,
H5Tget_cset, H5Tget_member_name, H5Tget_member_offset, H5Tget_member_type,
H5Tget_member_value, H5Tget_nmembers, H5Tget_sign, H5Tget_size, H5Tget_super, H5Tinsert,
H5Tis_variable_str, H5Tset_cset, H5Tset_size, H5Tset_strpad, H5Tvlen_create, H5T_VARIABLE,
},
};

use crate::globals::{H5T_C_S1, H5T_NATIVE_INT8};
Expand Down Expand Up @@ -40,28 +43,8 @@ macro_rules! be_le {
};
}

pub struct Datatype {
handle: Handle,
}

#[doc(hidden)]
impl ID for Datatype {
fn id(&self) -> hid_t {
self.handle.id()
}
}

#[doc(hidden)]
impl FromID for Datatype {
fn from_id(id: hid_t) -> Result<Datatype> {
h5lock!(match get_id_type(id) {
H5I_DATATYPE => Ok(Datatype { handle: Handle::new(id)? }),
_ => Err(From::from(format!("Invalid datatype id: {}", id))),
})
}
}

impl Object for Datatype {}
/// Represents the HDF5 datatype object.
define_object_type!(Datatype: Object, "datatype", |id_type| id_type == H5I_DATATYPE);

impl fmt::Debug for Datatype {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Expand Down
40 changes: 8 additions & 32 deletions hdf5-rs/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,41 +9,15 @@ use libhdf5_sys::{
H5F_ACC_RDWR, H5F_ACC_TRUNC, H5F_OBJ_ALL, H5F_OBJ_FILE, H5F_SCOPE_LOCAL,
},
h5fd::{H5Pset_fapl_core, H5Pset_fapl_sec2, H5Pset_fapl_stdio},
h5i::H5I_FILE,
h5p::{H5Pcreate, H5Pget_userblock, H5Pset_userblock},
};

use crate::globals::{H5P_FILE_ACCESS, H5P_FILE_CREATE};
use crate::internal_prelude::*;

/// Represents the HDF5 file object.
pub struct File {
handle: Handle,
}

#[doc(hidden)]
impl ID for File {
fn id(&self) -> hid_t {
self.handle.id()
}
}

#[doc(hidden)]
impl FromID for File {
fn from_id(id: hid_t) -> Result<File> {
h5lock!({
match get_id_type(id) {
H5I_FILE => Ok(File { handle: Handle::new(id)? }),
_ => Err(From::from(format!("Invalid file id: {}", id))),
}
})
}
}

impl Object for File {}

impl Location for File {}

impl Container for File {}
define_object_type!(File: Container, "file", |id_type| id_type == H5I_FILE);

impl File {
/// Create a new file object.
Expand Down Expand Up @@ -110,6 +84,7 @@ impl File {

/// Flushes the file to the storage medium.
pub fn flush(&self) -> Result<()> {
// TODO: &mut self?
h5call!(H5Fflush(self.id(), H5F_SCOPE_LOCAL)).and(Ok(()))
}

Expand All @@ -133,21 +108,22 @@ impl File {

/// Closes the file and invalidates all open handles for contained objects.
pub fn close(&self) {
// TODO: self instead of &self?
h5lock!({
let file_ids = self.get_obj_ids(H5F_OBJ_FILE);
let object_ids = self.get_obj_ids(H5F_OBJ_ALL & !H5F_OBJ_FILE);
for file_id in &file_ids {
let handle = Handle::from_id(*file_id);
let handle = Handle::new(*file_id);
if let Ok(handle) = handle {
while handle.is_valid() {
while handle.is_valid_user_id() {
handle.decref();
}
}
}
for object_id in &object_ids {
let handle = Handle::from_id(*object_id);
let handle = Handle::new(*object_id);
if let Ok(handle) = handle {
while handle.is_valid() {
while handle.is_valid_user_id() {
handle.decref();
}
}
Expand Down
29 changes: 3 additions & 26 deletions hdf5-rs/src/group.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::fmt;

use libhdf5_sys::h5i::H5I_type_t;

use crate::internal_prelude::*;

/// Represents the HDF5 group object.
pub struct Group {
handle: Handle,
}
define_object_type!(Group: Container, "group", |id_type| id_type == H5I_type_t::H5I_GROUP);

impl fmt::Debug for Group {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Expand All @@ -28,29 +28,6 @@ impl fmt::Display for Group {
}
}

#[doc(hidden)]
impl ID for Group {
fn id(&self) -> hid_t {
self.handle.id()
}
}

#[doc(hidden)]
impl FromID for Group {
fn from_id(id: hid_t) -> Result<Group> {
match get_id_type(id) {
H5I_GROUP => Ok(Group { handle: Handle::new(id)? }),
_ => Err(From::from(format!("Invalid group id: {}", id))),
}
}
}

impl Object for Group {}

impl Location for Group {}

impl Container for Group {}

#[cfg(test)]
pub mod tests {
use crate::internal_prelude::*;
Expand Down
Loading

0 comments on commit 53eff4f

Please sign in to comment.