Skip to content

Commit de1b903

Browse files
committed
FIX: Put .assume_init() on sound ground
Fix up the way we implement .assume_init() - use a mapping of the data storage type instead of transmute. The end result is similar anyway but easier to verify that it is correct. See docs for Arc::from_raw for its requirements - which we should now adhere to.
1 parent 79392bb commit de1b903

File tree

3 files changed

+55
-18
lines changed

3 files changed

+55
-18
lines changed

src/data_repr.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ use crate::extension::nonnull;
1010
/// *Don’t use this type directly—use the type alias
1111
/// [`Array`](type.Array.html) for the array type!*
1212
// Like a Vec, but with non-unique ownership semantics
13+
//
14+
// repr(C) to make it transmutable OwnedRepr<A> -> OwnedRepr<B> if
15+
// transmutable A -> B.
1316
#[derive(Debug)]
17+
#[repr(C)]
1418
pub struct OwnedRepr<A> {
1519
ptr: NonNull<A>,
1620
len: usize,
@@ -50,6 +54,23 @@ impl<A> OwnedRepr<A> {
5054
self.ptr
5155
}
5256

57+
/// Cast self into equivalent repr of other element type
58+
///
59+
/// ## Safety
60+
///
61+
/// Caller must ensure the two types have the same representation.
62+
/// **Panics** if sizes don't match (which is not a sufficient check).
63+
pub(crate) unsafe fn data_subst<B>(self) -> OwnedRepr<B> {
64+
// necessary but not sufficient check
65+
assert_eq!(mem::size_of::<A>(), mem::size_of::<B>());
66+
let self_ = ManuallyDrop::new(self);
67+
OwnedRepr {
68+
ptr: self_.ptr.cast::<B>(),
69+
len: self_.len,
70+
capacity: self_.capacity,
71+
}
72+
}
73+
5374
fn take_as_vec(&mut self) -> Vec<A> {
5475
let capacity = self.capacity;
5576
let len = self.len;

src/data_traits.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,28 +526,60 @@ unsafe impl<'a, A> DataMut for CowRepr<'a, A> where A: Clone {}
526526
pub trait RawDataSubst<A>: RawData {
527527
/// The resulting array storage of the same kind but substituted element type
528528
type Output: RawData<Elem = A>;
529+
530+
/// Unsafely translate the data representation from one element
531+
/// representation to another.
532+
///
533+
/// ## Safety
534+
///
535+
/// Caller must ensure the two types have the same representation.
536+
unsafe fn data_subst(self) -> Self::Output;
529537
}
530538

531539
impl<A, B> RawDataSubst<B> for OwnedRepr<A> {
532540
type Output = OwnedRepr<B>;
541+
542+
unsafe fn data_subst(self) -> Self::Output {
543+
self.data_subst()
544+
}
533545
}
534546

535547
impl<A, B> RawDataSubst<B> for OwnedArcRepr<A> {
536548
type Output = OwnedArcRepr<B>;
549+
550+
unsafe fn data_subst(self) -> Self::Output {
551+
OwnedArcRepr(Arc::from_raw(Arc::into_raw(self.0) as *const OwnedRepr<B>))
552+
}
537553
}
538554

539555
impl<A, B> RawDataSubst<B> for RawViewRepr<*const A> {
540556
type Output = RawViewRepr<*const B>;
557+
558+
unsafe fn data_subst(self) -> Self::Output {
559+
RawViewRepr::new()
560+
}
541561
}
542562

543563
impl<A, B> RawDataSubst<B> for RawViewRepr<*mut A> {
544564
type Output = RawViewRepr<*mut B>;
565+
566+
unsafe fn data_subst(self) -> Self::Output {
567+
RawViewRepr::new()
568+
}
545569
}
546570

547571
impl<'a, A: 'a, B: 'a> RawDataSubst<B> for ViewRepr<&'a A> {
548572
type Output = ViewRepr<&'a B>;
573+
574+
unsafe fn data_subst(self) -> Self::Output {
575+
ViewRepr::new()
576+
}
549577
}
550578

551579
impl<'a, A: 'a, B: 'a> RawDataSubst<B> for ViewRepr<&'a mut A> {
552580
type Output = ViewRepr<&'a mut B>;
581+
582+
unsafe fn data_subst(self) -> Self::Output {
583+
ViewRepr::new()
584+
}
553585
}

src/impl_special_element_types.rs

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9-
use std::mem::size_of;
10-
use std::mem::ManuallyDrop;
119
use std::mem::MaybeUninit;
1210

1311
use crate::imp_prelude::*;
@@ -37,12 +35,10 @@ where
3735
/// array's storage; it is for example possible to slice these in place, but that must
3836
/// only be done after all elements have been initialized.
3937
pub unsafe fn assume_init(self) -> ArrayBase<<S as RawDataSubst<A>>::Output, D> {
40-
// NOTE: Fully initialized includes elements not reachable in current slicing/view.
41-
4238
let ArrayBase { data, ptr, dim, strides } = self;
4339

44-
// transmute from storage of MaybeUninit<A> to storage of A
45-
let data = unlimited_transmute::<S, S::Output>(data);
40+
// "transmute" from storage of MaybeUninit<A> to storage of A
41+
let data = S::data_subst(data);
4642
let ptr = ptr.cast::<A>();
4743

4844
ArrayBase {
@@ -53,15 +49,3 @@ where
5349
}
5450
}
5551
}
56-
57-
/// Transmute from A to B.
58-
///
59-
/// Like transmute, but does not have the compile-time size check which blocks
60-
/// using regular transmute for "S to S::Output".
61-
///
62-
/// **Panics** if the size of A and B are different.
63-
unsafe fn unlimited_transmute<A, B>(data: A) -> B {
64-
assert_eq!(size_of::<A>(), size_of::<B>());
65-
let old_data = ManuallyDrop::new(data);
66-
(&*old_data as *const A as *const B).read()
67-
}

0 commit comments

Comments
 (0)