Skip to content

Commit 91de988

Browse files
committed
move_into: Split into .move_into_unit() and .move_into_overwrite()
1 parent 902bba8 commit 91de988

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

src/impl_owned_array.rs

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,42 @@ impl<A> Array<A, Ix2> {
156156
impl<A, D> Array<A, D>
157157
where D: Dimension
158158
{
159+
/// Move all elements from self into `new_array`, which must be of the same shape but
160+
/// can have a different memory layout. The destination is overwritten completely.
161+
///
162+
/// The destination should be a mut reference to an array or an `ArrayViewMut` with
163+
/// `A` elements (which are **overwritten without dropping any existing value**).
164+
///
165+
/// Minor implementation note: Owned arrays like `self` may be sliced in place and own elements
166+
/// that are not part of their active view; these are dropped at the end of this function,
167+
/// after all elements in the "active view" are moved into `new_array`. If there is a panic in
168+
/// drop of any such element, other elements may be leaked.
169+
///
170+
/// ***Panics*** if the shapes don't agree.
171+
///
172+
/// ## Example
173+
///
174+
/// ```
175+
/// use ndarray::Array;
176+
///
177+
/// // Usage example of move_into in safe code
178+
/// let mut a = Array::zeros((10, 10));
179+
/// let b = Array::from_iter(0..100).into_shape((10, 10)).unwrap();
180+
/// // make an MaybeUninit view so that we can *overwrite* into it.
181+
/// b.move_into_overwrite(&mut a);
182+
/// ```
183+
pub fn move_into_overwrite<'a, AM>(self, new_array: AM)
184+
where
185+
AM: Into<ArrayViewMut<'a, A, D>>,
186+
A: 'a,
187+
{
188+
// Remove generic parameter P and call the implementation
189+
// safe because: no uninit elements are written into the array view, only initialized
190+
unsafe {
191+
self.move_into_impl(new_array.into().into_maybe_uninit())
192+
}
193+
}
194+
159195
/// Move all elements from self into `new_array`, which must be of the same shape but
160196
/// can have a different memory layout. The destination is overwritten completely.
161197
///
@@ -168,7 +204,21 @@ impl<A, D> Array<A, D>
168204
/// drop of any such element, other elements may be leaked.
169205
///
170206
/// ***Panics*** if the shapes don't agree.
171-
pub fn move_into<'a, AM>(self, new_array: AM)
207+
///
208+
/// ## Example
209+
///
210+
/// ```
211+
/// use ndarray::Array;
212+
///
213+
/// let mut a = Array::uninit((10, 10));
214+
/// let b = Array::from_iter(0..100).into_shape((10, 10)).unwrap();
215+
/// b.move_inot_uninit(&mut a);
216+
/// unsafe {
217+
/// // we can now promise we have fully initialized `a`.
218+
/// let a = a.assume_init();
219+
/// }
220+
/// ```
221+
pub fn move_into_uninit<'a, AM>(self, new_array: AM)
172222
where
173223
AM: Into<ArrayViewMut<'a, MaybeUninit<A>, D>>,
174224
A: 'a,
@@ -271,7 +321,7 @@ impl<A, D> Array<A, D>
271321
// dummy array -> self.
272322
// old_self elements are moved -> new_array.
273323
let old_self = std::mem::replace(self, Self::empty());
274-
old_self.move_into(new_array.view_mut());
324+
old_self.move_into_uninit(new_array.view_mut());
275325

276326
// new_array -> self.
277327
unsafe {

src/impl_views/conversions.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
// except according to those terms.
88

99
use alloc::slice;
10+
use std::mem::MaybeUninit;
1011

1112
use crate::imp_prelude::*;
1213

@@ -133,6 +134,27 @@ where
133134
self.into_raw_view_mut().cast::<MathCell<A>>().deref_into_view()
134135
}
135136
}
137+
138+
/// Return the array view as a view of `MaybeUninit<A>` elements
139+
///
140+
/// This conversion leaves the elements as they were (presumably initialized), but
141+
/// they are represented with the `MaybeUninit<A>` type. Effectively this means that
142+
/// the elements can be overwritten without dropping the old element in its place.
143+
/// (In some situations this is not what you want, while for `Copy` elements it makes
144+
/// no difference at all.)
145+
///
146+
/// # Safety
147+
///
148+
/// This method allows writing uninitialized data into the view, which could leave any
149+
/// original array that we borrow from in an inconsistent state. This is not allowed
150+
/// when using the resulting array view.
151+
pub(crate) unsafe fn into_maybe_uninit(self) -> ArrayViewMut<'a, MaybeUninit<A>, D> {
152+
// Safe because: A and MaybeUninit<A> have the same representation;
153+
// and we can go from initialized to (maybe) not unconditionally in terms of
154+
// representation. However, the user must be careful to not write uninit elements
155+
// through the view.
156+
self.into_raw_view_mut().cast::<MaybeUninit<A>>().deref_into_view_mut()
157+
}
136158
}
137159

138160
/// Private array view methods

0 commit comments

Comments
 (0)