1 | use crate::mem::{self, MaybeUninit}; |
2 | use 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). |
6 | pub(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 | |
11 | unsafe 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. |
54 | unsafe 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]`. |
89 | struct 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 | |
95 | impl<'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], val:value); |
109 | self.initialized_len += 1; |
110 | } |
111 | } |
112 | |
113 | impl<'a, T> Drop for InitializingSlice<'a, T> { |
114 | #[cold ] // will only be invoked on unwind |
115 | fn drop(&mut self) { |
116 | let initialized_slice: *mut [T] = ptr::slice_from_raw_parts_mut( |
117 | data: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]>(to_drop:initialized_slice); |
126 | } |
127 | } |
128 | } |
129 | |