Skip to content

Commit

Permalink
Merge pull request #36 from WiresmithTech/feature/refs2
Browse files Browse the repository at this point in the history
Object Reference Types
  • Loading branch information
magnusuMET authored Nov 27, 2024
2 parents dd8e048 + c461ec1 commit be72139
Show file tree
Hide file tree
Showing 15 changed files with 563 additions and 2 deletions.
2 changes: 1 addition & 1 deletion hdf5-src/ext/hdf5
Submodule hdf5 updated 4731 files
11 changes: 11 additions & 0 deletions hdf5-types/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,15 @@ fn main() {
if std::env::var_os("DEP_HDF5_MSVC_DLL_INDIRECTION").is_some() {
println!("cargo::rustc-cfg=windows_dll");
}

// Declare the known HDF5 versions we might feature flag on
// in this crate.
println!("cargo::rustc-check-cfg=cfg(feature, values(\"1.12.0\"))");

for (key, _) in std::env::vars() {
if key.starts_with("DEP_HDF5_VERSION_") {
let version = key.trim_start_matches("DEP_HDF5_VERSION_").replace("_", ".");
println!("cargo::rustc-cfg=feature=\"{version}\"");
}
}
}
1 change: 1 addition & 0 deletions hdf5-types/src/dyn_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,7 @@ impl<'a> DynValue<'a> {
FixedUnicode(_) => DynFixedString::new(buf, true).into(),
VarLenAscii => DynVarLenString::new(buf, false).into(),
VarLenUnicode => DynVarLenString::new(buf, true).into(),
Reference(_x) => todo!(),
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion hdf5-types/src/h5type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::os::raw::c_void;
use std::ptr;

use crate::array::VarLenArray;
use crate::references::Reference;
use crate::string::{FixedAscii, FixedUnicode, VarLenAscii, VarLenUnicode};

#[allow(non_camel_case_types)]
Expand Down Expand Up @@ -160,6 +161,7 @@ pub enum TypeDescriptor {
VarLenArray(Box<Self>),
VarLenAscii,
VarLenUnicode,
Reference(Reference),
}

impl Display for TypeDescriptor {
Expand All @@ -186,6 +188,10 @@ impl Display for TypeDescriptor {
TypeDescriptor::VarLenArray(ref tp) => write!(f, "[{}] (var len)", tp),
TypeDescriptor::VarLenAscii => write!(f, "string (var len)"),
TypeDescriptor::VarLenUnicode => write!(f, "unicode (var len)"),
TypeDescriptor::Reference(Reference::Object) => write!(f, "reference (object)"),
TypeDescriptor::Reference(Reference::Region) => write!(f, "reference (region)"),
#[cfg(feature = "1.12.0")]
TypeDescriptor::Reference(Reference::Std) => write!(f, "reference"),
}
}
}
Expand All @@ -202,6 +208,7 @@ impl TypeDescriptor {
Self::FixedAscii(len) | Self::FixedUnicode(len) => len,
Self::VarLenArray(_) => mem::size_of::<hvl_t>(),
Self::VarLenAscii | Self::VarLenUnicode => mem::size_of::<*const u8>(),
Self::Reference(reftyp) => reftyp.size(),
}
}

Expand Down Expand Up @@ -340,7 +347,7 @@ unsafe impl<T: H5Type, const N: usize> H5Type for [T; N] {
}
}

unsafe impl<T: Copy + H5Type> H5Type for VarLenArray<T> {
unsafe impl<T: H5Type + Copy> H5Type for VarLenArray<T> {
#[inline]
fn type_descriptor() -> TypeDescriptor {
TypeDescriptor::VarLenArray(Box::new(<T as H5Type>::type_descriptor()))
Expand Down
2 changes: 2 additions & 0 deletions hdf5-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ extern crate quickcheck;
mod array;
pub mod dyn_value;
mod h5type;
pub mod references;
mod string;

#[cfg(feature = "complex")]
Expand All @@ -30,6 +31,7 @@ pub use self::dyn_value::{DynValue, OwnedDynValue};
pub use self::h5type::{
CompoundField, CompoundType, EnumMember, EnumType, FloatSize, H5Type, IntSize, TypeDescriptor,
};
pub use self::references::Reference;
pub use self::string::{FixedAscii, FixedUnicode, StringError, VarLenAscii, VarLenUnicode};

pub(crate) unsafe fn malloc(n: usize) -> *mut core::ffi::c_void {
Expand Down
22 changes: 22 additions & 0 deletions hdf5-types/src/references.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! Types for references.
use std::mem;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Reference {
Object,
Region,
#[cfg(feature = "1.12.0")]
Std,
}

impl Reference {
pub fn size(self) -> usize {
match self {
Self::Object => mem::size_of::<hdf5_sys::h5r::hobj_ref_t>(),
Self::Region => mem::size_of::<hdf5_sys::h5r::hdset_reg_ref_t>(),
#[cfg(feature = "1.12.0")]
Self::Std => mem::size_of::<hdf5_sys::h5r::H5R_ref_t>(),
}
}
}
2 changes: 2 additions & 0 deletions hdf5/src/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ link_hid!(H5T_STD_B64BE, h5t::H5T_STD_B64BE);
link_hid!(H5T_STD_B64LE, h5t::H5T_STD_B64LE);
link_hid!(H5T_STD_REF_OBJ, h5t::H5T_STD_REF_OBJ);
link_hid!(H5T_STD_REF_DSETREG, h5t::H5T_STD_REF_DSETREG);
#[cfg(feature = "1.12.0")]
link_hid!(H5T_STD_REF, h5t::H5T_STD_REF);
link_hid!(H5T_UNIX_D32BE, h5t::H5T_UNIX_D32BE);
link_hid!(H5T_UNIX_D32LE, h5t::H5T_UNIX_D32LE);
link_hid!(H5T_UNIX_D64BE, h5t::H5T_UNIX_D64BE);
Expand Down
1 change: 1 addition & 0 deletions hdf5/src/hl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod group;
pub mod location;
pub mod object;
pub mod plist;
pub mod references;
pub mod selection;

pub use self::{
Expand Down
10 changes: 10 additions & 0 deletions hdf5/src/hl/datatype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,16 @@ impl Datatype {
}
TD::VarLenAscii => string_type(None, H5T_cset_t::H5T_CSET_ASCII),
TD::VarLenUnicode => string_type(None, H5T_cset_t::H5T_CSET_UTF8),
#[cfg(feature = "1.12.0")]
TD::Reference(hdf5_types::Reference::Std) => {
Ok(h5try!(H5Tcopy(*crate::globals::H5T_STD_REF)))
}
TD::Reference(hdf5_types::Reference::Object) => {
Ok(h5try!(H5Tcopy(*crate::globals::H5T_STD_REF_OBJ)))
}
TD::Reference(hdf5_types::Reference::Region) => {
Ok(h5try!(H5Tcopy(*crate::globals::H5T_STD_REF_DSETREG)))
}
}
});

Expand Down
14 changes: 14 additions & 0 deletions hdf5/src/hl/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,20 @@ impl Location {
pub fn open_by_token(&self, token: LocationToken) -> Result<Self> {
H5O_open_by_token(self.id(), token)
}

/// Generate a [object reference](ObjectReference) to the object for a reference storage.
///
/// This can be a group, dataset or datatype. Other objects are not supported.
pub fn reference<R: ObjectReference>(&self, name: &str) -> Result<R> {
R::create(self, name)
}

/// Get a reference back to the referenced object from a standard reference.
///
/// This can be called against any object in the same file as the referenced object.
pub fn dereference<R: ObjectReference>(&self, reference: &R) -> Result<ReferencedObject> {
reference.dereference(self)
}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Expand Down
61 changes: 61 additions & 0 deletions hdf5/src/hl/references.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use crate::internal_prelude::*;
use crate::Location;

mod legacy;

#[cfg(feature = "1.12.1")]
mod standard;

use hdf5_sys::h5o::H5O_type_t;
use hdf5_sys::h5r::H5R_type_t;

pub use legacy::ObjectReference1;
#[cfg(feature = "1.12.1")]
pub use standard::ObjectReference2;

mod private {
pub trait ObjectReferencePrivate {}
}

/// The trait for all object references. This provides a common interface
/// over the legacy and standard reference types.
///
/// This trait is sealed and cannot be implemented for types outside `hdf5::hl`.
pub trait ObjectReference: Sized + H5Type + private::ObjectReferencePrivate {
const REF_TYPE: H5R_type_t;
fn ptr(&self) -> *const c_void;

/// Get the type of the object that the reference points in the same space as the provided location.
fn get_object_type(&self, location: &Location) -> Result<H5O_type_t>;

/// Create a new reference in the same structure as the location provided.
fn create(location: &Location, name: &str) -> Result<Self>;

/// Dereference the object reference in the space provided.
fn dereference(&self, location: &Location) -> Result<ReferencedObject>;
}
/// The result of dereferencing an [object reference](ObjectReference).
///
/// Each variant represents a different type of object that can be referenced by a [ObjectReference].
#[derive(Clone, Debug)]
pub enum ReferencedObject {
Group(Group),
Dataset(Dataset),
Datatype(Datatype),
}

impl ReferencedObject {
pub fn from_type_and_id(object_type: H5O_type_t, object_id: hid_t) -> Result<Self> {
use hdf5_sys::h5o::H5O_type_t::*;
let referenced_object = match object_type {
H5O_TYPE_GROUP => ReferencedObject::Group(Group::from_id(object_id)?),
H5O_TYPE_DATASET => ReferencedObject::Dataset(Dataset::from_id(object_id)?),
H5O_TYPE_NAMED_DATATYPE => ReferencedObject::Datatype(Datatype::from_id(object_id)?),
#[cfg(feature = "1.12.0")]
H5O_TYPE_MAP => fail!("Can not create object from a map"),
H5O_TYPE_UNKNOWN => fail!("Unknown datatype"),
H5O_TYPE_NTYPES => fail!("hdf5 should not produce this type"),
};
Ok(referenced_object)
}
}
72 changes: 72 additions & 0 deletions hdf5/src/hl/references/legacy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//! The pre v1.12.0 reference types.
use crate::internal_prelude::*;

use hdf5_sys::{
h5o::H5O_type_t,
h5p::H5P_DEFAULT,
h5r::{hobj_ref_t, H5Rcreate, H5Rdereference, H5Rget_obj_type2},
};
use hdf5_types::H5Type;

#[cfg(not(feature = "1.12.0"))]
use hdf5_sys::h5r::H5R_OBJECT as H5R_OBJECT1;
#[cfg(feature = "1.12.0")]
use hdf5_sys::h5r::H5R_OBJECT1;

use super::{private::ObjectReferencePrivate, ObjectReference};
use crate::Location;

#[repr(transparent)]
#[derive(Debug, Copy, Clone)]
pub struct ObjectReference1 {
inner: hobj_ref_t,
}

unsafe impl H5Type for ObjectReference1 {
fn type_descriptor() -> hdf5_types::TypeDescriptor {
hdf5_types::TypeDescriptor::Reference(hdf5_types::Reference::Object)
}
}

impl ObjectReferencePrivate for ObjectReference1 {}

impl ObjectReference for ObjectReference1 {
const REF_TYPE: hdf5_sys::h5r::H5R_type_t = H5R_OBJECT1;

fn ptr(&self) -> *const c_void {
let pointer = std::ptr::addr_of!(self.inner);
pointer.cast()
}

fn create(location: &Location, name: &str) -> Result<Self> {
let mut ref_out: std::mem::MaybeUninit<hobj_ref_t> = std::mem::MaybeUninit::uninit();
let name = to_cstring(name)?;
h5call!(H5Rcreate(
ref_out.as_mut_ptr().cast(),
location.id(),
name.as_ptr(),
Self::REF_TYPE,
-1
))?;
let reference = unsafe { ref_out.assume_init() };
Ok(Self { inner: reference })
}

fn get_object_type(&self, location: &Location) -> Result<hdf5_sys::h5o::H5O_type_t> {
let mut objtype = std::mem::MaybeUninit::<H5O_type_t>::uninit();
h5call!(H5Rget_obj_type2(location.id(), H5R_OBJECT1, self.ptr(), objtype.as_mut_ptr()))?;
let objtype = unsafe { objtype.assume_init() };
Ok(objtype)
}

fn dereference(&self, location: &Location) -> Result<ReferencedObject> {
let object_type = self.get_object_type(location)?;
#[cfg(feature = "1.10.0")]
let object_id =
h5call!(H5Rdereference(location.id(), H5P_DEFAULT, H5R_OBJECT1, self.ptr()))?;
#[cfg(not(feature = "1.10.0"))]
let object_id = h5call!(H5Rdereference(location.id(), H5R_OBJECT1, self.ptr()))?;
ReferencedObject::from_type_and_id(object_type, object_id)
}
}
Loading

0 comments on commit be72139

Please sign in to comment.