Skip to content

Commit d75f3b4

Browse files
committed
Add cast to OwnedDynValue
1 parent a7b0333 commit d75f3b4

File tree

2 files changed

+36
-18
lines changed

2 files changed

+36
-18
lines changed

hdf5-types/src/dyn_value.rs

+29-8
Original file line numberDiff line numberDiff line change
@@ -732,14 +732,35 @@ impl OwnedDynValue {
732732
Self { tp, buf }
733733
}
734734

735-
#[doc(hidden)]
736-
/// Use this if the values should still be used after the buffer has been
737-
/// copied to the concrete type
738-
pub fn drop_nonrecursive(mut self) {
739-
// We can't take ownership of the contents of self,
740-
// but we can replace the items with a zero-sized object
741-
self.tp = <[u8; 0] as H5Type>::type_descriptor();
742-
self.buf = Box::new([]);
735+
/// Cast to the concrete type
736+
///
737+
/// Will fail if the type-descriptors are not equal
738+
pub fn cast<T: H5Type>(mut self) -> Result<T, Self> {
739+
use std::mem::MaybeUninit;
740+
if self.tp != T::type_descriptor() {
741+
return Err(self);
742+
}
743+
debug_assert_eq!(self.tp.size(), self.buf.len());
744+
let mut out = MaybeUninit::<T>::uninit();
745+
unsafe {
746+
ptr::copy_nonoverlapping(
747+
self.buf.as_ptr(),
748+
out.as_mut_ptr().cast::<u8>(),
749+
self.buf.len(),
750+
);
751+
}
752+
// For safety we must ensure any nested structures are not live at the same time,
753+
// as this could cause a double free in `dyn_drop`.
754+
// We must deallocate only the top level of Self
755+
756+
// The zero-sized array has a special case to not drop ptr if len is zero,
757+
// so `dyn_drop` of `DynArray` is a nop
758+
self.tp = <[u8; 0]>::type_descriptor();
759+
// We must also swap out the buffer to ensure we can create the `DynValue`
760+
let mut b: Box<[u8]> = Box::new([]);
761+
std::mem::swap(&mut self.buf, &mut b);
762+
763+
Ok(unsafe { out.assume_init() })
743764
}
744765
}
745766

src/hl/plist/dataset_create.rs

+7-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! Dataset creation properties.
22
33
use std::fmt::{self, Debug};
4-
use std::mem;
54
use std::ops::Deref;
65
use std::ptr;
76

@@ -740,15 +739,13 @@ impl DatasetCreate {
740739
#[doc(hidden)]
741740
pub fn get_fill_value_as<T: H5Type>(&self) -> Result<Option<T>> {
742741
let dtype = Datatype::from_type::<T>()?;
743-
Ok(self.get_fill_value(&dtype.to_descriptor()?)?.map(|value| unsafe {
744-
let mut out: mem::MaybeUninit<T> = mem::MaybeUninit::uninit();
745-
let buf = value.get_buf();
746-
ptr::copy_nonoverlapping(buf.as_ptr(), out.as_mut_ptr().cast(), buf.len());
747-
// Drop the Box<[u8]>, but not subfields
748-
value.drop_nonrecursive();
749-
// We now have exclusive access to all subfields
750-
out.assume_init()
751-
}))
742+
self.get_fill_value(&dtype.to_descriptor()?)?
743+
.map(|value| {
744+
value
745+
.cast::<T>()
746+
.map_err(|_| "The fill value and requested types are not equal".into())
747+
})
748+
.transpose()
752749
}
753750

754751
pub fn fill_value_as<T: H5Type>(&self) -> Option<T> {

0 commit comments

Comments
 (0)