1use super::TrivialClone;
2use crate::mem::{self, MaybeUninit};
3use crate::ptr;
45/// Private specialization trait used by CloneToUninit, as per
6/// [the dev guide](https://std-dev-guide.rust-lang.org/policy/specialization.html).
7pub(super) unsafe trait CopySpec: Clone {
8unsafe fn clone_one(src: &Self, dst: *mut Self);
9unsafe fn clone_slice(src: &[Self], dst: *mut [Self]);
10}
1112unsafe impl<T: Clone> CopySpecfor T {
13#[inline]
14default unsafe fn clone_one(src: &Self, dst: *mut Self) {
15// SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
16 // ptr::write().
17unsafe {
18// We hope the optimizer will figure out to create the cloned value in-place,
19 // skipping ever storing it on the stack and the copy to the destination.
20ptr::write(dst, src.clone());
21 }
22 }
2324#[inline]
25 #[cfg_attr(debug_assertions, track_caller)]
26default unsafe fn clone_slice(src: &[Self], dst: *mut [Self]) {
27let len = src.len();
28// This is the most likely mistake to make, so check it as a debug assertion.
29if true {
match (&len, &dst.len()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = crate::panicking::AssertKind::Eq;
crate::panicking::assert_failed(kind, &*left_val, &*right_val,
crate::option::Option::Some(format_args!("clone_to_uninit() source and destination must have equal lengths")));
}
}
};
};debug_assert_eq!(
30 len,
31 dst.len(),
32"clone_to_uninit() source and destination must have equal lengths",
33 );
3435// SAFETY: The produced `&mut` is valid because:
36 // * The caller is obligated to provide a pointer which is valid for writes.
37 // * All bytes pointed to are in MaybeUninit, so we don't care about the memory's
38 // initialization status.
39let uninit_ref = unsafe { &mut *(dstas *mut [MaybeUninit<T>]) };
4041// Copy the elements
42let mut initializing = InitializingSlice::from_fully_uninit(uninit_ref);
43for element_ref in src {
44// If the clone() panics, `initializing` will take care of the cleanup.
45initializing.push(element_ref.clone());
46 }
47// If we reach here, then the entire slice is initialized, and we've satisfied our
48 // responsibilities to the caller. Disarm the cleanup guard by forgetting it.
49mem::forget(initializing);
50 }
51}
5253// Specialized implementation for types that are [`TrivialClone`], not just [`Clone`],
54// and can therefore be copied bitwise.
55unsafe impl<T: TrivialClone> CopySpecfor T {
56#[inline]
57unsafe fn clone_one(src: &Self, dst: *mut Self) {
58// SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
59 // ptr::copy_nonoverlapping().
60unsafe {
61 ptr::copy_nonoverlapping(src, dst, 1);
62 }
63 }
6465#[inline]
66 #[cfg_attr(debug_assertions, track_caller)]
67unsafe fn clone_slice(src: &[Self], dst: *mut [Self]) {
68let len = src.len();
69// This is the most likely mistake to make, so check it as a debug assertion.
70if true {
match (&len, &dst.len()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = crate::panicking::AssertKind::Eq;
crate::panicking::assert_failed(kind, &*left_val, &*right_val,
crate::option::Option::Some(format_args!("clone_to_uninit() source and destination must have equal lengths")));
}
}
};
};debug_assert_eq!(
71 len,
72 dst.len(),
73"clone_to_uninit() source and destination must have equal lengths",
74 );
7576// SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
77 // ptr::copy_nonoverlapping().
78unsafe {
79 ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), len);
80 }
81 }
82}
8384/// Ownership of a collection of values stored in a non-owned `[MaybeUninit<T>]`, some of which
85/// are not yet initialized. This is sort of like a `Vec` that doesn't own its allocation.
86/// Its responsibility is to provide cleanup on unwind by dropping the values that *are*
87/// initialized, unless disarmed by forgetting.
88///
89/// This is a helper for `impl<T: Clone> CloneToUninit for [T]`.
90struct InitializingSlice<'a, T> {
91 data: &'a mut [MaybeUninit<T>],
92/// Number of elements of `*self.data` that are initialized.
93initialized_len: usize,
94}
9596impl<'a, T> InitializingSlice<'a, T> {
97#[inline]
98fn from_fully_uninit(data: &'a mut [MaybeUninit<T>]) -> Self {
99Self { data, initialized_len: 0 }
100 }
101102/// Push a value onto the end of the initialized part of the slice.
103 ///
104 /// # Panics
105 ///
106 /// Panics if the slice is already fully initialized.
107#[inline]
108fn push(&mut self, value: T) {
109MaybeUninit::write(&mut self.data[self.initialized_len], value);
110self.initialized_len += 1;
111 }
112}
113114impl<'a, T> Dropfor InitializingSlice<'a, T> {
115#[cold] // will only be invoked on unwind
116fn drop(&mut self) {
117// SAFETY:
118 // * the pointer is valid because it was made from a mutable reference
119 // * `initialized_len` counts the initialized elements as an invariant of this type,
120 // so each of the pointed-to elements is initialized and may be dropped.
121unsafe { self.data[..self.initialized_len].assume_init_drop() };
122 }
123}