Skip to content

Commit f503665

Browse files
committed
Add cast to OwnedDynValue
1 parent 9ad0925 commit f503665

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

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

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

0 commit comments

Comments
 (0)