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