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}