core/clone/
uninit.rs

1use super::TrivialClone;
2use crate::mem::{self, MaybeUninit};
3use crate::ptr;
4
5/// 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 {
8    unsafe fn clone_one(src: &Self, dst: *mut Self);
9    unsafe fn clone_slice(src: &[Self], dst: *mut [Self]);
10}
11
12unsafe impl<T: Clone> CopySpec for T {
13    #[inline]
14    default 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().
17        unsafe {
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.
20            ptr::write(dst, src.clone());
21        }
22    }
23
24    #[inline]
25    #[cfg_attr(debug_assertions, track_caller)]
26    default unsafe fn clone_slice(src: &[Self], dst: *mut [Self]) {
27        let len = src.len();
28        // This is the most likely mistake to make, so check it as a debug assertion.
29        debug_assert_eq!(
30            len,
31            dst.len(),
32            "clone_to_uninit() source and destination must have equal lengths",
33        );
34
35        // 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.
39        let uninit_ref = unsafe { &mut *(dst as *mut [MaybeUninit<T>]) };
40
41        // Copy the elements
42        let mut initializing = InitializingSlice::from_fully_uninit(uninit_ref);
43        for element_ref in src {
44            // If the clone() panics, `initializing` will take care of the cleanup.
45            initializing.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.
49        mem::forget(initializing);
50    }
51}
52
53// Specialized implementation for types that are [`TrivialClone`], not just [`Clone`],
54// and can therefore be copied bitwise.
55unsafe impl<T: TrivialClone> CopySpec for T {
56    #[inline]
57    unsafe 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().
60        unsafe {
61            ptr::copy_nonoverlapping(src, dst, 1);
62        }
63    }
64
65    #[inline]
66    #[cfg_attr(debug_assertions, track_caller)]
67    unsafe fn clone_slice(src: &[Self], dst: *mut [Self]) {
68        let len = src.len();
69        // This is the most likely mistake to make, so check it as a debug assertion.
70        debug_assert_eq!(
71            len,
72            dst.len(),
73            "clone_to_uninit() source and destination must have equal lengths",
74        );
75
76        // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
77        // ptr::copy_nonoverlapping().
78        unsafe {
79            ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), len);
80        }
81    }
82}
83
84/// 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.
93    initialized_len: usize,
94}
95
96impl<'a, T> InitializingSlice<'a, T> {
97    #[inline]
98    fn from_fully_uninit(data: &'a mut [MaybeUninit<T>]) -> Self {
99        Self { data, initialized_len: 0 }
100    }
101
102    /// 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]
108    fn push(&mut self, value: T) {
109        MaybeUninit::write(&mut self.data[self.initialized_len], value);
110        self.initialized_len += 1;
111    }
112}
113
114impl<'a, T> Drop for InitializingSlice<'a, T> {
115    #[cold] // will only be invoked on unwind
116    fn drop(&mut self) {
117        let initialized_slice = ptr::slice_from_raw_parts_mut(
118            MaybeUninit::slice_as_mut_ptr(self.data),
119            self.initialized_len,
120        );
121        // SAFETY:
122        // * the pointer is valid because it was made from a mutable reference
123        // * `initialized_len` counts the initialized elements as an invariant of this type,
124        //   so each of the pointed-to elements is initialized and may be dropped.
125        unsafe {
126            ptr::drop_in_place::<[T]>(initialized_slice);
127        }
128    }
129}