diff --git a/hdf5-derive/src/lib.rs b/hdf5-derive/src/lib.rs index a93ceef6..50d25c13 100644 --- a/hdf5-derive/src/lib.rs +++ b/hdf5-derive/src/lib.rs @@ -12,6 +12,7 @@ use syn::{ TypeGenerics, TypePath, }; +/// Derive macro generating an impl of the trait `H5Type`. #[proc_macro_derive(H5Type, attributes(hdf5))] #[proc_macro_error] pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { diff --git a/hdf5-types/src/array.rs b/hdf5-types/src/array.rs index f5b8956c..34e1e5af 100644 --- a/hdf5-types/src/array.rs +++ b/hdf5-types/src/array.rs @@ -5,6 +5,7 @@ use std::ops::Deref; use std::ptr; use std::slice; +/// A variable-length array. #[repr(C)] pub struct VarLenArray { len: usize, @@ -13,6 +14,14 @@ pub struct VarLenArray { } impl VarLenArray { + /// Creates a `VarLenArray` by copying the first `len` elements stored at `p`. + /// + /// Returns an empty array if `p` is null. + /// + /// # Safety + /// + /// - `p` must be valid for reads of `len * size_of::()` bytes. + /// - `p` must point to `len` consecutive properly initialized and aligned values of type `T`. pub unsafe fn from_parts(p: *const T, len: usize) -> Self { let (len, ptr) = if !p.is_null() && len != 0 { let dst = crate::malloc(len * mem::size_of::()); @@ -24,26 +33,31 @@ impl VarLenArray { Self { len, ptr: ptr as *const _, tag: PhantomData } } + /// Creates a `VarLenArray` from a slice by copying its elements. #[inline] pub fn from_slice(arr: &[T]) -> Self { unsafe { Self::from_parts(arr.as_ptr(), arr.len()) } } + /// Returns a raw pointer to the array's buffer. #[inline] pub fn as_ptr(&self) -> *const T { self.ptr } + /// Returns the number of elements in the array. #[inline] pub fn len(&self) -> usize { self.len as _ } + /// Returns `true` if the array has a length of zero. #[inline] pub fn is_empty(&self) -> bool { self.len == 0 } + /// Returns a slice containing the entire array. #[inline] pub fn as_slice(&self) -> &[T] { self diff --git a/hdf5-types/src/dyn_value.rs b/hdf5-types/src/dyn_value.rs index 1ef50ef3..dba57cd8 100644 --- a/hdf5-types/src/dyn_value.rs +++ b/hdf5-types/src/dyn_value.rs @@ -1,3 +1,5 @@ +//! Dynamically-typed values. + use std::fmt::{self, Debug, Display}; use std::mem; use std::ptr; @@ -26,6 +28,7 @@ unsafe trait DynClone { fn dyn_clone(&mut self, out: &mut [u8]); } +/// A dynamically-typed integer. #[derive(Copy, Clone, PartialEq, Eq)] pub enum DynInteger { Int8(i8), @@ -114,6 +117,7 @@ impl From for DynValue<'_> { } } +/// A dynamically-typed floating-point value. #[derive(Copy, Clone, PartialEq)] pub enum DynFloat { #[cfg(feature = "f16")] @@ -173,6 +177,7 @@ impl From for DynValue<'_> { } } +/// A dynamically-typed scalar value. #[derive(Copy, Clone, PartialEq)] pub enum DynScalar { Integer(DynInteger), @@ -212,6 +217,7 @@ impl From for DynValue<'static> { } } +/// A dynamically-typed enumeration value. #[derive(Copy, Clone)] pub struct DynEnum<'a> { tp: &'a EnumType, @@ -269,6 +275,7 @@ impl<'a> From> for DynValue<'a> { } } +/// A dynamically-typed compound value. pub struct DynCompound<'a> { tp: &'a CompoundType, buf: &'a [u8], @@ -354,6 +361,7 @@ impl<'a> From> for DynValue<'a> { } } +/// A dynamically-typed array. pub struct DynArray<'a> { tp: &'a TypeDescriptor, buf: &'a [u8], @@ -470,6 +478,7 @@ impl<'a> From> for DynValue<'a> { } } +/// A fixed-length string with a dynamic encoding. pub struct DynFixedString<'a> { buf: &'a [u8], unicode: bool, @@ -529,6 +538,7 @@ impl<'a> From> for DynValue<'a> { } } +/// A variable-length string with a dynamic encoding. pub struct DynVarLenString<'a> { buf: &'a [u8], unicode: bool, @@ -633,6 +643,7 @@ impl<'a> From> for DynValue<'a> { } } +/// A dynamically-typed string. #[derive(PartialEq, Eq)] pub enum DynString<'a> { Fixed(DynFixedString<'a>), @@ -677,6 +688,7 @@ impl<'a> From> for DynValue<'a> { } } +/// A borrowed value with dynamic type. #[derive(PartialEq)] pub enum DynValue<'a> { Scalar(DynScalar), @@ -687,6 +699,7 @@ pub enum DynValue<'a> { } impl<'a> DynValue<'a> { + /// Constructs a new `DynValue` from a `TypeDescriptor` and a byte slice. pub fn new(tp: &'a TypeDescriptor, buf: &'a [u8]) -> Self { use TypeDescriptor::*; debug_assert_eq!(tp.size(), buf.len()); @@ -748,12 +761,14 @@ impl Display for DynValue<'_> { } } +/// An owned value with dynamic type. pub struct OwnedDynValue { tp: TypeDescriptor, buf: Box<[u8]>, } impl OwnedDynValue { + /// Constructs a new `OwnedDynValue` from the given value. pub fn new(value: T) -> Self { let ptr = (&value as *const T).cast::(); let len = mem::size_of_val(&value); @@ -762,10 +777,12 @@ impl OwnedDynValue { Self { tp: T::type_descriptor(), buf: buf.to_owned().into_boxed_slice() } } + /// Returns a borrowed version of the contained value. pub fn get(&self) -> DynValue { DynValue::new(&self.tp, &self.buf) } + /// Returns the value's type descriptor. pub fn type_descriptor(&self) -> &TypeDescriptor { &self.tp } @@ -780,9 +797,12 @@ impl OwnedDynValue { Self { tp, buf } } - /// Cast to the concrete type + /// Tries to downcast the value to a concrete type. + /// + /// # Errors /// - /// Will fail if the type-descriptors are not equal + /// If the type descriptors of `self` and `T` are not equal, this will fail and return a + /// `Result::Err` containing the original value. pub fn cast(mut self) -> Result { use mem::MaybeUninit; if self.tp != T::type_descriptor() { diff --git a/hdf5-types/src/h5type.rs b/hdf5-types/src/h5type.rs index f8dbf6dd..2c53dd16 100644 --- a/hdf5-types/src/h5type.rs +++ b/hdf5-types/src/h5type.rs @@ -14,15 +14,21 @@ pub(crate) struct hvl_t { pub ptr: *mut c_void, } +/// A valid integer size. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum IntSize { + /// 1 byte. U1 = 1, + /// 2 bytes. U2 = 2, + /// 4 bytes. U4 = 4, + /// 8 bytes. U8 = 8, } impl IntSize { + /// Returns an `IntSize` of `size` bytes, or `None` if `size` is invalid. pub const fn from_int(size: usize) -> Option { if size == 1 { Some(Self::U1) @@ -38,15 +44,20 @@ impl IntSize { } } +/// A valid floating-point number size. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum FloatSize { + /// 2 bytes. #[cfg(feature = "f16")] U2 = 2, + /// 4 bytes. U4 = 4, + /// 8 bytes. U8 = 8, } impl FloatSize { + /// Returns a `FloatSize` of `size` bytes, or `None` if `size` is invalid. pub const fn from_int(size: usize) -> Option { #[cfg(feature = "f16")] { @@ -62,20 +73,28 @@ impl FloatSize { } } +/// A descriptor for an enumeration datatype member. #[derive(Clone, Debug, PartialEq, Eq)] pub struct EnumMember { + /// The name of the member. pub name: String, + /// The value of the member. pub value: u64, } +/// A descriptor for an enumeration datatype. #[derive(Clone, Debug, PartialEq, Eq)] pub struct EnumType { + /// The size of the underlying integer type. pub size: IntSize, + /// Whether to use a signed integer. pub signed: bool, + /// The enumeration datatype members. pub members: Vec, } impl EnumType { + /// Returns the type descriptor of the underlying integer datatype. #[inline] pub fn base_type(&self) -> TypeDescriptor { if self.signed { @@ -86,31 +105,42 @@ impl EnumType { } } +/// A descriptor for a compound datatype field. #[derive(Clone, Debug, PartialEq, Eq)] pub struct CompoundField { + /// The name of the field. pub name: String, + /// The type of the field. pub ty: TypeDescriptor, + /// The byte offset of the field. pub offset: usize, + /// The ordering of the field within the compound type. pub index: usize, } impl CompoundField { + /// Creates a new `CompoundField`. pub fn new(name: &str, ty: TypeDescriptor, offset: usize, index: usize) -> Self { Self { name: name.to_owned(), ty, offset, index } } + /// Creates a new `CompoundField` for a concrete type. pub fn typed(name: &str, offset: usize, index: usize) -> Self { Self::new(name, T::type_descriptor(), offset, index) } } +/// A descriptor for a compound datatype. #[derive(Clone, Debug, PartialEq, Eq)] pub struct CompoundType { + /// The fields of the datatype. pub fields: Vec, + /// The size in bytes of the datatype. pub size: usize, } impl CompoundType { + /// Converts `self` to a C struct representation. pub fn to_c_repr(&self) -> Self { let mut layout = self.clone(); layout.fields.sort_by_key(|f| f.index); @@ -133,6 +163,7 @@ impl CompoundType { layout } + /// Converts `self` to a packed representation. pub fn to_packed_repr(&self) -> Self { let mut layout = self.clone(); layout.fields.sort_by_key(|f| f.index); @@ -146,19 +177,32 @@ impl CompoundType { } } +/// A descriptor for an HDF5 datatype. #[derive(Clone, Debug, PartialEq, Eq)] pub enum TypeDescriptor { + /// A signed integer. Integer(IntSize), + /// An unsigned integer. Unsigned(IntSize), + /// A floating-point number. Float(FloatSize), + /// A boolean value. Boolean, + /// An enumeration datatype. Enum(EnumType), + /// A compound datatype. Compound(CompoundType), + /// A fixed-length array. FixedArray(Box, usize), + /// A fixed-length ASCII string. FixedAscii(usize), + /// A fixed-length UTF-8 string. FixedUnicode(usize), + /// A variable-length array. VarLenArray(Box), + /// A variable-length ASCII string. VarLenAscii, + /// A variable-length UTF-8 string. VarLenUnicode, } @@ -191,6 +235,7 @@ impl Display for TypeDescriptor { } impl TypeDescriptor { + /// Returns the size of the type in bytes. pub fn size(&self) -> usize { match *self { Self::Integer(size) | Self::Unsigned(size) => size as _, @@ -217,6 +262,7 @@ impl TypeDescriptor { } } + /// Converts `self` to a C-compatible representation. pub fn to_c_repr(&self) -> Self { match *self { Self::Compound(ref compound) => Self::Compound(compound.to_c_repr()), @@ -226,6 +272,7 @@ impl TypeDescriptor { } } + /// Converts `self` to a packed representation. pub fn to_packed_repr(&self) -> Self { match *self { Self::Compound(ref compound) => Self::Compound(compound.to_packed_repr()), @@ -236,7 +283,18 @@ impl TypeDescriptor { } } +/// A type that can be represented as an HDF5 datatype. +/// +/// # Derivable +/// This trait can be used with `#[derive]`. +/// +/// To `derive` on structs, they must be one of: `repr(C)`, `repr(packed)`, or `repr(transparent)`, +/// and have at least one field, all of which must implement `H5Type`. +/// +/// To `derive` on enums, they must have an explicit `repr` and at least one variant, all of which +/// must be unit variants with explicit discriminants. pub unsafe trait H5Type: 'static { + /// Returns a descriptor for an equivalent HDF5 datatype. fn type_descriptor() -> TypeDescriptor; } diff --git a/hdf5-types/src/lib.rs b/hdf5-types/src/lib.rs index 19f0389e..7076b320 100644 --- a/hdf5-types/src/lib.rs +++ b/hdf5-types/src/lib.rs @@ -52,6 +52,7 @@ pub(crate) unsafe fn free(ptr: *mut core::ffi::c_void) { } } +/// Whether this crate is using the HDF5 library for allocations instead of `libc`. pub const USING_H5_ALLOCATOR: bool = { cfg_if::cfg_if! { if #[cfg(any(feature = "h5-alloc", windows_dll))] { diff --git a/hdf5-types/src/string.rs b/hdf5-types/src/string.rs index 5f587f50..451b1051 100644 --- a/hdf5-types/src/string.rs +++ b/hdf5-types/src/string.rs @@ -11,6 +11,7 @@ use std::str::{self, FromStr}; use ascii::{AsAsciiStr, AsAsciiStrError, AsciiStr}; +/// Errors can occur when attempting to interpret a byte sequence as a string. #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[non_exhaustive] pub enum StringError { @@ -181,6 +182,7 @@ impl_string_traits!(VarLenUnicode); // ================================================================================ +/// A variable-length ASCII string. #[repr(C)] pub struct VarLenAscii { ptr: *mut u8, @@ -203,6 +205,7 @@ impl Clone for VarLenAscii { } impl VarLenAscii { + /// Creates a new empty `VarLenAscii` string. #[inline] pub fn new() -> Self { unsafe { @@ -220,36 +223,52 @@ impl VarLenAscii { Self { ptr } } + /// Returns the length of `self`. #[inline] pub fn len(&self) -> usize { unsafe { libc::strlen(self.ptr as *const _) } } + /// Returns `true` if `self` has a length of zero bytes. #[inline] pub fn is_empty(&self) -> bool { self.len() == 0 } + /// Returns a raw pointer to the string's buffer. #[inline] pub fn as_ptr(&self) -> *const u8 { self.ptr } + /// Returns the contents of the string as a byte slice. #[inline] pub fn as_bytes(&self) -> &[u8] { unsafe { slice::from_raw_parts(self.ptr as *const _, self.len()) } } + /// Returns the contents of the string as a string slice. #[inline] pub fn as_str(&self) -> &str { unsafe { str::from_utf8_unchecked(self.as_bytes()) } } + /// Converts a byte slice into a `VarLenAscii` without checking that the string contains only + /// non-zero ASCII bytes. + /// + /// # Safety + /// + /// The bytes must be valid ASCII and non-zero. #[inline] pub unsafe fn from_ascii_unchecked>(bytes: &B) -> Self { Self::from_bytes(bytes.as_ref()) } + /// Converts a byte slice into a `VarLenAscii`. + /// + /// # Errors + /// + /// Returns `Err` if the bytes are not valid ASCII, or if any byte is zero. pub fn from_ascii>(bytes: &B) -> Result { let bytes = bytes.as_ref(); if !bytes.iter().all(|&c| c != 0) { @@ -284,6 +303,7 @@ impl AsAsciiStr for VarLenAscii { // ================================================================================ +/// A variable-length UTF-8 string. #[repr(C)] pub struct VarLenUnicode { ptr: *mut u8, @@ -306,6 +326,7 @@ impl Clone for VarLenUnicode { } impl VarLenUnicode { + /// Creates a new empty `VarLenUnicode` string. #[inline] pub fn new() -> Self { unsafe { @@ -328,31 +349,42 @@ impl VarLenUnicode { libc::strlen(self.ptr as *const _) } + /// Returns the length of `self`. #[inline] pub fn len(&self) -> usize { self.as_str().len() } + /// Returns `true` if `self` has a length of zero bytes. #[inline] pub fn is_empty(&self) -> bool { unsafe { self.raw_len() == 0 } } + /// Returns a raw pointer to the string's buffer. #[inline] pub fn as_ptr(&self) -> *const u8 { self.ptr } + /// Returns the contents of the string as a byte slice. #[inline] pub fn as_bytes(&self) -> &[u8] { unsafe { slice::from_raw_parts(self.ptr as *const _, self.raw_len()) } } + /// Returns the contents of the string as a string slice. #[inline] pub fn as_str(&self) -> &str { unsafe { str::from_utf8_unchecked(self.as_bytes()) } } + /// Converts a byte slice into a `VarLenUnicode` without checking that the string contains only + /// non-zero UTF-8 bytes. + /// + /// # Safety + /// + /// The bytes must be valid UTF-8 and non-zero. #[inline] pub unsafe fn from_str_unchecked>(s: S) -> Self { Self::from_bytes(s.borrow().as_bytes()) @@ -373,6 +405,7 @@ impl FromStr for VarLenUnicode { // ================================================================================ +/// A fixed-length ASCII string. #[repr(C)] #[derive(Copy, Clone)] pub struct FixedAscii { @@ -380,6 +413,7 @@ pub struct FixedAscii { } impl FixedAscii { + /// Creates a new empty `FixedAscii` string. #[inline] pub fn new() -> Self { unsafe { Self { buf: mem::zeroed() } } @@ -398,41 +432,59 @@ impl FixedAscii { unsafe { slice::from_raw_parts(self.buf.as_ptr(), N) } } + /// Returns the string's capacity in bytes. #[inline] pub const fn capacity() -> usize { N } + /// Returns the length of `self`. #[inline] pub fn len(&self) -> usize { self.as_raw_slice().iter().rev().skip_while(|&c| *c == 0).count() } + /// Returns `true` if `self` has a length of zero bytes. #[inline] pub fn is_empty(&self) -> bool { self.as_raw_slice().iter().all(|&c| c == 0) } + /// Returns a raw pointer to the string's buffer. #[inline] pub fn as_ptr(&self) -> *const u8 { self.buf.as_ptr() } + /// Returns the contents of the string as a byte slice. #[inline] pub fn as_bytes(&self) -> &[u8] { &self.as_raw_slice()[..self.len()] } + /// Returns the contents of the string as a string slice. #[inline] pub fn as_str(&self) -> &str { unsafe { str::from_utf8_unchecked(self.as_bytes()) } } + /// Converts a byte slice into a `FixedAscii` without checking that the string is valid ASCII, + /// and truncating at the type's capacity. + /// + /// # Safety + /// + /// The bytes must be valid ASCII. #[inline] pub unsafe fn from_ascii_unchecked>(bytes: &B) -> Self { Self::from_bytes(bytes.as_ref()) } + /// Converts a byte slice into a `FixedAscii`. + /// + /// # Errors + /// + /// Returns `Err` if the bytes are not valid ASCII or if the slice length is greater than the + /// type's capacity. pub fn from_ascii>(bytes: &B) -> Result { let bytes = bytes.as_ref(); if bytes.len() > N { @@ -467,6 +519,7 @@ impl AsAsciiStr for FixedAscii { // ================================================================================ +/// A fixed-length UTF-8 string. #[repr(C)] #[derive(Copy, Clone)] pub struct FixedUnicode { @@ -474,6 +527,7 @@ pub struct FixedUnicode { } impl FixedUnicode { + /// Creates a new empty `FixedUnicode` string. #[inline] pub fn new() -> Self { unsafe { Self { buf: mem::zeroed() } } @@ -497,36 +551,48 @@ impl FixedUnicode { self.as_raw_slice().iter().rev().skip_while(|&c| *c == 0).count() } + /// Returns the string's capacity in bytes. #[inline] pub const fn capacity() -> usize { N } + /// Returns the length of `self`. #[inline] pub fn len(&self) -> usize { self.as_str().len() } + /// Returns `true` if `self` has a length of zero bytes. #[inline] pub fn is_empty(&self) -> bool { self.raw_len() == 0 } + /// Returns a raw pointer to the string's buffer. #[inline] pub fn as_ptr(&self) -> *const u8 { self.buf.as_ptr() } + /// Returns the contents of the string as a byte slice. #[inline] pub fn as_bytes(&self) -> &[u8] { &self.as_raw_slice()[..self.raw_len()] } + /// Returns the contents of the string as a string slice. #[inline] pub fn as_str(&self) -> &str { unsafe { str::from_utf8_unchecked(self.as_bytes()) } } + /// Converts a byte slice into a `FixedUnicode` without checking that the string is valid UTF-8, + /// and truncating at the type's capacity. + /// + /// # Safety + /// + /// The bytes must be valid UTF-8. #[inline] pub unsafe fn from_str_unchecked>(s: S) -> Self { Self::from_bytes(s.borrow().as_bytes()) diff --git a/hdf5/src/class.rs b/hdf5/src/class.rs index e859b14f..15527b63 100644 --- a/hdf5/src/class.rs +++ b/hdf5/src/class.rs @@ -81,6 +81,20 @@ pub trait ObjectClass: Sized { } } +/// Takes ownership of an object via its identifier. +/// +/// # Errors +/// +/// Returns an error if `id` does not refer to an object of type `T`. +/// +/// # Safety +/// +/// This should only be called with an identifier obtained from an object constructor in the HDF5 C +/// library. The reference count of a newly created object is 1, so this function creates a handle +/// for the object without incrementing its reference count. +/// +/// This function is unsafe because improper use may lead to the object being closed before all its +/// handles are dropped. pub unsafe fn from_id(id: hid_t) -> Result { T::from_id(id) } diff --git a/hdf5/src/error.rs b/hdf5/src/error.rs index 553a6dbe..71a4b53a 100644 --- a/hdf5/src/error.rs +++ b/hdf5/src/error.rs @@ -35,6 +35,7 @@ pub fn silence_errors(silence: bool) { h5lock!(silence_errors_no_sync(silence)); } +/// A stack of error records from an HDF5 library call. #[repr(transparent)] #[derive(Clone)] pub struct ErrorStack(Handle); @@ -107,6 +108,7 @@ impl ErrorStack { } } +/// An error record for an HDF5 library call. #[derive(Clone, Debug)] pub struct ErrorFrame { desc: String, @@ -127,19 +129,24 @@ impl ErrorFrame { } } + /// Returns the error description. pub fn desc(&self) -> &str { self.desc.as_ref() } + /// Returns a message with the error description and the relevant function name. pub fn description(&self) -> &str { self.description.as_ref() } + /// Returns a message with the error description and the relevant function name, file name, + /// and line number. pub fn detail(&self) -> Option { Some(format!("Error in {}(): {} [{}: {}]", self.func, self.desc, self.major, self.minor)) } } +/// A converted [`ErrorStack`] with methods to access [`ErrorFrame`] data. #[derive(Clone, Debug)] pub struct ExpandedErrorStack { frames: Vec, @@ -178,10 +185,12 @@ impl ExpandedErrorStack { } } + /// Returns the top [`ErrorFrame`] of the stack, or `None` if it is empty. pub fn top(&self) -> Option<&ErrorFrame> { self.get(0) } + /// Returns the description of the error on top of the stack. pub fn description(&self) -> &str { match self.description { None => "unknown library error", @@ -189,6 +198,7 @@ impl ExpandedErrorStack { } } + /// Returns a detailed message for the error on top of the stack, or `None` if it is empty. pub fn detail(&self) -> Option { self.top().and_then(ErrorFrame::detail) } diff --git a/hdf5/src/hl/attribute.rs b/hdf5/src/hl/attribute.rs index 8943e0aa..a5f84166 100644 --- a/hdf5/src/hl/attribute.rs +++ b/hdf5/src/hl/attribute.rs @@ -85,18 +85,22 @@ pub struct AttributeBuilder { } impl AttributeBuilder { + /// Creates a builder for a new attribute on a named object. pub fn new(parent: &Location) -> Self { Self { builder: AttributeBuilderInner::new(parent) } } + /// Sets the attribute's type without initializing its data. pub fn empty(self) -> AttributeBuilderEmpty { self.empty_as(&T::type_descriptor()) } + /// Sets the attribute's type from a type descriptor without initializing its data. pub fn empty_as(self, type_desc: &TypeDescriptor) -> AttributeBuilderEmpty { AttributeBuilderEmpty { builder: self.builder, type_desc: type_desc.clone() } } + /// Sets the data to store in the attribute. pub fn with_data<'d, A, T, D>(self, data: A) -> AttributeBuilderData<'d, T, D> where A: Into>, @@ -106,6 +110,7 @@ impl AttributeBuilder { self.with_data_as::(data, &T::type_descriptor()) } + /// Sets the data to store in the attribute and sets its element type with a type descriptor. pub fn with_data_as<'d, A, T, D>( self, data: A, type_desc: &TypeDescriptor, ) -> AttributeBuilderData<'d, T, D> @@ -138,6 +143,7 @@ pub struct AttributeBuilderEmpty { } impl AttributeBuilderEmpty { + /// Sets the shape of the attribute's data. pub fn shape>(self, extents: S) -> AttributeBuilderEmptyShape { AttributeBuilderEmptyShape { builder: self.builder, @@ -145,6 +151,8 @@ impl AttributeBuilderEmpty { extents: extents.into(), } } + + /// Creates the attribute. pub fn create<'n, T: Into<&'n str>>(self, name: T) -> Result { self.shape(()).create(name) } @@ -166,6 +174,7 @@ pub struct AttributeBuilderEmptyShape { } impl AttributeBuilderEmptyShape { + /// Creates the attribute. pub fn create<'n, T: Into<&'n str>>(&self, name: T) -> Result { h5lock!(self.builder.create(&self.type_desc, name.into(), &self.extents)) } @@ -204,6 +213,7 @@ where self } + /// Creates the attribute. pub fn create<'n, N: Into<&'n str>>(&self, name: N) -> Result { ensure!( self.data.is_standard_layout(), diff --git a/hdf5/src/hl/container.rs b/hdf5/src/hl/container.rs index 1c371ede..5811b96e 100644 --- a/hdf5/src/hl/container.rs +++ b/hdf5/src/hl/container.rs @@ -12,6 +12,7 @@ use hdf5_sys::h5p::H5Pcreate; use crate::internal_prelude::*; +/// A type for reading data from a [`Container`]. #[derive(Debug)] pub struct Reader<'a> { obj: &'a Container, @@ -188,6 +189,7 @@ impl<'a> Reader<'a> { } } +/// A type for writing data into a [`Container`]. #[derive(Debug)] pub struct Writer<'a> { obj: &'a Container, @@ -347,6 +349,7 @@ impl<'a> Writer<'a> { } } +/// A reader for a 1-dimensional dataset of bytes. #[derive(Debug, Clone)] pub struct ByteReader { obj: Container, @@ -357,6 +360,14 @@ pub struct ByteReader { } impl ByteReader { + /// Creates a new `ByteReader` for the given [`Container`]. + /// + /// # Panics + /// Panics if `obj` is not 1-dimensional. + /// + /// # Errors + /// + /// Returns an error if `obj` does not contain bytes or if the underlying library calls fail. pub fn new(obj: &Container) -> Result { ensure!(!obj.is_attr(), "ByteReader cannot be used on attribute datasets"); @@ -382,6 +393,7 @@ impl ByteReader { self.dataset_len().saturating_sub(self.pos as usize) } + /// Returns `true` if the reader has no more bytes to read. pub fn is_empty(&self) -> bool { self.pos >= self.dataset_len() as u64 } diff --git a/hdf5/src/hl/dataset.rs b/hdf5/src/hl/dataset.rs index 26415fde..5b7c7b04 100644 --- a/hdf5/src/hl/dataset.rs +++ b/hdf5/src/hl/dataset.rs @@ -1,3 +1,5 @@ +//! Interfaces for `Dataset` objects. + use std::fmt::{self, Debug}; use std::ops::Deref; @@ -311,11 +313,15 @@ where } } +/// Options for how to chunk data. #[derive(Debug, Clone, PartialEq, Eq)] pub enum Chunk { - Exact(Vec), // exact chunk shape - MinKB(usize), // minimum chunk shape in KB - None, // leave it unchunked + /// Exact chunk shape. + Exact(Vec), + /// Minimum chunk shape in kilobytes. + MinKB(usize), + /// Leave the data unchunked. + None, } impl Default for Chunk { diff --git a/hdf5/src/hl/dataspace.rs b/hdf5/src/hl/dataspace.rs index 58c9af2f..d4d5f1f1 100644 --- a/hdf5/src/hl/dataspace.rs +++ b/hdf5/src/hl/dataspace.rs @@ -78,46 +78,62 @@ unsafe fn get_simple_extents(space_id: hid_t) -> Result { } impl Dataspace { + /// Tries to construct a `Dataspace` from the given extents. + /// + /// # Errors + /// + /// Returns an error if the extents are invalid. pub fn try_new>(extents: T) -> Result { Self::from_extents(&extents.into()) } + /// Creates a new `Dataspace` that is a copy of the current one. pub fn copy(&self) -> Self { Self::from_id(h5lock!(H5Scopy(self.id()))).unwrap_or_else(|_| Self::invalid()) } + /// Returns the number of dimensions in the space. pub fn ndim(&self) -> usize { h5call!(H5Sget_simple_extent_ndims(self.id())).unwrap_or(0) as _ } + /// Returns a vector containing the current size of each dimension. pub fn shape(&self) -> Vec { h5lock!(get_shape(self.id())).unwrap_or_default() } + /// Returns a vector containing the current maximum size (if set) of each dimension. pub fn maxdims(&self) -> Vec> { self.extents().unwrap_or(Extents::Null).maxdims() } + /// Returns `true` if any dimension is resizable. pub fn is_resizable(&self) -> bool { self.maxdims().iter().any(Option::is_none) } + /// Returns `true` if the extent type is null. pub fn is_null(&self) -> bool { h5lock!(H5Sget_simple_extent_type(self.id())) == H5S_class_t::H5S_NULL } + /// Returns `true` if the extent type is scalar. pub fn is_scalar(&self) -> bool { h5lock!(H5Sget_simple_extent_type(self.id())) == H5S_class_t::H5S_SCALAR } + /// Returns `true` if the extent type is simple. pub fn is_simple(&self) -> bool { h5lock!(H5Sget_simple_extent_type(self.id())) == H5S_class_t::H5S_SIMPLE } + /// Returns `true` if the selection for the space is within the dataspace extent if the current + /// offset is used. pub fn is_valid(&self) -> bool { h5lock!(H5Sselect_valid(self.id())) > 0 } + /// Returns the number of elements in the space. pub fn size(&self) -> usize { match h5lock!(H5Sget_simple_extent_type(self.id())) { H5S_class_t::H5S_SIMPLE => { @@ -128,6 +144,11 @@ impl Dataspace { } } + /// Encodes the dataspace description into a new byte vector. + /// + /// # Errors + /// + /// Returns an error if the underlying encoding call fails. #[allow(deprecated)] pub fn encode(&self) -> Result> { cfg_if::cfg_if! { @@ -152,6 +173,11 @@ impl Dataspace { } } + /// Tries to decode a dataspace from a byte buffer. + /// + /// # Errors + /// + /// Returns an error if the buffer does not decode to a valid dataspace. pub fn decode(buf: T) -> Result where T: AsRef<[u8]>, @@ -174,6 +200,11 @@ impl Dataspace { })) } + /// Returns the extents of the dataspace. + /// + /// # Errors + /// + /// Returns an error if the extents type is unsupported. #[allow(clippy::match_wildcard_for_single_variants)] pub fn extents(&self) -> Result { h5lock!(match H5Sget_simple_extent_type(self.id()) { @@ -184,6 +215,7 @@ impl Dataspace { }) } + /// Returns the number of elements in the dataspace selection. pub fn selection_size(&self) -> usize { h5call!(H5Sget_select_npoints(self.id())).ok().map_or(0, |x| x as _) } @@ -199,6 +231,7 @@ impl Dataspace { }) } + /// Selects part of the dataspace and returns a new dataspace selection object. pub fn select>(&self, selection: S) -> Result { let raw_sel = selection.into().into_raw(self.shape())?; self.select_raw(raw_sel) @@ -209,6 +242,7 @@ impl Dataspace { sync(|| unsafe { RawSelection::extract_from_dataspace(self.id()) }) } + /// Returns a description of the current dataspace selection. pub fn get_selection(&self) -> Result { let raw_sel = self.get_raw_selection()?; Selection::from_raw(raw_sel) diff --git a/hdf5/src/hl/datatype.rs b/hdf5/src/hl/datatype.rs index 9c9ebe58..13d93c46 100644 --- a/hdf5/src/hl/datatype.rs +++ b/hdf5/src/hl/datatype.rs @@ -85,10 +85,14 @@ impl PartialEq for Datatype { } } +/// A level of possible conversion between two types. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum Conversion { + /// No conversion. NoOp = 1, // TODO: rename to "None"? + /// Functions employing compiler casting. Hard, + /// Functions not employing compiler casting. Soft, } @@ -120,12 +124,18 @@ impl Default for Conversion { } } +/// The byte order of a datatype. #[derive(Copy, Debug, Clone, PartialEq, Eq)] pub enum ByteOrder { + /// Little endian. LittleEndian, + /// Big endian. BigEndian, + /// VAX mixed endian. Vax, + /// Compound type with mixed member orders. Mixed, + /// No particular order. None, } @@ -166,6 +176,7 @@ impl Datatype { h5lock!(H5Tget_order(self.id())).into() } + /// Returns the conversion function level from `self` to `dst`, if one exists. pub fn conv_path(&self, dst: D) -> Option where D: Borrow, @@ -186,14 +197,17 @@ impl Datatype { }) } + /// Returns the conversion function level from `self` to a concrete type, if one exists. pub fn conv_to(&self) -> Option { Self::from_type::().ok().and_then(|dtype| self.conv_path(dtype)) } + /// Returns the conversion function level from a concrete type to `self`, if one exists. pub fn conv_from(&self) -> Option { Self::from_type::().ok().and_then(|dtype| dtype.conv_path(self)) } + /// Returns `true` if `self` represents a concrete type. pub fn is(&self) -> bool { Self::from_type::().ok().map_or(false, |dtype| &dtype == self) } @@ -213,6 +227,7 @@ impl Datatype { } } + /// Returns a type descriptor for the datatype. pub fn to_descriptor(&self) -> Result { use hdf5_types::TypeDescriptor as TD; @@ -306,10 +321,12 @@ impl Datatype { }) } + /// Creates a datatype from a concrete type. pub fn from_type() -> Result { Self::from_descriptor(&::type_descriptor()) } + /// Creates a datatype from a type descriptor. pub fn from_descriptor(desc: &TypeDescriptor) -> Result { use hdf5_types::TypeDescriptor as TD; diff --git a/hdf5/src/hl/extents.rs b/hdf5/src/hl/extents.rs index 9c9dea06..a91024be 100644 --- a/hdf5/src/hl/extents.rs +++ b/hdf5/src/hl/extents.rs @@ -68,6 +68,7 @@ impl + Clone> From<&T> for Extent { } impl Extent { + /// Creates a new extent with a current size and (optional) maximum size. pub fn new(dim: Ix, max: Option) -> Self { Self { dim, max } } @@ -82,18 +83,22 @@ impl Extent { Self { dim, max: None } } + /// Returns `true` if the current dimension size is at least the maximum size, if set. pub fn is_fixed(&self) -> bool { self.max.map_or(false, |max| self.dim >= max) } + /// Returns `true` if the dimension is resizable. pub fn is_resizable(&self) -> bool { self.max.is_none() } + /// Returns `true` if the dimension has unlimited maximum size. pub fn is_unlimited(&self) -> bool { self.is_resizable() } + /// Returns `true` if the current dimension size is not greater than the maximum. pub fn is_valid(&self) -> bool { self.max.unwrap_or(self.dim) >= self.dim } @@ -113,10 +118,12 @@ pub struct SimpleExtents { } impl SimpleExtents { + /// Creates extents from a vector of `Extent` values. pub fn from_vec(extents: Vec) -> Self { Self { inner: extents } } + /// Creates extents from an iterable of extent-like values. pub fn new(extents: T) -> Self where T: IntoIterator, @@ -125,6 +132,8 @@ impl SimpleExtents { Self::from_vec(extents.into_iter().map(Into::into).collect()) } + /// Creates extents from an iterable of dimension sizes and sets their + /// maximum sizes equal to their current sizes. pub fn fixed(extents: T) -> Self where T: IntoIterator, @@ -142,38 +151,48 @@ impl SimpleExtents { Self::from_vec(extents.into_iter().map(|x| Extent::resizable(*x.borrow())).collect()) } + /// Returns the number of dimensions. pub fn ndim(&self) -> usize { self.inner.len() } + /// Returns a vector containing the current size of each dimension. pub fn dims(&self) -> Vec { self.inner.iter().map(|e| e.dim).collect() } + /// Returns a vector containing the maximum size (if set) of each dimension. pub fn maxdims(&self) -> Vec> { self.inner.iter().map(|e| e.max).collect() } + /// Returns the number of elements that the space can hold. pub fn size(&self) -> usize { self.inner.iter().fold(1, |acc, x| acc * x.dim) } + /// Returns `true` if there is at least one dimension and they all have fixed maximum size. pub fn is_fixed(&self) -> bool { !self.inner.is_empty() && self.inner.iter().map(Extent::is_fixed).all(identity) } + /// Returns `true` if there is at least one resizable dimension. pub fn is_resizable(&self) -> bool { !self.inner.is_empty() && self.inner.iter().map(Extent::is_unlimited).any(identity) } + /// Returns `true` if there is at least one dimension of unlimited size. pub fn is_unlimited(&self) -> bool { self.inner.iter().map(Extent::is_unlimited).any(identity) } + /// Returns `true` if the extents are valid and the dimensionality does not exceed + /// HDF5's max rank. pub fn is_valid(&self) -> bool { self.inner.iter().map(Extent::is_valid).all(identity) && self.ndim() <= H5S_MAX_RANK as _ } + /// Returns an iterator over the `Extent` values for each dimension. pub fn iter( &self, ) -> impl ExactSizeIterator + DoubleEndedIterator { @@ -290,6 +309,7 @@ impl_from!(RangeFrom); impl_from!(RangeInclusive); impl_from!(Extent); +/// The dimensionality of a dataspace. #[derive(Clone, Debug, PartialEq, Eq)] pub enum Extents { /// A null dataspace contains no data elements. @@ -324,6 +344,7 @@ pub enum Extents { } impl Extents { + /// Creates extents from a value. pub fn new>(extents: T) -> Self { extents.into() } @@ -389,18 +410,22 @@ impl Extents { } } + /// Returns `true` if the extents are valid. pub fn is_valid(&self) -> bool { self.as_simple().map_or(true, SimpleExtents::is_valid) } + /// Returns `true` if the extents have unlimited maximum size. pub fn is_unlimited(&self) -> bool { self.as_simple().map_or(true, SimpleExtents::is_unlimited) } + /// Returns `true` if there is at least one resizable dimension. pub fn is_resizable(&self) -> bool { self.as_simple().map_or(true, SimpleExtents::is_resizable) } + /// Returns a version of `self` that is resizable along all dimensions. pub fn resizable(self) -> Self { match self { Self::Simple(extents) => SimpleExtents::resizable(extents.dims()).into(), @@ -408,12 +433,15 @@ impl Extents { } } + /// Returns an iterator of `Extent` values, one for each dimension. pub fn iter( &self, ) -> impl ExactSizeIterator + DoubleEndedIterator { ExtentsIter { inner: self.as_simple().map(SimpleExtents::iter) } } + /// Returns a slice containing an `Extent` for each dimension, or `None` if the extents are + /// null or scalar. pub fn slice(&self) -> Option<&[Extent]> { if let Self::Simple(x) = self { Some(x) @@ -423,6 +451,7 @@ impl Extents { } } +/// An iterator over the dimensions of an `Extents`. pub struct ExtentsIter { inner: Option, } diff --git a/hdf5/src/hl/filters.rs b/hdf5/src/hl/filters.rs index cd845ade..00f0213c 100644 --- a/hdf5/src/hl/filters.rs +++ b/hdf5/src/hl/filters.rs @@ -14,6 +14,7 @@ use hdf5_sys::h5z::{ H5_SZIP_NN_OPTION_MASK, }; +/// A filter identifier. pub use hdf5_sys::h5z::H5Z_filter_t; use crate::internal_prelude::*; @@ -23,20 +24,27 @@ mod blosc; #[cfg(feature = "lzf")] mod lzf; +/// Coding methods for Szip compression. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum SZip { + /// Entropy coding method. Entropy, + /// Nearest-neighbor coding method. NearestNeighbor, } +/// Scaling methods for scale-offset compression. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ScaleOffset { + /// Integer scaling with some MinBits value. Integer(u16), + /// Floating-point D-scaling with some decimal scale factor. FloatDScale(u8), } #[cfg(feature = "blosc")] mod blosc_impl { + /// Available compressors for Blosc compression. #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg(feature = "blosc")] pub enum Blosc { @@ -97,25 +105,39 @@ mod blosc_impl { #[cfg(feature = "blosc")] pub use blosc_impl::*; +/// An HDF5 filter configuration. #[derive(Clone, Debug, PartialEq, Eq)] pub enum Filter { + /// Gzip compression (deflation) with some compression level. Deflate(u8), + /// Shuffle algorithm. Shuffle, + /// Fletcher32 checksum. Fletcher32, + /// SZIP compression with some coding method and pixels per block. SZip(SZip, u8), + /// N-bit compression. NBit, + /// Scale-offset compression with some scaling mode. ScaleOffset(ScaleOffset), + /// LZF compression. #[cfg(feature = "lzf")] LZF, + /// Blosc compression with some compressor, compression level, and shuffle mode. #[cfg(feature = "blosc")] Blosc(Blosc, u8, BloscShuffle), + /// A user-defined filter with some parameters. User(H5Z_filter_t, Vec), } +/// Information about whether a filter is available and enabled for encoding/decoding. #[derive(Default, Clone, Copy, Debug, PartialEq, Eq)] pub struct FilterInfo { + /// Whether the filter is available. pub is_available: bool, + /// Whether the filter is configured to encode data. pub encode_enabled: bool, + /// Whether the filter is configured to decode data. pub decode_enabled: bool, } @@ -159,6 +181,7 @@ pub fn blosc_available() -> bool { } impl Filter { + /// Returns the filter's identifier. pub fn id(&self) -> H5Z_filter_t { match self { Self::Deflate(_) => H5Z_FILTER_DEFLATE, @@ -175,6 +198,7 @@ impl Filter { } } + /// Returns metadata for the filter with the given identifier. pub fn get_info(filter_id: H5Z_filter_t) -> FilterInfo { if !h5call!(H5Zfilter_avail(filter_id)).map(|x| x > 0).unwrap_or_default() { return FilterInfo::default(); @@ -188,47 +212,59 @@ impl Filter { } } + /// Returns `true` if the filter is available. pub fn is_available(&self) -> bool { Self::get_info(self.id()).is_available } + /// Returns `true` if the filter is configured to encode data. pub fn encode_enabled(&self) -> bool { Self::get_info(self.id()).encode_enabled } + /// Returns `true` if the filter is configured to decode data. pub fn decode_enabled(&self) -> bool { Self::get_info(self.id()).decode_enabled } + /// Creates a deflation filter configuration with some compression level. pub fn deflate(level: u8) -> Self { Self::Deflate(level) } + /// Returns the shuffle algorithm filter configuration. pub fn shuffle() -> Self { Self::Shuffle } + /// Returns the Fletcher32 checksum filter configuration. pub fn fletcher32() -> Self { Self::Fletcher32 } + /// Creates an Szip filter configuration with some coding method and pixels per block. pub fn szip(coding: SZip, px_per_block: u8) -> Self { Self::SZip(coding, px_per_block) } + /// Returns the N-bit compression filter configuration. pub fn nbit() -> Self { Self::NBit } + /// Creates a scale-offset compression filter configuration with some scaling mode. pub fn scale_offset(mode: ScaleOffset) -> Self { Self::ScaleOffset(mode) } + /// Returns the LZF compression filter. #[cfg(feature = "lzf")] pub fn lzf() -> Self { Self::LZF } + /// Creates a Blosc compression filter configuration with some compressor, + /// compression level, and shuffle mode. #[cfg(feature = "blosc")] pub fn blosc(complib: Blosc, clevel: u8, shuffle: T) -> Self where @@ -237,6 +273,8 @@ impl Filter { Self::Blosc(complib, clevel, shuffle.into()) } + /// Creates a Blosc LZ compression filter configuration with some compression level and + /// shuffle mode. #[cfg(feature = "blosc")] pub fn blosc_blosclz(clevel: u8, shuffle: T) -> Self where @@ -245,6 +283,8 @@ impl Filter { Self::blosc(Blosc::BloscLZ, clevel, shuffle) } + /// Creates a Blosc LZ4 compression filter configuration with some compression level and + /// shuffle mode. #[cfg(feature = "blosc")] pub fn blosc_lz4(clevel: u8, shuffle: T) -> Self where @@ -253,6 +293,8 @@ impl Filter { Self::blosc(Blosc::LZ4, clevel, shuffle) } + /// Creates a Blosc LZ4HC compression filter configuration with some compression level and + /// shuffle mode. #[cfg(feature = "blosc")] pub fn blosc_lz4hc(clevel: u8, shuffle: T) -> Self where @@ -261,6 +303,8 @@ impl Filter { Self::blosc(Blosc::LZ4HC, clevel, shuffle) } + /// Creates a Blosc Snappy compression filter configuration with some compression level and + /// shuffle mode. #[cfg(feature = "blosc")] pub fn blosc_snappy(clevel: u8, shuffle: T) -> Self where @@ -269,6 +313,8 @@ impl Filter { Self::blosc(Blosc::Snappy, clevel, shuffle) } + /// Creates a Blosc Zlib compression filter configuration with some compression level and + /// shuffle mode. #[cfg(feature = "blosc")] pub fn blosc_zlib(clevel: u8, shuffle: T) -> Self where @@ -277,6 +323,8 @@ impl Filter { Self::blosc(Blosc::ZLib, clevel, shuffle) } + /// Creates a Blosc Zstd compression filter configuration with some compression level and + /// shuffle mode. #[cfg(feature = "blosc")] pub fn blosc_zstd(clevel: u8, shuffle: T) -> Self where @@ -285,6 +333,7 @@ impl Filter { Self::blosc(Blosc::ZStd, clevel, shuffle) } + /// Creates a user-defined filter configuration with some filter identifier and parameters. pub fn user(id: H5Z_filter_t, cdata: &[c_uint]) -> Self { Self::User(id, cdata.to_vec()) } @@ -386,6 +435,12 @@ impl Filter { Ok(Self::blosc(complib, clevel, shuffle)) } + /// Tries to create a filter configuration from a filter identifier and parameters. + /// + /// # Errors + /// + /// Returns an error if the identifier is invalid or the parameters are invalid + /// for the specified filter. pub fn from_raw(filter_id: H5Z_filter_t, cdata: &[c_uint]) -> Result { ensure!(filter_id > 0, "invalid filter id: {}", filter_id); match filter_id { diff --git a/hdf5/src/hl/group.rs b/hdf5/src/hl/group.rs index 9bcbe28c..1123cace 100644 --- a/hdf5/src/hl/group.rs +++ b/hdf5/src/hl/group.rs @@ -261,10 +261,14 @@ impl From for H5_iter_order_t { } } +/// The type of an object link. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum LinkType { + /// A hard link to an object within a single file. Hard, + /// A symbolic link to an object within a single file. Soft, + /// A symbolic link to an object in a different file. External, } @@ -278,6 +282,7 @@ impl From for LinkType { } } +/// Metadata describing an object link. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct LinkInfo { pub link_type: LinkType, diff --git a/hdf5/src/hl/location.rs b/hdf5/src/hl/location.rs index 82adea4f..753043af 100644 --- a/hdf5/src/hl/location.rs +++ b/hdf5/src/hl/location.rs @@ -84,14 +84,14 @@ impl Location { File::from_id(h5try!(H5Iget_file_id(self.id()))) } - /// Returns the commment attached to the named object, if any. + /// Returns the comment attached to the named object, if any. pub fn comment(&self) -> Option { // TODO: should this return Result> or fail silently? let comment = h5lock!(get_h5_str(|m, s| H5Oget_comment(self.id(), m, s)).ok()); comment.and_then(|c| if c.is_empty() { None } else { Some(c) }) } - /// Set or the commment attached to the named object. + /// Set or the comment attached to the named object. #[deprecated(note = "attributes are preferred to comments")] pub fn set_comment(&self, comment: &str) -> Result<()> { // TODO: &mut self? @@ -100,7 +100,7 @@ impl Location { h5call!(H5Oset_comment(self.id(), comment.as_ptr())).and(Ok(())) } - /// Clear the commment attached to the named object. + /// Clear the comment attached to the named object. #[deprecated(note = "attributes are preferred to comments")] pub fn clear_comment(&self) -> Result<()> { // TODO: &mut self? @@ -108,52 +108,75 @@ impl Location { h5call!(H5Oset_comment(self.id(), ptr::null_mut())).and(Ok(())) } + /// Create a builder for a new attribute of known type. pub fn new_attr(&self) -> AttributeBuilderEmpty { AttributeBuilder::new(self).empty::() } + /// Create a builder for a new attribute. pub fn new_attr_builder(&self) -> AttributeBuilder { AttributeBuilder::new(self) } + /// Create a new named attribute on the object. pub fn attr(&self, name: &str) -> Result { let name = to_cstring(name)?; Attribute::from_id(h5try!(H5Aopen(self.id(), name.as_ptr(), H5P_DEFAULT))) } + /// Return the names of all attributes on the object. + /// + /// # Errors + /// + /// Returns an error if an underlying library call fails. pub fn attr_names(&self) -> Result> { Attribute::attr_names(self) } + /// Returns the object's metadata. pub fn loc_info(&self) -> Result { H5O_get_info(self.id(), true) } + /// Returns the object's type. pub fn loc_type(&self) -> Result { Ok(H5O_get_info(self.id(), false)?.loc_type) } + /// Returns the metadata of another object with name relative to `self`. + /// + /// # Errors + /// + /// Returns an error if the name is invalid. pub fn loc_info_by_name(&self, name: &str) -> Result { let name = to_cstring(name)?; H5O_get_info_by_name(self.id(), name.as_ptr(), true) } + /// Returns the type of another object with name relative to `self`. + /// + /// # Errors + /// + /// Returns an error if the name is invalid. pub fn loc_type_by_name(&self, name: &str) -> Result { let name = to_cstring(name)?; Ok(H5O_get_info_by_name(self.id(), name.as_ptr(), false)?.loc_type) } + /// Opens an object using its location token. pub fn open_by_token(&self, token: LocationToken) -> Result { H5O_open_by_token(self.id(), token) } } +/// A token containing the address or identifier of a [`Location`]. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct LocationToken( #[cfg(not(feature = "1.12.0"))] haddr_t, #[cfg(feature = "1.12.0")] H5O_token_t, ); +/// The type of an object in a [`Location`]. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum LocationType { Group, diff --git a/hdf5/src/hl/object.rs b/hdf5/src/hl/object.rs index cabe0e97..f6d8724c 100644 --- a/hdf5/src/hl/object.rs +++ b/hdf5/src/hl/object.rs @@ -29,6 +29,7 @@ impl Debug for Object { } impl Object { + /// Returns the object's identifier. pub fn id(&self) -> hid_t { self.0.id() } @@ -57,7 +58,7 @@ impl Object { macro_rules! impl_downcast { ($func:ident, $tp:ty) => { impl Object { - #[doc = "Downcast the object into $tp if possible."] + #[doc = concat!("Downcast the object into `", stringify!($tp), "` if possible.")] pub fn $func(&self) -> Result<$tp> { self.clone().cast() } diff --git a/hdf5/src/hl/plist.rs b/hdf5/src/hl/plist.rs index abd4da83..f514b402 100644 --- a/hdf5/src/hl/plist.rs +++ b/hdf5/src/hl/plist.rs @@ -93,7 +93,7 @@ pub enum PropertyListClass { LinkCreate, /// Properties for object copying process. ObjectCopy, - /// Properties for object creatio. + /// Properties for object creation. ObjectCreate, /// Properties for character encoding. StringCreate, @@ -209,6 +209,7 @@ impl PropertyList { }) } + /// Returns `true` if the property list is a member of `class`. pub fn is_class(&self, class: PropertyListClass) -> bool { use crate::globals::*; h5lock!({ diff --git a/hdf5/src/hl/plist/dataset_access.rs b/hdf5/src/hl/plist/dataset_access.rs index 99601347..73649347 100644 --- a/hdf5/src/hl/plist/dataset_access.rs +++ b/hdf5/src/hl/plist/dataset_access.rs @@ -91,10 +91,13 @@ impl Clone for DatasetAccess { } } +/// Options for including or excluding missing mapped elements in a virtual dataset view. #[cfg(feature = "1.10.0")] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum VirtualView { + /// Include all data before the first missing mapped data. FirstMissing, + /// Include all available mapped data, filling missing data with a fill value. LastAvailable, } @@ -165,29 +168,35 @@ impl DatasetAccessBuilder { Ok(builder) } + /// Sets the [`ChunkCache`] options. pub fn chunk_cache(&mut self, nslots: usize, nbytes: usize, w0: f64) -> &mut Self { self.chunk_cache = Some(ChunkCache { nslots, nbytes, w0 }); self } + /// Sets the external dataset storage file prefix. #[cfg(feature = "1.8.17")] pub fn efile_prefix(&mut self, prefix: &str) -> &mut Self { self.efile_prefix = Some(prefix.into()); self } + /// Sets the [`VirtualView`] options. #[cfg(feature = "1.10.0")] pub fn virtual_view(&mut self, view: VirtualView) -> &mut Self { self.virtual_view = Some(view); self } + /// Sets the maximum number of files/datasets allowed to be missing when determining the extent + /// of an unlimited virtual dataset with printf-style mappings. #[cfg(feature = "1.10.0")] pub fn virtual_printf_gap(&mut self, gap_size: usize) -> &mut Self { self.virtual_printf_gap = Some(gap_size); self } + /// Sets metadata I/O mode for read options to collective or independent. #[cfg(all(feature = "1.10.0", feature = "have-parallel"))] pub fn all_coll_metadata_ops(&mut self, is_collective: bool) -> &mut Self { self.all_coll_metadata_ops = Some(is_collective); @@ -223,10 +232,12 @@ impl DatasetAccessBuilder { Ok(()) } + /// Copies the builder settings into a dataset access property list. pub fn apply(&self, plist: &mut DatasetAccess) -> Result<()> { h5lock!(self.populate_plist(plist.id())) } + /// Constructs a new dataset access property list. pub fn finish(&self) -> Result { h5lock!({ let mut plist = DatasetAccess::try_new()?; @@ -237,14 +248,17 @@ impl DatasetAccessBuilder { /// Dataset access property list. impl DatasetAccess { + /// Creates a new dataset access property list. pub fn try_new() -> Result { Self::from_id(h5try!(H5Pcreate(*H5P_DATASET_ACCESS))) } + /// Creates a copy of the property list. pub fn copy(&self) -> Self { unsafe { self.deref().copy().cast_unchecked() } } + /// Creates a new dataset access property list builder. pub fn build() -> DatasetAccessBuilder { DatasetAccessBuilder::new() } @@ -260,6 +274,7 @@ impl DatasetAccess { ) } + /// Returns the raw data chunk cache parameters. pub fn chunk_cache(&self) -> ChunkCache { self.get_chunk_cache().unwrap_or_else(|_| ChunkCache::default()) } @@ -270,6 +285,7 @@ impl DatasetAccess { h5lock!(get_h5_str(|m, s| H5Pget_efile_prefix(self.id(), m, s))) } + /// Returns the external dataset storage file prefix. #[cfg(feature = "1.8.17")] pub fn efile_prefix(&self) -> String { self.get_efile_prefix().ok().unwrap_or_default() @@ -281,6 +297,7 @@ impl DatasetAccess { h5get!(H5Pget_virtual_view(self.id()): H5D_vds_view_t).map(Into::into) } + /// Returns the virtual dataset view options. #[cfg(feature = "1.10.0")] pub fn virtual_view(&self) -> VirtualView { self.get_virtual_view().ok().unwrap_or_default() @@ -292,6 +309,8 @@ impl DatasetAccess { h5get!(H5Pget_virtual_printf_gap(self.id()): hsize_t).map(|x| x as _) } + /// Returns the maximum number of files/datasets allowed to be missing when determining the + /// extent of an unlimited virtual dataset with printf-style mappings. #[cfg(feature = "1.10.0")] pub fn virtual_printf_gap(&self) -> usize { self.get_virtual_printf_gap().unwrap_or(0) @@ -303,6 +322,7 @@ impl DatasetAccess { h5get!(H5Pget_all_coll_metadata_ops(self.id()): hbool_t).map(|x| x > 0) } + /// Returns `true` if metadata I/O reads are set to collective, or `false` if independent. #[cfg(all(feature = "1.10.0", feature = "have-parallel"))] pub fn all_coll_metadata_ops(&self) -> bool { self.get_all_coll_metadata_ops().unwrap_or(false) diff --git a/hdf5/src/hl/plist/dataset_create.rs b/hdf5/src/hl/plist/dataset_create.rs index c9f96eba..1b93ea11 100644 --- a/hdf5/src/hl/plist/dataset_create.rs +++ b/hdf5/src/hl/plist/dataset_create.rs @@ -107,11 +107,16 @@ impl Clone for DatasetCreate { } } +/// Options for how to store raw data for a dataset. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Layout { + /// Raw data is stored in the file's object header. Compact, + /// Raw data is stored in a contiguous chunk in the file, outside the object header. Contiguous, + /// Raw data is stored in separate chunks in the file. Chunked, + /// Raw data is drawn from multiple datasets in different files. #[cfg(feature = "1.10.0")] Virtual, } @@ -148,8 +153,10 @@ impl From for H5D_layout_t { #[cfg(feature = "1.10.0")] bitflags! { + /// Edge chunk option flags. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct ChunkOpts: u32 { + /// Disable applying filters to partial edge chunks. const DONT_FILTER_PARTIAL_CHUNKS = H5D_CHUNK_DONT_FILTER_PARTIAL_CHUNKS; } } @@ -161,10 +168,14 @@ impl Default for ChunkOpts { } } +/// Options for when to allocate dataset storage space. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum AllocTime { + /// Allocate all space when the dataset is created. Early, + /// Allocate space incrementally as data is written to the dataset. Incr, + /// Allocate all space when data is first written to the dataset. Late, } @@ -188,10 +199,15 @@ impl From for H5D_alloc_time_t { } } +/// Options for when to write fill values to a dataset. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum FillTime { + /// Write fill values to the dataset when storage is allocated only if a user-defined fill + /// value is set. IfSet, + /// Write fill values to the dataset when storage is allocated. Alloc, + /// Never write fill values to the dataset. Never, } @@ -221,10 +237,14 @@ impl From for H5D_fill_time_t { } } +/// The status of a dataset creation property list's fill value. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum FillValue { + /// Fill value is undefined. Undefined, + /// Fill value is the library default. Default, + /// Fill value is defined by the application. UserDefined, } @@ -254,26 +274,38 @@ impl From for H5D_fill_value_t { } } +/// Properties of data stored in an external file. #[derive(Clone, Debug, PartialEq, Eq)] pub struct ExternalFile { + /// The name of the file. pub name: String, + /// The offset in bytes from the start of the file to the location where the data starts. pub offset: usize, + /// The number of bytes reserved in the file for data. pub size: usize, } +/// Properties of a mapping between virtual and source datasets. #[cfg(feature = "1.10.0")] #[derive(Clone, Debug, PartialEq, Eq)] pub struct VirtualMapping { + /// The name of the HDF5 file containing the source dataset. pub src_filename: String, + /// The path to the source dataset inside the file. pub src_dataset: String, + /// The dimensionality of the source dataset. pub src_extents: Extents, + /// The selection of the source dataset to be mapped. pub src_selection: Selection, + /// The dimensionality of the virtual dataset. pub vds_extents: Extents, + /// The selection fo the virtual dataset to be mapped. pub vds_selection: Selection, } #[cfg(feature = "1.10.0")] impl VirtualMapping { + /// Constructs a `VirtualMapping` with the given parameters. pub fn new( src_filename: F, src_dataset: D, src_extents: E1, src_selection: S1, vds_extents: E2, vds_selection: S2, @@ -365,41 +397,49 @@ impl DatasetCreateBuilder { Ok(builder) } + /// Sets the dataset filters from a slice of filter specifiers. pub fn set_filters(&mut self, filters: &[Filter]) -> &mut Self { self.filters = filters.to_owned(); self } + /// Adds a deflation filter with some compression level to the dataset. pub fn deflate(&mut self, level: u8) -> &mut Self { self.filters.push(Filter::deflate(level)); self } + /// Adds a shuffle filter to the dataset. pub fn shuffle(&mut self) -> &mut Self { self.filters.push(Filter::shuffle()); self } + /// Adds a Fletcher32 checksum filter to the dataset. pub fn fletcher32(&mut self) -> &mut Self { self.filters.push(Filter::fletcher32()); self } + /// Adds an Szip compression filter with some coding method and pixels per block to the dataset. pub fn szip(&mut self, coding: SZip, px_per_block: u8) -> &mut Self { self.filters.push(Filter::szip(coding, px_per_block)); self } + /// Adds an N-bit compression filter to the dataset. pub fn nbit(&mut self) -> &mut Self { self.filters.push(Filter::nbit()); self } + /// Adds a scale-offset compression filter with some scaling mode to the dataset. pub fn scale_offset(&mut self, mode: ScaleOffset) -> &mut Self { self.filters.push(Filter::scale_offset(mode)); self } + /// Adds an LZF compression filter to the dataset. #[cfg(feature = "lzf")] pub fn lzf(&mut self) -> &mut Self { self.filters.push(Filter::lzf()); @@ -421,6 +461,7 @@ impl DatasetCreateBuilder { self } + /// Adds a Blosc filter with LZ compression to the dataset. #[cfg(feature = "blosc")] pub fn blosc_blosclz(&mut self, clevel: u8, shuffle: T) -> &mut Self where @@ -430,6 +471,7 @@ impl DatasetCreateBuilder { self } + /// Adds a Blosc filter with LZ4 compression to the dataset. #[cfg(feature = "blosc")] pub fn blosc_lz4(&mut self, clevel: u8, shuffle: T) -> &mut Self where @@ -439,6 +481,7 @@ impl DatasetCreateBuilder { self } + /// Adds a Blosc filter with LZ4HC compression to the dataset. #[cfg(feature = "blosc")] pub fn blosc_lz4hc(&mut self, clevel: u8, shuffle: T) -> &mut Self where @@ -448,6 +491,7 @@ impl DatasetCreateBuilder { self } + /// Adds a Blosc filter with Snappy compression to the dataset. #[cfg(feature = "blosc")] pub fn blosc_snappy(&mut self, clevel: u8, shuffle: T) -> &mut Self where @@ -457,6 +501,7 @@ impl DatasetCreateBuilder { self } + /// Adds a Blosc filter with Zlib compression to the dataset. #[cfg(feature = "blosc")] pub fn blosc_zlib(&mut self, clevel: u8, shuffle: T) -> &mut Self where @@ -466,6 +511,7 @@ impl DatasetCreateBuilder { self } + /// Adds a Blosc filter with Zstd compression to the dataset. #[cfg(feature = "blosc")] pub fn blosc_zstd(&mut self, clevel: u8, shuffle: T) -> &mut Self where @@ -475,21 +521,25 @@ impl DatasetCreateBuilder { self } + /// Adds a user-defined filter with the given identifier and parameters to the dataset. pub fn add_filter(&mut self, id: H5Z_filter_t, cdata: &[c_uint]) -> &mut Self { self.filters.push(Filter::user(id, cdata)); self } + /// Removes all filters from the dataset. pub fn clear_filters(&mut self) -> &mut Self { self.filters.clear(); self } + /// Sets the dataset's storage space allocation timing. pub fn alloc_time(&mut self, alloc_time: Option) -> &mut Self { self.alloc_time = Some(alloc_time); self } + /// Sets the time when fill values should be written to the dataset. pub fn fill_time(&mut self, fill_time: FillTime) -> &mut Self { self.fill_time = Some(fill_time); self @@ -499,11 +549,13 @@ impl DatasetCreateBuilder { self.fill_time.is_some() } + /// Sets the dataset's fill value. pub fn fill_value>(&mut self, fill_value: T) -> &mut Self { self.fill_value = Some(fill_value.into()); self } + /// Clears the dataset's fill value. pub fn no_fill_value(&mut self) -> &mut Self { self.fill_value = None; self @@ -521,27 +573,32 @@ impl DatasetCreateBuilder { self } + /// Clears the dataset's chunking settings. pub fn no_chunk(&mut self) -> &mut Self { self.chunk = None; self } + /// Sets the dataset's raw data layout. pub fn layout(&mut self, layout: Layout) -> &mut Self { self.layout = Some(layout); self } + /// Sets the dataset's edge chunk options. #[cfg(feature = "1.10.0")] pub fn chunk_opts(&mut self, opts: ChunkOpts) -> &mut Self { self.chunk_opts = Some(opts); self } + /// Adds an external file to the dataset. pub fn external(&mut self, name: &str, offset: usize, size: usize) -> &mut Self { self.external.push(ExternalFile { name: name.to_owned(), offset, size }); self } + /// Adds a mapping between virtual and source datasets. #[cfg(feature = "1.10.0")] pub fn virtual_map( &mut self, src_filename: F, src_dataset: D, src_extents: E1, src_selection: S1, @@ -566,16 +623,19 @@ impl DatasetCreateBuilder { self } + /// Sets whether to record time data for the dataset. pub fn obj_track_times(&mut self, track_times: bool) -> &mut Self { self.obj_track_times = Some(track_times); self } + /// Sets the dataset's attribute storage phase change thresholds. pub fn attr_phase_change(&mut self, max_compact: u32, min_dense: u32) -> &mut Self { self.attr_phase_change = Some(AttrPhaseChange { max_compact, min_dense }); self } + /// Sets whether to track and/or index the dataset's attribute creation order. pub fn attr_creation_order(&mut self, attr_creation_order: AttrCreationOrder) -> &mut Self { self.attr_creation_order = Some(attr_creation_order); self @@ -650,10 +710,12 @@ impl DatasetCreateBuilder { !self.filters.is_empty() } + /// Copies the builder settings into a dataset creation property list. pub fn apply(&self, plist: &mut DatasetCreate) -> Result<()> { h5lock!(self.populate_plist(plist.id())) } + /// Constructs a new dataset creation property list. pub fn finish(&self) -> Result { h5lock!({ let mut plist = DatasetCreate::try_new()?; @@ -664,18 +726,22 @@ impl DatasetCreateBuilder { /// Dataset creation property list. impl DatasetCreate { + /// Constructs a new dataset creation property list. pub fn try_new() -> Result { Self::from_id(h5try!(H5Pcreate(*H5P_DATASET_CREATE))) } + /// Returns a copy of the dataset creation property list. pub fn copy(&self) -> Self { unsafe { self.deref().copy().cast_unchecked() } } + /// Returns a builder for configuring a dataset creation property list. pub fn build() -> DatasetCreateBuilder { DatasetCreateBuilder::new() } + /// Returns `true` if all required filters are available. pub fn all_filters_avail(&self) -> bool { h5lock!(H5Pall_filters_avail(self.id())) > 0 } @@ -685,10 +751,12 @@ impl DatasetCreate { Filter::extract_pipeline(self.id()) } + /// Returns a vector of the dataset's filter configurations. pub fn filters(&self) -> Vec { self.get_filters().unwrap_or_default() } + /// Returns `true` if there is at least one filter configured. pub fn has_filters(&self) -> bool { !self.filters().is_empty() } @@ -698,6 +766,7 @@ impl DatasetCreate { h5get!(H5Pget_alloc_time(self.id()): H5D_alloc_time_t).map(Into::into) } + /// Returns the storage allocation timing settings. pub fn alloc_time(&self) -> AllocTime { self.get_alloc_time().unwrap_or(AllocTime::Late) } @@ -707,6 +776,7 @@ impl DatasetCreate { h5get!(H5Pget_fill_time(self.id()): H5D_fill_time_t).map(Into::into) } + /// Returns the fill value timing settings. pub fn fill_time(&self) -> FillTime { self.get_fill_time().unwrap_or_default() } @@ -716,6 +786,7 @@ impl DatasetCreate { h5get!(H5Pfill_value_defined(self.id()): H5D_fill_value_t).map(Into::into) } + /// Returns the fill value status. pub fn fill_value_defined(&self) -> FillValue { self.get_fill_value_defined().unwrap_or(FillValue::Undefined) } @@ -736,6 +807,7 @@ impl DatasetCreate { } } + /// Returns the fill value converted to a dynamic type, or `None` if not set. pub fn fill_value(&self, tp: &TypeDescriptor) -> Option { self.get_fill_value(tp).unwrap_or_default() } @@ -752,6 +824,7 @@ impl DatasetCreate { .transpose() } + /// Returns the fill value converted to a concrete type, or `None` if not set. pub fn fill_value_as(&self) -> Option { self.get_fill_value_as::().unwrap_or_default() } @@ -768,6 +841,7 @@ impl DatasetCreate { } } + /// Returns a vector of chunk dimensions for the dataset, or `None` if it is not chunked. pub fn chunk(&self) -> Option> { self.get_chunk().unwrap_or_default() } @@ -779,6 +853,7 @@ impl DatasetCreate { Ok(layout.into()) } + /// Returns the layout setting for the dataset's raw data. pub fn layout(&self) -> Layout { self.get_layout().unwrap_or_default() } @@ -794,6 +869,7 @@ impl DatasetCreate { } } + /// Returns the edge chunk option setting, or `None` if the dataset is not chunked. #[cfg(feature = "1.10.0")] pub fn chunk_opts(&self) -> Option { self.get_chunk_opts().unwrap_or_default() @@ -828,6 +904,7 @@ impl DatasetCreate { }) } + /// Returns a vector of external file specifiers for the dataset. pub fn external(&self) -> Vec { self.get_external().unwrap_or_default() } @@ -868,6 +945,7 @@ impl DatasetCreate { }) } + /// Returns a vector of virtual mapping specifiers for the dataset. #[cfg(feature = "1.10.0")] pub fn virtual_map(&self) -> Vec { self.get_virtual_map().unwrap_or_default() @@ -878,6 +956,7 @@ impl DatasetCreate { h5get!(H5Pget_obj_track_times(self.id()): hbool_t).map(|x| x > 0) } + /// Returns `true` if object time tracking is enabled for the dataset. pub fn obj_track_times(&self) -> bool { self.get_obj_track_times().unwrap_or(true) } @@ -888,6 +967,7 @@ impl DatasetCreate { .map(|(mc, md)| AttrPhaseChange { max_compact: mc as _, min_dense: md as _ }) } + /// Returns the attribute storage phase change thresholds. pub fn attr_phase_change(&self) -> AttrPhaseChange { self.get_attr_phase_change().unwrap_or_default() } @@ -898,6 +978,7 @@ impl DatasetCreate { .map(AttrCreationOrder::from_bits_truncate) } + /// Returns flags for whether attribute creation order will be tracked/indexed. pub fn attr_creation_order(&self) -> AttrCreationOrder { self.get_attr_creation_order().unwrap_or_default() } diff --git a/hdf5/src/hl/plist/file_access.rs b/hdf5/src/hl/plist/file_access.rs index 6d0e050b..6718c70f 100644 --- a/hdf5/src/hl/plist/file_access.rs +++ b/hdf5/src/hl/plist/file_access.rs @@ -164,10 +164,14 @@ impl Clone for FileAccess { } } +/// Core file driver properties. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct CoreDriver { + /// Size, in bytes, of memory increments. pub increment: usize, + /// Whether to write the file contents to disk when the file is closed. pub filebacked: bool, + /// Size, in bytes, of write aggregation pages. Setting to 1 enables tracking with no paging. #[cfg(feature = "1.8.13")] pub write_tracking: usize, } @@ -183,8 +187,10 @@ impl Default for CoreDriver { } } +/// Family file driver properties. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct FamilyDriver { + /// Size in bytes of each file member. pub member_size: usize, } @@ -195,32 +201,63 @@ impl Default for FamilyDriver { } bitflags! { + /// Flags specifying types of logging activity for the logging virtual file driver. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct LogFlags: u64 { + /// Track truncate operations. const TRUNCATE = H5FD_LOG_TRUNCATE; + /// Track "meta" operations (e.g. truncate). const META_IO = H5FD_LOG_META_IO; + /// Track the location of every read. const LOC_READ = H5FD_LOG_LOC_READ; + /// Track the location of every write. const LOC_WRITE = H5FD_LOG_LOC_WRITE; + /// Track the location of every seek. const LOC_SEEK = H5FD_LOG_LOC_SEEK; + /// Track all I/O locations and lengths. + /// Equivalent to `LOC_READ | LOC_WRITE | LOC_SEEK`. const LOC_IO = H5FD_LOG_LOC_IO; + /// Track the number of times each byte is read. const FILE_READ = H5FD_LOG_FILE_READ; + /// Track the number of times each byte is written. const FILE_WRITE = H5FD_LOG_FILE_WRITE; + /// Track the number of all types of I/O operations. + /// Equivalent to `FILE_READ | FILE_WRITE`. const FILE_IO = H5FD_LOG_FILE_IO; + /// Track the type of information stored at each byte. const FLAVOR = H5FD_LOG_FLAVOR; + /// Track the total number of read operations. const NUM_READ = H5FD_LOG_NUM_READ; + /// Track the total number of write operations. const NUM_WRITE = H5FD_LOG_NUM_WRITE; + /// Track the total number of seek operations. const NUM_SEEK = H5FD_LOG_NUM_SEEK; + /// Track the total number of truncate operations. const NUM_TRUNCATE = H5FD_LOG_NUM_TRUNCATE; + /// Track the total number of all types of I/O operations. + /// Equivalent to `NUM_READ | NUM_WRITE | NUM_SEEK | NUM_TRUNCATE`. const NUM_IO = H5FD_LOG_NUM_IO; + /// Track the time spent in open operations. const TIME_OPEN = H5FD_LOG_TIME_OPEN; + /// Track the time spent in stat operations. const TIME_STAT = H5FD_LOG_TIME_STAT; + /// Track the time spent in read operations. const TIME_READ = H5FD_LOG_TIME_READ; + /// Track the time spent in write operations. const TIME_WRITE = H5FD_LOG_TIME_WRITE; + /// Track the time spent in seek operations. const TIME_SEEK = H5FD_LOG_TIME_SEEK; + /// Track the time spent in truncate operations. const TIME_TRUNCATE = H5FD_LOG_TIME_TRUNCATE; + /// Track the time spent in close operations. const TIME_CLOSE = H5FD_LOG_TIME_CLOSE; + /// Track the time spent in each I/O operation. + /// Equivalent to `TIME_OPEN | TIME_STAT | TIME_READ | TIME_WRITE | TIME_SEEK + /// | TIME_TRUNCATE | TIME_CLOSE`. const TIME_IO = H5FD_LOG_TIME_IO; + /// Track releases of space in the file. const FREE = H5FD_LOG_FREE; + /// Track everything. const ALL = H5FD_LOG_ALL; } } @@ -231,6 +268,7 @@ impl Default for LogFlags { } } +/// Logging virtual file driver properties. #[derive(Clone, Default, Debug, PartialEq, Eq)] pub struct LogOptions { logfile: Option, @@ -248,25 +286,36 @@ static FD_MEM_TYPES: &[H5F_mem_t] = &[ H5F_mem_t::H5FD_MEM_OHDR, ]; +/// Properties for a data storage used by the multi-file driver. #[derive(Clone, Debug, PartialEq, Eq)] pub struct MultiFile { + /// Name of the member file. pub name: String, + /// Offset within virtual address space where the storage begins. pub addr: u64, } impl MultiFile { + /// Creates a new `MultiFile`. pub fn new(name: &str, addr: u64) -> Self { Self { name: name.into(), addr } } } +/// A mapping of memory usage types to storage indices. #[derive(Clone, Debug, PartialEq, Eq)] pub struct MultiLayout { + /// Index of the superblock. pub mem_super: u8, + /// Index of the B-tree data. pub mem_btree: u8, + /// Index of the raw data. pub mem_draw: u8, + /// Index of the global heap data. pub mem_gheap: u8, + /// Index of the local heap data. pub mem_lheap: u8, + /// Index of the object headers. pub mem_object: u8, } @@ -302,10 +351,14 @@ impl MultiLayout { } } +/// Multi-file driver properties. #[derive(Clone, Debug, PartialEq, Eq)] pub struct MultiDriver { + /// The names and offsets of each type of data storage. pub files: Vec, + /// The mapping of memory usage types to file indices. pub layout: MultiLayout, + /// Whether to allow read-only access to incomplete file sets. pub relax: bool, } @@ -345,9 +398,12 @@ impl MultiDriver { } } +/// Split file driver properties. #[derive(Clone, Debug, PartialEq, Eq)] pub struct SplitDriver { + /// Metadata filename extension. pub meta_ext: String, + /// Raw data filename extension. pub raw_ext: String, } @@ -396,9 +452,12 @@ mod mpio { use super::{c_int, Result}; + /// MPI-I/O file driver properties. #[derive(Debug)] pub struct MpioDriver { + /// MPI-2 communicator. pub comm: MPI_Comm, + /// MPI-2 info object. pub info: MPI_Info, } @@ -453,11 +512,15 @@ mod mpio { #[cfg(feature = "mpio")] pub use self::mpio::*; +/// Direct I/O driver properties. #[cfg(feature = "have-direct")] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct DirectDriver { + /// Required memory alignment boundary. pub alignment: usize, + /// File system block size. pub block_size: usize, + /// Size in bytes of the copy buffer. pub cbuf_size: usize, } @@ -468,26 +531,43 @@ impl Default for DirectDriver { } } +/// A low-level file driver configuration. #[derive(Clone, Debug)] pub enum FileDriver { + /// Uses POSIX filesystem functions to perform unbuffered access to a single file. Sec2, + /// Uses functions from the standard C `stdio.h` to perform buffered access to a single file. Stdio, + /// SEC2 with logging capabilities. Log, + /// Keeps file contents in memory until the file is closed, enabling faster access. Core(CoreDriver), + /// Partitions file address space into pieces and sends them to separate storage files. Family(FamilyDriver), + /// Allows data to be stored in multiple files according to the type of data. Multi(MultiDriver), + /// Special case of the Multi driver that stores metadata and raw data in separate files. Split(SplitDriver), + /// Uses the MPI standard for communication and I/O. #[cfg(feature = "mpio")] Mpio(MpioDriver), + /// SEC2 except data is accessed synchronously without being cached by the system. #[cfg(feature = "have-direct")] Direct(DirectDriver), } +/// Options for what to do when trying to close a file while there are open objects inside it. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum FileCloseDegree { + /// Let the driver choose the behavior. + /// + /// All drivers set this to `Weak`, except for MPI-I/O, which sets it to `Semi`. Default, + /// Terminate file identifier access, but delay closing until all objects are closed. Weak, + /// Return an error if the file has open objects. Semi, + /// Close all open objects, then close the file. Strong, } @@ -519,22 +599,33 @@ impl From for H5F_close_degree_t { } } +/// File alignment properties. +/// +/// Any file object with size of at least `threshold` bytes will be aligned on an address that is +/// a multiple of `alignment`. Addresses are relative to the end of the user block. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Alignment { + /// The byte size threshold. pub threshold: u64, + /// The alignment value. pub alignment: u64, } impl Default for Alignment { + /// Returns the default threshold and alignment of 1 (i.e. no alignment). fn default() -> Self { Self { threshold: 1, alignment: 1 } } } +/// Raw data chunk cache parameters. #[derive(Clone, Copy, Debug, PartialEq)] pub struct ChunkCache { + /// The number of objects in the cache. pub nslots: usize, + /// The total size of the cache in bytes. pub nbytes: usize, + /// The chunk preemption policy. pub w0: f64, } @@ -546,16 +637,25 @@ impl Default for ChunkCache { impl Eq for ChunkCache {} +/// Page buffer size properties. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub struct PageBufferSize { + /// Maximum size, in bytes, of the page buffer. pub buf_size: usize, + /// Minimum metadata percentage to keep in the buffer before allowing pages with metadata to be + /// evicted. pub min_meta_perc: u32, + /// Minimum raw data percentage to keep in the buffer before allowing pages with raw data to be + /// evicted. pub min_raw_perc: u32, } +/// Automatic cache size increase mode. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum CacheIncreaseMode { + /// Automatic increase is disabled. Off, + /// Automatic increase uses the hit rate threshold algorithm. Threshold, } @@ -577,9 +677,12 @@ impl From for H5C_cache_incr_mode { } } +/// Flash cache size increase mode. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum FlashIncreaseMode { + /// Flash cache size increase is disabled. Off, + /// Flash cache size increase uses the add space algorithm. AddSpace, } @@ -601,11 +704,16 @@ impl From for H5C_cache_flash_incr_mode { } } +/// Automatic cache size decrease mode. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum CacheDecreaseMode { + /// Automatic decrease is disabled. Off, + /// Automatic decrease uses the hit rate threshold algorithm. Threshold, + /// Automatic decrease uses the ageout algorithm. AgeOut, + /// Automatic decrease uses the ageout with hit rate threshold algorithm. AgeOutWithThreshold, } @@ -631,9 +739,13 @@ impl From for H5C_cache_decr_mode { } } +/// A strategy for writing metadata to disk. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum MetadataWriteStrategy { + /// Only process zero is allowed to write dirty metadata to disk. ProcessZeroOnly, + /// Process zero decides what entries to flush, but the flushes are distributed across + /// processes. Distributed, } @@ -661,36 +773,76 @@ impl From for c_int { } } +/// Metadata cache configuration. #[derive(Clone, Debug, PartialEq)] pub struct MetadataCacheConfig { + /// Whether the adaptive cache resize report function is enabled. pub rpt_fcn_enabled: bool, + /// Whether `trace_file_name` should be used to open a trace file for the cache. pub open_trace_file: bool, + /// Whether the current trace file (if any) should be closed. pub close_trace_file: bool, + /// Full path of the trace file to be opened if `open_trace_file` is `true`. pub trace_file_name: String, + /// Whether evictions from the metadata cache are enabled. pub evictions_enabled: bool, + /// Whether the cache should be created with a user-specified initial size. pub set_initial_size: bool, + /// Initial cache size in bytes if `set_initial_size` is `true`. pub initial_size: usize, + /// Minimum fraction of the cache that must be kept clean or empty. pub min_clean_fraction: f64, + /// Maximum number of bytes that adaptive cache resizing can select as the maximum cache size. pub max_size: usize, + /// Minimum number of bytes that adaptive cache resizing can select as the minimum cache size. pub min_size: usize, + /// Number of cache accesses between runs of the adaptive cache resize code. pub epoch_length: i64, + /// Automatic cache size increase mode. pub incr_mode: CacheIncreaseMode, + /// Hit rate threshold for the hit rate threshold cache size increment algorithm. pub lower_hr_threshold: f64, + /// Factor by which the hit rate threshold cache size increment algorithm multiplies the current + /// cache max size to obtain a tentative new size. pub increment: f64, + /// Whether to apply an upper limit to the size of cache size increases. pub apply_max_increment: bool, + /// Maximum number of bytes by which cache size can be increased in a single step, + /// if applicable. pub max_increment: usize, + /// Flash cache size increase mode. pub flash_incr_mode: FlashIncreaseMode, + /// Factor by which the size of the triggering entry / entry size increase is multiplied to + /// obtain the initial cache size increment. pub flash_multiple: f64, + /// Factor by which the current maximum cache size is multiplied to obtain the minimum size + /// entry / entry size increase which may trigger a flash cache size increase. pub flash_threshold: f64, + /// Automatic cache size decrease mode. pub decr_mode: CacheDecreaseMode, + /// Hit rate threshold for hit-rate-based cache size decrease algorithms. pub upper_hr_threshold: f64, + /// Factor by which the hit rate threshold cache size decrease algorithm multiplies the current + /// cache max size to obtain a tentative new size. pub decrement: f64, + /// Whether an upper limit should be applied to the size of cache size decreases. pub apply_max_decrement: bool, + /// Maximum number of bytes by which cache size can be decreased in a single step, + /// if applicable. pub max_decrement: usize, + /// Minimum number of epochs that an entry must remain unaccessed in cache before ageout-based + /// reduction algorithms try to evict it. pub epochs_before_eviction: i32, + /// Whether ageout-based decrement algorithms will maintain an empty reserve. pub apply_empty_reserve: bool, + /// Empty reserve as a fraction of maximum cache size. + /// Ageout-based algorithms will not decrease the maximum size unless the empty reserve can be + /// met. pub empty_reserve: f64, + /// Threshold number of bytes of dirty metadata that will trigger synchronization of + /// parallel metadata caches. pub dirty_bytes_threshold: usize, + /// Strategy for writing metadata to disk. pub metadata_write_strategy: MetadataWriteStrategy, } @@ -816,10 +968,15 @@ impl From for MetadataCacheConfig { mod cache_image_config { use super::*; + /// Metadata cache image configuration. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct CacheImageConfig { + /// Whether a cache image should be created on file close. pub generate_image: bool, + /// Whether the cache image should include the adaptive cache resize configuration and + /// status. pub save_resize_status: bool, + /// Maximum number of times a prefetched entry can appear in subsequent cache images. pub entry_ageout: i32, } @@ -858,11 +1015,15 @@ mod cache_image_config { #[cfg(feature = "1.10.1")] pub use self::cache_image_config::*; +/// Metadata cache logging options. #[cfg(feature = "1.10.0")] #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct CacheLogOptions { + /// Whether logging is enabled. pub is_enabled: bool, + /// File path of the log. (Must be ASCII on Windows) pub location: String, + /// Whether to begin logging as soon as the file is opened pub start_on_access: bool, } @@ -870,18 +1031,24 @@ pub struct CacheLogOptions { mod libver { use super::*; + /// Options for which library format version to use when storing objects. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum LibraryVersion { + /// Use the earliest possible format. Earliest = 0, + /// Use the latest v18 format. V18 = 1, + /// Use the latest v110 format. V110 = 2, } impl LibraryVersion { + /// Returns `true` if the version is set to `Earliest`. pub fn is_earliest(self) -> bool { self == Self::Earliest } + /// Returns the latest library version. pub const fn latest() -> Self { Self::V110 } @@ -907,9 +1074,12 @@ mod libver { } } + /// Library format version bounds for writing objects to a file. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct LibVerBounds { + /// The earliest version to use for writing objects. pub low: LibraryVersion, + /// The latest version to use for writing objects. pub high: LibraryVersion, } @@ -1037,27 +1207,32 @@ impl FileAccessBuilder { self } + /// Sets the file alignment parameters. pub fn alignment(&mut self, threshold: u64, alignment: u64) -> &mut Self { self.alignment = Some(Alignment { threshold, alignment }); self } + /// Sets the raw data chunk cache parameters. pub fn chunk_cache(&mut self, nslots: usize, nbytes: usize, w0: f64) -> &mut Self { self.chunk_cache = Some(ChunkCache { nslots, nbytes, w0 }); self } + /// Sets the number of files that can be held open in an external link open file cache. #[cfg(feature = "1.8.7")] pub fn elink_file_cache_size(&mut self, efc_size: u32) -> &mut Self { self.elink_file_cache_size = Some(efc_size); self } + /// Sets the minimum metadata block size in bytes. pub fn meta_block_size(&mut self, size: u64) -> &mut Self { self.meta_block_size = Some(size); self } + /// Sets the page buffer size properties. #[cfg(feature = "1.10.1")] pub fn page_buffer_size( &mut self, buf_size: usize, min_meta_perc: u32, min_raw_perc: u32, @@ -1066,28 +1241,34 @@ impl FileAccessBuilder { self } + /// Sets the maximum size of the data sieve buffer. pub fn sieve_buf_size(&mut self, size: usize) -> &mut Self { self.sieve_buf_size = Some(size); self } + /// Sets whether object metadata should be evicted from cache when an object is closed. #[cfg(feature = "1.10.1")] pub fn evict_on_close(&mut self, evict_on_close: bool) -> &mut Self { self.evict_on_close = Some(evict_on_close); self } + /// Sets the number of reads that the library will try when reading checksummed metadata in a + /// file opened with SWMR access. #[cfg(feature = "1.10.0")] pub fn metadata_read_attempts(&mut self, attempts: u32) -> &mut Self { self.metadata_read_attempts = Some(attempts); self } + /// Sets the metadata cache configuration. pub fn mdc_config(&mut self, config: &MetadataCacheConfig) -> &mut Self { self.mdc_config = Some(config.clone()); self } + /// Sets whether a cache image should be created on file close. #[cfg(feature = "1.10.1")] pub fn mdc_image_config(&mut self, generate_image: bool) -> &mut Self { self.mdc_image_config = Some(CacheImageConfig { @@ -1098,6 +1279,7 @@ impl FileAccessBuilder { self } + /// Sets metadata cache logging options. #[cfg(feature = "1.10.0")] pub fn mdc_log_options( &mut self, is_enabled: bool, location: &str, start_on_access: bool, @@ -1107,67 +1289,80 @@ impl FileAccessBuilder { self } + /// Sets whether metadata reads are collective. #[cfg(all(feature = "1.10.0", feature = "have-parallel"))] pub fn all_coll_metadata_ops(&mut self, is_collective: bool) -> &mut Self { self.all_coll_metadata_ops = Some(is_collective); self } + /// Sets whether metadata writes are collective. #[cfg(all(feature = "1.10.0", feature = "have-parallel"))] pub fn coll_metadata_write(&mut self, is_collective: bool) -> &mut Self { self.coll_metadata_write = Some(is_collective); self } + /// Sets whether reference garbage collection is enabled. pub fn gc_references(&mut self, gc_ref: bool) -> &mut Self { self.gc_references = Some(gc_ref); self } + /// Sets the maximum size in bytes of a contiguous block reserved for small data. pub fn small_data_block_size(&mut self, size: u64) -> &mut Self { self.small_data_block_size = Some(size); self } + /// Sets the range of library versions to use when writing objects. #[cfg(feature = "1.10.2")] pub fn libver_bounds(&mut self, low: LibraryVersion, high: LibraryVersion) -> &mut Self { self.libver_bounds = Some(LibVerBounds { low, high }); self } + /// Allows use of the earliest library version when writing objects. #[cfg(feature = "1.10.2")] pub fn libver_earliest(&mut self) -> &mut Self { self.libver_bounds(LibraryVersion::Earliest, LibraryVersion::latest()) } + /// Sets the earliest library version for writing objects to v18. #[cfg(feature = "1.10.2")] pub fn libver_v18(&mut self) -> &mut Self { self.libver_bounds(LibraryVersion::V18, LibraryVersion::latest()) } + /// Sets the earliest library version for writing objects to v110. #[cfg(feature = "1.10.2")] pub fn libver_v110(&mut self) -> &mut Self { self.libver_bounds(LibraryVersion::V110, LibraryVersion::latest()) } + /// Allows only the latest library version when writing objects. #[cfg(feature = "1.10.2")] pub fn libver_latest(&mut self) -> &mut Self { self.libver_bounds(LibraryVersion::latest(), LibraryVersion::latest()) } + /// Sets which file driver to use. pub fn driver(&mut self, file_driver: &FileDriver) -> &mut Self { self.file_driver = Some(file_driver.clone()); self } + /// Sets the file driver to SEC2 (POSIX). pub fn sec2(&mut self) -> &mut Self { self.driver(&FileDriver::Sec2) } + /// Sets the file driver to STDIO. pub fn stdio(&mut self) -> &mut Self { self.driver(&FileDriver::Stdio) } + /// Sets the file driver to SEC2 with logging and configures it. pub fn log_options( &mut self, logfile: Option<&str>, flags: LogFlags, buf_size: usize, ) -> &mut Self { @@ -1177,38 +1372,46 @@ impl FileAccessBuilder { self.driver(&FileDriver::Log) } + /// Sets the file driver to SEC2 with logging. pub fn log(&mut self) -> &mut Self { self.log_options(None, LogFlags::LOC_IO, 0) } + /// Sets the file driver to Core and configures it. pub fn core_options(&mut self, increment: usize, filebacked: bool) -> &mut Self { let drv = CoreDriver { increment, filebacked, ..CoreDriver::default() }; self.driver(&FileDriver::Core(drv)) } + /// Sets the file driver to Core and sets whether to write file contents to disk upon closing. pub fn core_filebacked(&mut self, filebacked: bool) -> &mut Self { let drv = CoreDriver { filebacked, ..CoreDriver::default() }; self.driver(&FileDriver::Core(drv)) } + /// Sets the file driver to Core. pub fn core(&mut self) -> &mut Self { self.driver(&FileDriver::Core(CoreDriver::default())) } + /// Sets the write tracking page size for the Core file driver. #[cfg(feature = "1.8.13")] pub fn write_tracking(&mut self, page_size: usize) -> &mut Self { self.write_tracking = Some(page_size); self } + /// Sets the file driver to Family. pub fn family(&mut self) -> &mut Self { self.driver(&FileDriver::Family(FamilyDriver::default())) } + /// Sets the file driver to Family and configures the file member size. pub fn family_options(&mut self, member_size: usize) -> &mut Self { self.driver(&FileDriver::Family(FamilyDriver { member_size })) } + /// Sets the file driver to Multi and configures it. pub fn multi_options( &mut self, files: &[MultiFile], layout: &MultiLayout, relax: bool, ) -> &mut Self { @@ -1219,10 +1422,12 @@ impl FileAccessBuilder { })) } + /// Sets the file driver to Multi. pub fn multi(&mut self) -> &mut Self { self.driver(&FileDriver::Multi(MultiDriver::default())) } + /// Sets the file driver to Split and configures it. pub fn split_options(&mut self, meta_ext: &str, raw_ext: &str) -> &mut Self { self.driver(&FileDriver::Split(SplitDriver { meta_ext: meta_ext.into(), @@ -1230,16 +1435,19 @@ impl FileAccessBuilder { })) } + /// Sets the file driver to Split. pub fn split(&mut self) -> &mut Self { self.driver(&FileDriver::Split(SplitDriver::default())) } + /// Sets the file driver to MPI-I/O and configures it. #[cfg(feature = "mpio")] pub fn mpio(&mut self, comm: mpi_sys::MPI_Comm, info: Option) -> &mut Self { // We use .unwrap() here since MPI will almost surely terminate the process anyway. self.driver(&FileDriver::Mpio(MpioDriver::try_new(comm, info).unwrap())) } + /// Sets the file driver to Direct and configures it. #[cfg(feature = "have-direct")] pub fn direct_options( &mut self, alignment: usize, block_size: usize, cbuf_size: usize, @@ -1247,6 +1455,7 @@ impl FileAccessBuilder { self.driver(&FileDriver::Direct(DirectDriver { alignment, block_size, cbuf_size })) } + /// Sets the file driver to Direct. #[cfg(feature = "have-direct")] pub fn direct(&mut self) -> &mut Self { self.driver(&FileDriver::Direct(DirectDriver::default())) @@ -1482,10 +1691,12 @@ impl FileAccessBuilder { Ok(()) } + /// Copies the builder settings into a file access property list. pub fn apply(&self, plist: &mut FileAccess) -> Result<()> { h5lock!(self.populate_plist(plist.id())) } + /// Constructs a new file access property list. pub fn finish(&self) -> Result { h5lock!({ let mut plist = FileAccess::try_new()?; @@ -1496,14 +1707,17 @@ impl FileAccessBuilder { /// File access property list. impl FileAccess { + /// Creates a new file access property list. pub fn try_new() -> Result { Self::from_id(h5try!(H5Pcreate(*H5P_FILE_ACCESS))) } + /// Creates a copy of the property list. pub fn copy(&self) -> Self { unsafe { self.deref().copy().cast_unchecked() } } + /// Creates a new file access property list builder. pub fn build() -> FileAccessBuilder { FileAccessBuilder::new() } @@ -1628,6 +1842,7 @@ impl FileAccess { } } + /// Returns the file driver properties. pub fn driver(&self) -> FileDriver { self.get_driver().unwrap_or(FileDriver::Sec2) } @@ -1637,6 +1852,7 @@ impl FileAccess { h5get!(H5Pget_fclose_degree(self.id()): H5F_close_degree_t).map(Into::into) } + /// Returns the file close degree. pub fn fclose_degree(&self) -> FileCloseDegree { self.get_fclose_degree().unwrap_or_else(|_| FileCloseDegree::default()) } @@ -1648,6 +1864,7 @@ impl FileAccess { }) } + /// Returns the file alignment properties. pub fn alignment(&self) -> Alignment { self.get_alignment().unwrap_or_else(|_| Alignment::default()) } @@ -1663,6 +1880,7 @@ impl FileAccess { ) } + /// Returns the raw data chunk cache properties. pub fn chunk_cache(&self) -> ChunkCache { self.get_chunk_cache().unwrap_or_else(|_| ChunkCache::default()) } @@ -1683,6 +1901,7 @@ impl FileAccess { h5get!(H5Pget_meta_block_size(self.id()): hsize_t).map(|x| x as _) } + /// Returns the metadata block size. pub fn meta_block_size(&self) -> u64 { self.get_meta_block_size().unwrap_or(2048) } @@ -1699,6 +1918,7 @@ impl FileAccess { ) } + /// Returns the page buffer size properties. #[cfg(feature = "1.10.1")] pub fn page_buffer_size(&self) -> PageBufferSize { self.get_page_buffer_size().unwrap_or_else(|_| PageBufferSize::default()) @@ -1709,6 +1929,7 @@ impl FileAccess { h5get!(H5Pget_sieve_buf_size(self.id()): size_t).map(|x| x as _) } + /// Returns the maximum data sieve buffer size. pub fn sieve_buf_size(&self) -> usize { self.get_sieve_buf_size().unwrap_or(64 * 1024) } @@ -1719,6 +1940,8 @@ impl FileAccess { h5get!(H5Pget_evict_on_close(self.id()): hbool_t).map(|x| x > 0) } + /// Returns `true` if an object will be evicted from the metadata cache when the object is + /// closed. #[cfg(feature = "1.10.1")] pub fn evict_on_close(&self) -> bool { self.get_evict_on_close().unwrap_or(false) @@ -1730,6 +1953,7 @@ impl FileAccess { h5get!(H5Pget_metadata_read_attempts(self.id()): c_uint).map(|x| x as _) } + /// Returns the number of read attempts for SWMR access. #[cfg(feature = "1.10.0")] pub fn metadata_read_attempts(&self) -> u32 { self.get_metadata_read_attempts().unwrap_or(1) @@ -1742,6 +1966,7 @@ impl FileAccess { h5call!(H5Pget_mdc_config(self.id(), &mut config)).map(|_| config.into()) } + /// Returns the metadata cache configuration. pub fn mdc_config(&self) -> MetadataCacheConfig { self.get_mdc_config().ok().unwrap_or_default() } @@ -1754,6 +1979,7 @@ impl FileAccess { h5call!(H5Pget_mdc_image_config(self.id(), &mut config)).map(|_| config.into()) } + /// Returns the metadata cache image configuration. #[cfg(feature = "1.10.1")] pub fn mdc_image_config(&self) -> CacheImageConfig { self.get_mdc_image_config().ok().unwrap_or_default() @@ -1788,6 +2014,7 @@ impl FileAccess { }) } + /// Returns the metadata cache logging options. #[cfg(feature = "1.10.0")] pub fn mdc_log_options(&self) -> CacheLogOptions { self.get_mdc_log_options().ok().unwrap_or_default() @@ -1799,6 +2026,7 @@ impl FileAccess { h5get!(H5Pget_all_coll_metadata_ops(self.id()): hbool_t).map(|x| x > 0) } + /// Returns `true` if metadata reads are collective. #[cfg(all(feature = "1.10.0", feature = "have-parallel"))] pub fn all_coll_metadata_ops(&self) -> bool { self.get_all_coll_metadata_ops().unwrap_or(false) @@ -1810,6 +2038,7 @@ impl FileAccess { h5get!(H5Pget_coll_metadata_write(self.id()): hbool_t).map(|x| x > 0) } + /// Returns `true` if metadata writes are collective. #[cfg(all(feature = "1.10.0", feature = "have-parallel"))] pub fn coll_metadata_write(&self) -> bool { self.get_coll_metadata_write().unwrap_or(false) @@ -1820,6 +2049,7 @@ impl FileAccess { h5get!(H5Pget_gc_references(self.id()): c_uint).map(|x| x > 0) } + /// Returns `true` if reference garbage collection is enabled. pub fn gc_references(&self) -> bool { self.get_gc_references().unwrap_or(false) } @@ -1829,6 +2059,7 @@ impl FileAccess { h5get!(H5Pget_small_data_block_size(self.id()): hsize_t).map(|x| x as _) } + /// Returns the size setting in bytes of the small data block. pub fn small_data_block_size(&self) -> u64 { self.get_small_data_block_size().unwrap_or(2048) } @@ -1840,11 +2071,13 @@ impl FileAccess { .map(|(low, high)| LibVerBounds { low: low.into(), high: high.into() }) } + /// Returns the library format version bounds for writing objects to a file. #[cfg(feature = "1.10.2")] pub fn libver_bounds(&self) -> LibVerBounds { self.get_libver_bounds().ok().unwrap_or_default() } + /// Returns the lower library format version bound for writing objects to a file. #[cfg(feature = "1.10.2")] pub fn libver(&self) -> LibraryVersion { self.get_libver_bounds().ok().unwrap_or_default().low diff --git a/hdf5/src/hl/plist/file_create.rs b/hdf5/src/hl/plist/file_create.rs index 03b105da..9e86bb93 100644 --- a/hdf5/src/hl/plist/file_create.rs +++ b/hdf5/src/hl/plist/file_create.rs @@ -424,10 +424,12 @@ impl FileCreateBuilder { Ok(()) } + /// Copies the builder settings into a file creation property list. pub fn apply(&self, plist: &mut FileCreate) -> Result<()> { h5lock!(self.populate_plist(plist.id())) } + /// Constructs a new file creation property list. pub fn finish(&self) -> Result { h5lock!({ let mut plist = FileCreate::try_new()?; @@ -438,14 +440,17 @@ impl FileCreateBuilder { /// File creation property list. impl FileCreate { + /// Creates a new file creation property list. pub fn try_new() -> Result { Self::from_id(h5try!(H5Pcreate(*H5P_FILE_CREATE))) } + /// Creates a copy of the file creation property list. pub fn copy(&self) -> Self { unsafe { self.deref().copy().cast_unchecked() } } + /// Returns a builder for configuring a file creation property list. pub fn build() -> FileCreateBuilder { FileCreateBuilder::new() } diff --git a/hdf5/src/hl/plist/link_create.rs b/hdf5/src/hl/plist/link_create.rs index b1819680..02d11d15 100644 --- a/hdf5/src/hl/plist/link_create.rs +++ b/hdf5/src/hl/plist/link_create.rs @@ -69,9 +69,12 @@ impl Clone for LinkCreate { } } +/// The character encoding used to create a link or attribute name. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum CharEncoding { + /// US ASCII. Ascii, + /// UTF-8. Utf8, } @@ -96,11 +99,13 @@ impl LinkCreateBuilder { Ok(builder) } + /// Sets whether to create intermediate groups upon creation of an object. pub fn create_intermediate_group(&mut self, create: bool) -> &mut Self { self.create_intermediate_group = Some(create); self } + /// Sets the character encoding to use when creating links. pub fn char_encoding(&mut self, encoding: CharEncoding) -> &mut Self { self.char_encoding = Some(encoding); self @@ -120,10 +125,12 @@ impl LinkCreateBuilder { Ok(()) } + /// Copies the builder settings into a link creation property list. pub fn apply(&self, plist: &mut LinkCreate) -> Result<()> { h5lock!(self.populate_plist(plist.id())) } + /// Constructs a new link creation property list. pub fn finish(&self) -> Result { h5lock!({ let mut plist = LinkCreate::try_new()?; @@ -134,14 +141,17 @@ impl LinkCreateBuilder { /// Link create property list. impl LinkCreate { + /// Creates a new link creation property list. pub fn try_new() -> Result { Self::from_id(h5try!(H5Pcreate(*H5P_LINK_CREATE))) } + /// Creates a copy of the link creation property list. pub fn copy(&self) -> Self { unsafe { self.deref().copy().cast_unchecked() } } + /// Returns a builder for configuring a link creation property list. pub fn build() -> LinkCreateBuilder { LinkCreateBuilder::new() } @@ -151,6 +161,7 @@ impl LinkCreate { h5get!(H5Pget_create_intermediate_group(self.id()): c_uint).map(|x| x > 0) } + /// Returns `true` if intermediate groups will be created upon object creation. pub fn create_intermediate_group(&self) -> bool { self.get_create_intermediate_group().unwrap_or(false) } @@ -164,6 +175,7 @@ impl LinkCreate { }) } + /// Returns the character encoding used to create links. pub fn char_encoding(&self) -> CharEncoding { self.get_char_encoding().unwrap_or(CharEncoding::Ascii) } diff --git a/hdf5/src/hl/selection.rs b/hdf5/src/hl/selection.rs index ce089329..023684a6 100644 --- a/hdf5/src/hl/selection.rs +++ b/hdf5/src/hl/selection.rs @@ -772,8 +772,11 @@ impl Display for Hyperslab { #[derive(Clone, Debug, PartialEq, Eq)] /// A selection used for reading and writing to a [`Container`](Container). pub enum Selection { + /// The entire dataset. All, + /// A sequence of points. Points(Array2), + /// A hyperslab or compound hyperslab. Hyperslab(Hyperslab), } @@ -784,10 +787,16 @@ impl Default for Selection { } impl Selection { + /// Creates a new selection. pub fn new>(selection: T) -> Self { selection.into() } + /// Tries to create a new selection. + /// + /// # Errors + /// + /// Returns an error if the conversion method fails. pub fn try_new>(selection: T) -> Result { selection.try_into() } @@ -829,6 +838,8 @@ impl Selection { }) } + /// Returns the required number of dimensions for the input dataspace, + /// or `None` if selecting everything. pub fn in_ndim(&self) -> Option { match self { Self::All => None, @@ -843,6 +854,7 @@ impl Selection { } } + /// Returns the number of dimensions in the output dataspace, or `None` if selecting everything. pub fn out_ndim(&self) -> Option { match self { Self::All => None, @@ -853,6 +865,11 @@ impl Selection { } } + /// Returns the output shape that would result from applying the selection to some input shape. + /// + /// # Errors + /// + /// Returns an error if the input shape is incompatible with the selection. pub fn out_shape>(&self, in_shape: S) -> Result> { let in_shape = in_shape.as_ref(); match self { @@ -875,10 +892,12 @@ impl Selection { } } + /// Returns `true` if the selection is for the entire dataset. pub fn is_all(&self) -> bool { self == &Self::All } + /// Returns `true` if the selection is a sequence of points. pub fn is_points(&self) -> bool { if let Self::Points(ref points) = self { points.shape() != [0, 0] @@ -887,6 +906,7 @@ impl Selection { } } + /// Returns `true` if the selection is empty. pub fn is_none(&self) -> bool { if let Self::Points(points) = self { points.shape() == [0, 0] @@ -895,6 +915,7 @@ impl Selection { } } + /// Returns `true` if the selection is a hyperslab. pub fn is_hyperslab(&self) -> bool { matches!(self, Self::Hyperslab(_)) } diff --git a/hdf5/src/lib.rs b/hdf5/src/lib.rs index 5f6c3411..c929e70b 100644 --- a/hdf5/src/lib.rs +++ b/hdf5/src/lib.rs @@ -72,10 +72,12 @@ mod export { pub use hdf5_derive::H5Type; pub use hdf5_types::H5Type; + /// Base types and interfaces for creating compound data types. pub mod types { pub use hdf5_types::*; } + /// Multi-dimensional datasets. pub mod dataset { #[cfg(feature = "1.10.5")] pub use crate::hl::chunks::ChunkInfo; @@ -86,16 +88,19 @@ mod export { pub use crate::hl::plist::dataset_create::*; } + /// Datatype objects for defining the layout of a data element. pub mod datatype { pub use crate::hl::datatype::{ByteOrder, Conversion, Datatype}; } + /// HDF5 file objects. pub mod file { pub use crate::hl::file::{File, FileBuilder, OpenMode}; pub use crate::hl::plist::file_access::*; pub use crate::hl::plist::file_create::*; } + /// Property list objects. pub mod plist { pub use crate::hl::plist::dataset_access::{DatasetAccess, DatasetAccessBuilder}; pub use crate::hl::plist::dataset_create::{DatasetCreate, DatasetCreateBuilder}; @@ -104,22 +109,29 @@ mod export { pub use crate::hl::plist::link_create::{LinkCreate, LinkCreateBuilder}; pub use crate::hl::plist::{PropertyList, PropertyListClass}; + /// Dataset access property lists. pub mod dataset_access { pub use crate::hl::plist::dataset_access::*; } + /// Dataset creation property lists. pub mod dataset_create { pub use crate::hl::plist::dataset_create::*; } + /// File access property lists. pub mod file_access { pub use crate::hl::plist::file_access::*; } + /// File creation property lists. pub mod file_create { pub use crate::hl::plist::file_create::*; } + /// Link creation property lists. pub mod link_create { pub use crate::hl::plist::link_create::*; } } + + /// Filters for data compression and validation during file I/O. pub mod filters { pub use crate::hl::filters::*; }