| 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 | |