Skip to content

Commit bb55063

Browse files
committed
Tidy up maybe_uninit_write_slice API
- Move methods to extensions Signed-off-by: Alex Saveau <[email protected]>
1 parent 8be3ce9 commit bb55063

File tree

5 files changed

+155
-161
lines changed

5 files changed

+155
-161
lines changed

library/core/src/mem/maybe_uninit.rs

+143-149
Original file line numberDiff line numberDiff line change
@@ -1014,154 +1014,6 @@ impl<T> MaybeUninit<T> {
10141014
this.as_mut_ptr() as *mut T
10151015
}
10161016

1017-
/// Copies the elements from `src` to `this`, returning a mutable reference to the now initialized contents of `this`.
1018-
///
1019-
/// If `T` does not implement `Copy`, use [`write_slice_cloned`]
1020-
///
1021-
/// This is similar to [`slice::copy_from_slice`].
1022-
///
1023-
/// # Panics
1024-
///
1025-
/// This function will panic if the two slices have different lengths.
1026-
///
1027-
/// # Examples
1028-
///
1029-
/// ```
1030-
/// #![feature(maybe_uninit_write_slice)]
1031-
/// use std::mem::MaybeUninit;
1032-
///
1033-
/// let mut dst = [MaybeUninit::uninit(); 32];
1034-
/// let src = [0; 32];
1035-
///
1036-
/// let init = MaybeUninit::write_slice(&mut dst, &src);
1037-
///
1038-
/// assert_eq!(init, src);
1039-
/// ```
1040-
///
1041-
/// ```
1042-
/// #![feature(maybe_uninit_write_slice)]
1043-
/// use std::mem::MaybeUninit;
1044-
///
1045-
/// let mut vec = Vec::with_capacity(32);
1046-
/// let src = [0; 16];
1047-
///
1048-
/// MaybeUninit::write_slice(&mut vec.spare_capacity_mut()[..src.len()], &src);
1049-
///
1050-
/// // SAFETY: we have just copied all the elements of len into the spare capacity
1051-
/// // the first src.len() elements of the vec are valid now.
1052-
/// unsafe {
1053-
/// vec.set_len(src.len());
1054-
/// }
1055-
///
1056-
/// assert_eq!(vec, src);
1057-
/// ```
1058-
///
1059-
/// [`write_slice_cloned`]: MaybeUninit::write_slice_cloned
1060-
#[unstable(feature = "maybe_uninit_write_slice", issue = "79995")]
1061-
pub fn write_slice<'a>(this: &'a mut [MaybeUninit<T>], src: &[T]) -> &'a mut [T]
1062-
where
1063-
T: Copy,
1064-
{
1065-
// SAFETY: &[T] and &[MaybeUninit<T>] have the same layout
1066-
let uninit_src: &[MaybeUninit<T>] = unsafe { super::transmute(src) };
1067-
1068-
this.copy_from_slice(uninit_src);
1069-
1070-
// SAFETY: Valid elements have just been copied into `this` so it is initialized
1071-
unsafe { MaybeUninit::slice_assume_init_mut(this) }
1072-
}
1073-
1074-
/// Clones the elements from `src` to `this`, returning a mutable reference to the now initialized contents of `this`.
1075-
/// Any already initialized elements will not be dropped.
1076-
///
1077-
/// If `T` implements `Copy`, use [`write_slice`]
1078-
///
1079-
/// This is similar to [`slice::clone_from_slice`] but does not drop existing elements.
1080-
///
1081-
/// # Panics
1082-
///
1083-
/// This function will panic if the two slices have different lengths, or if the implementation of `Clone` panics.
1084-
///
1085-
/// If there is a panic, the already cloned elements will be dropped.
1086-
///
1087-
/// # Examples
1088-
///
1089-
/// ```
1090-
/// #![feature(maybe_uninit_write_slice)]
1091-
/// use std::mem::MaybeUninit;
1092-
///
1093-
/// let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()];
1094-
/// let src = ["wibbly".to_string(), "wobbly".to_string(), "timey".to_string(), "wimey".to_string(), "stuff".to_string()];
1095-
///
1096-
/// let init = MaybeUninit::write_slice_cloned(&mut dst, &src);
1097-
///
1098-
/// assert_eq!(init, src);
1099-
/// ```
1100-
///
1101-
/// ```
1102-
/// #![feature(maybe_uninit_write_slice)]
1103-
/// use std::mem::MaybeUninit;
1104-
///
1105-
/// let mut vec = Vec::with_capacity(32);
1106-
/// let src = ["rust", "is", "a", "pretty", "cool", "language"];
1107-
///
1108-
/// MaybeUninit::write_slice_cloned(&mut vec.spare_capacity_mut()[..src.len()], &src);
1109-
///
1110-
/// // SAFETY: we have just cloned all the elements of len into the spare capacity
1111-
/// // the first src.len() elements of the vec are valid now.
1112-
/// unsafe {
1113-
/// vec.set_len(src.len());
1114-
/// }
1115-
///
1116-
/// assert_eq!(vec, src);
1117-
/// ```
1118-
///
1119-
/// [`write_slice`]: MaybeUninit::write_slice
1120-
#[unstable(feature = "maybe_uninit_write_slice", issue = "79995")]
1121-
pub fn write_slice_cloned<'a>(this: &'a mut [MaybeUninit<T>], src: &[T]) -> &'a mut [T]
1122-
where
1123-
T: Clone,
1124-
{
1125-
// unlike copy_from_slice this does not call clone_from_slice on the slice
1126-
// this is because `MaybeUninit<T: Clone>` does not implement Clone.
1127-
1128-
struct Guard<'a, T> {
1129-
slice: &'a mut [MaybeUninit<T>],
1130-
initialized: usize,
1131-
}
1132-
1133-
impl<'a, T> Drop for Guard<'a, T> {
1134-
fn drop(&mut self) {
1135-
let initialized_part = &mut self.slice[..self.initialized];
1136-
// SAFETY: this raw slice will contain only initialized objects
1137-
// that's why, it is allowed to drop it.
1138-
unsafe {
1139-
crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part));
1140-
}
1141-
}
1142-
}
1143-
1144-
assert_eq!(this.len(), src.len(), "destination and source slices have different lengths");
1145-
// NOTE: We need to explicitly slice them to the same length
1146-
// for bounds checking to be elided, and the optimizer will
1147-
// generate memcpy for simple cases (for example T = u8).
1148-
let len = this.len();
1149-
let src = &src[..len];
1150-
1151-
// guard is needed b/c panic might happen during a clone
1152-
let mut guard = Guard { slice: this, initialized: 0 };
1153-
1154-
for i in 0..len {
1155-
guard.slice[i].write(src[i].clone());
1156-
guard.initialized += 1;
1157-
}
1158-
1159-
super::forget(guard);
1160-
1161-
// SAFETY: Valid elements have just been written into `this` so it is initialized
1162-
unsafe { MaybeUninit::slice_assume_init_mut(this) }
1163-
}
1164-
11651017
/// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes.
11661018
///
11671019
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
@@ -1265,7 +1117,7 @@ impl<T> MaybeUninit<T> {
12651117
///
12661118
/// let mut uninit = [MaybeUninit::<u16>::uninit(), MaybeUninit::<u16>::uninit()];
12671119
/// let uninit_bytes = MaybeUninit::slice_as_bytes_mut(&mut uninit);
1268-
/// MaybeUninit::write_slice(uninit_bytes, &[0x12, 0x34, 0x56, 0x78]);
1120+
/// uninit_bytes.write_slice(&[0x12, 0x34, 0x56, 0x78]);
12691121
/// let vals = unsafe { MaybeUninit::slice_assume_init_ref(&uninit) };
12701122
/// if cfg!(target_endian = "little") {
12711123
/// assert_eq!(vals, &[0x3412u16, 0x7856u16]);
@@ -1321,3 +1173,145 @@ impl<T, const N: usize> [MaybeUninit<T>; N] {
13211173
unsafe { super::transmute_copy(&ManuallyDrop::new(self)) }
13221174
}
13231175
}
1176+
1177+
impl<T> [MaybeUninit<T>] {
1178+
/// Copies the elements from `src` to `this`, returning a mutable reference to the now initialized contents of `this`.
1179+
///
1180+
/// If `T` does not implement `Copy`, use [`write_slice_cloned`](slice::write_slice_cloned)
1181+
///
1182+
/// This is similar to [`slice::copy_from_slice`].
1183+
///
1184+
/// # Panics
1185+
///
1186+
/// This function will panic if the two slices have different lengths.
1187+
///
1188+
/// # Examples
1189+
///
1190+
/// ```
1191+
/// #![feature(maybe_uninit_write_slice)]
1192+
/// use std::mem::MaybeUninit;
1193+
///
1194+
/// let mut dst = [MaybeUninit::uninit(); 32];
1195+
/// let src = [0; 32];
1196+
///
1197+
/// let init = dst.write_slice(&src);
1198+
///
1199+
/// assert_eq!(init, src);
1200+
/// ```
1201+
///
1202+
/// ```
1203+
/// #![feature(maybe_uninit_write_slice)]
1204+
/// let mut vec = Vec::with_capacity(32);
1205+
/// let src = [0; 16];
1206+
///
1207+
/// vec.spare_capacity_mut()[..src.len()].write_slice(&src);
1208+
///
1209+
/// // SAFETY: we have just copied all the elements of len into the spare capacity
1210+
/// // the first src.len() elements of the vec are valid now.
1211+
/// unsafe {
1212+
/// vec.set_len(src.len());
1213+
/// }
1214+
///
1215+
/// assert_eq!(vec, src);
1216+
/// ```
1217+
#[unstable(feature = "maybe_uninit_write_slice", issue = "79995")]
1218+
pub fn write_slice(&mut self, src: &[T]) -> &mut [T]
1219+
where
1220+
T: Copy,
1221+
{
1222+
// SAFETY: &[T] and &[MaybeUninit<T>] have the same layout
1223+
let uninit_src: &[MaybeUninit<T>] = unsafe { super::transmute(src) };
1224+
1225+
self.copy_from_slice(uninit_src);
1226+
1227+
// SAFETY: Valid elements have just been copied into `this` so it is initialized
1228+
unsafe { MaybeUninit::slice_assume_init_mut(self) }
1229+
}
1230+
1231+
/// Clones the elements from `src` to `this`, returning a mutable reference to the now initialized contents of `this`.
1232+
/// Any already initialized elements will not be dropped.
1233+
///
1234+
/// If `T` implements `Copy`, use [`write_slice`](slice::write_slice)
1235+
///
1236+
/// This is similar to [`slice::clone_from_slice`] but does not drop existing elements.
1237+
///
1238+
/// # Panics
1239+
///
1240+
/// This function will panic if the two slices have different lengths, or if the implementation of `Clone` panics.
1241+
///
1242+
/// If there is a panic, the already cloned elements will be dropped.
1243+
///
1244+
/// # Examples
1245+
///
1246+
/// ```
1247+
/// #![feature(maybe_uninit_write_slice)]
1248+
/// use std::mem::MaybeUninit;
1249+
///
1250+
/// let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()];
1251+
/// let src = ["wibbly".to_string(), "wobbly".to_string(), "timey".to_string(), "wimey".to_string(), "stuff".to_string()];
1252+
///
1253+
/// let init = dst.write_slice_cloned(&src);
1254+
///
1255+
/// assert_eq!(init, src);
1256+
/// ```
1257+
///
1258+
/// ```
1259+
/// #![feature(maybe_uninit_write_slice)]
1260+
/// let mut vec = Vec::with_capacity(32);
1261+
/// let src = ["rust", "is", "a", "pretty", "cool", "language"];
1262+
///
1263+
/// vec.spare_capacity_mut()[..src.len()].write_slice_cloned(&src);
1264+
///
1265+
/// // SAFETY: we have just cloned all the elements of len into the spare capacity
1266+
/// // the first src.len() elements of the vec are valid now.
1267+
/// unsafe {
1268+
/// vec.set_len(src.len());
1269+
/// }
1270+
///
1271+
/// assert_eq!(vec, src);
1272+
/// ```
1273+
#[unstable(feature = "maybe_uninit_write_slice", issue = "79995")]
1274+
pub fn write_slice_cloned(&mut self, src: &[T]) -> &mut [T]
1275+
where
1276+
T: Clone,
1277+
{
1278+
// unlike copy_from_slice this does not call clone_from_slice on the slice
1279+
// this is because `MaybeUninit<T: Clone>` does not implement Clone.
1280+
1281+
struct Guard<'a, T> {
1282+
slice: &'a mut [MaybeUninit<T>],
1283+
initialized: usize,
1284+
}
1285+
1286+
impl<'a, T> Drop for Guard<'a, T> {
1287+
fn drop(&mut self) {
1288+
let initialized_part = &mut self.slice[..self.initialized];
1289+
// SAFETY: this raw slice will contain only initialized objects
1290+
// that's why, it is allowed to drop it.
1291+
unsafe {
1292+
ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part));
1293+
}
1294+
}
1295+
}
1296+
1297+
assert_eq!(self.len(), src.len(), "destination and source slices have different lengths");
1298+
// NOTE: We need to explicitly slice them to the same length
1299+
// for bounds checking to be elided, and the optimizer will
1300+
// generate memcpy for simple cases (for example T = u8).
1301+
let len = self.len();
1302+
let src = &src[..len];
1303+
1304+
// guard is needed b/c panic might happen during a clone
1305+
let mut guard = Guard { slice: self, initialized: 0 };
1306+
1307+
for i in 0..len {
1308+
guard.slice[i].write(src[i].clone());
1309+
guard.initialized += 1;
1310+
}
1311+
1312+
super::forget(guard);
1313+
1314+
// SAFETY: Valid elements have just been written into `self` so it is initialized
1315+
unsafe { MaybeUninit::slice_assume_init_mut(self) }
1316+
}
1317+
}

library/core/tests/mem.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ fn uninit_write_slice() {
182182
let mut dst = [MaybeUninit::new(255); 64];
183183
let src = [0; 64];
184184

185-
assert_eq!(MaybeUninit::write_slice(&mut dst, &src), &src);
185+
assert_eq!(dst.write_slice(&src), &src);
186186
}
187187

188188
#[test]
@@ -191,7 +191,7 @@ fn uninit_write_slice_panic_lt() {
191191
let mut dst = [MaybeUninit::uninit(); 64];
192192
let src = [0; 32];
193193

194-
MaybeUninit::write_slice(&mut dst, &src);
194+
dst.write_slice(&src);
195195
}
196196

197197
#[test]
@@ -200,15 +200,15 @@ fn uninit_write_slice_panic_gt() {
200200
let mut dst = [MaybeUninit::uninit(); 64];
201201
let src = [0; 128];
202202

203-
MaybeUninit::write_slice(&mut dst, &src);
203+
dst.write_slice(&src);
204204
}
205205

206206
#[test]
207-
fn uninit_clone_from_slice() {
207+
fn uninit_write_slice_cloned() {
208208
let mut dst = [MaybeUninit::new(255); 64];
209209
let src = [0; 64];
210210

211-
assert_eq!(MaybeUninit::write_slice_cloned(&mut dst, &src), &src);
211+
assert_eq!(dst.write_slice_cloned(&src), &src);
212212
}
213213

214214
#[test]
@@ -217,7 +217,7 @@ fn uninit_write_slice_cloned_panic_lt() {
217217
let mut dst = [MaybeUninit::uninit(); 64];
218218
let src = [0; 32];
219219

220-
MaybeUninit::write_slice_cloned(&mut dst, &src);
220+
dst.write_slice_cloned(&src);
221221
}
222222

223223
#[test]
@@ -226,7 +226,7 @@ fn uninit_write_slice_cloned_panic_gt() {
226226
let mut dst = [MaybeUninit::uninit(); 64];
227227
let src = [0; 128];
228228

229-
MaybeUninit::write_slice_cloned(&mut dst, &src);
229+
dst.write_slice_cloned(&src);
230230
}
231231

232232
#[test]
@@ -267,7 +267,7 @@ fn uninit_write_slice_cloned_mid_panic() {
267267
];
268268

269269
let err = panic::catch_unwind(panic::AssertUnwindSafe(|| {
270-
MaybeUninit::write_slice_cloned(&mut dst, &src);
270+
dst.write_slice_cloned(&src);
271271
}));
272272

273273
drop(src);
@@ -299,7 +299,7 @@ fn uninit_write_slice_cloned_no_drop() {
299299
let mut dst = [MaybeUninit::uninit()];
300300
let src = [Bomb];
301301

302-
MaybeUninit::write_slice_cloned(&mut dst, &src);
302+
dst.write_slice_cloned(&src);
303303

304304
forget(src);
305305
}

library/proc_macro/src/bridge/arena.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ impl Arena {
104104

105105
pub(crate) fn alloc_str<'a>(&'a self, string: &str) -> &'a mut str {
106106
let alloc = self.alloc_raw(string.len());
107-
let bytes = MaybeUninit::write_slice(alloc, string.as_bytes());
107+
let bytes = alloc.write_slice(string.as_bytes());
108108

109109
// SAFETY: we convert from `&str` to `&[u8]`, clone it into the arena,
110110
// and immediately convert the clone back to `&str`.

0 commit comments

Comments
 (0)