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}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy