3636
3737#![ stable( feature = "rust1" , since = "1.0.0" ) ]
3838
39- use crate :: mem:: { self , MaybeUninit } ;
40- use crate :: ptr;
39+ mod uninit;
4140
4241/// A common trait for the ability to explicitly duplicate an object.
4342///
@@ -248,7 +247,7 @@ pub unsafe trait CloneToUninit {
248247 /// * `dst` must be properly aligned.
249248 /// * `dst` must have the same [pointer metadata] (slice length or `dyn` vtable) as `self`.
250249 ///
251- /// [valid]: ptr#safety
250+ /// [valid]: crate:: ptr#safety
252251 /// [pointer metadata]: crate::ptr::metadata()
253252 ///
254253 /// # Panics
@@ -272,124 +271,42 @@ pub unsafe trait CloneToUninit {
272271
273272#[ unstable( feature = "clone_to_uninit" , issue = "126799" ) ]
274273unsafe impl < T : Clone > CloneToUninit for T {
275- default unsafe fn clone_to_uninit ( & self , dst : * mut Self ) {
276- // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
277- // ptr::write().
278- unsafe {
279- // We hope the optimizer will figure out to create the cloned value in-place,
280- // skipping ever storing it on the stack and the copy to the destination.
281- ptr:: write ( dst, self . clone ( ) ) ;
282- }
283- }
284- }
285-
286- // Specialized implementation for types that are [`Copy`], not just [`Clone`],
287- // and can therefore be copied bitwise.
288- #[ unstable( feature = "clone_to_uninit" , issue = "126799" ) ]
289- unsafe impl < T : Copy > CloneToUninit for T {
274+ #[ inline]
290275 unsafe fn clone_to_uninit ( & self , dst : * mut Self ) {
291- // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
292- // ptr::copy_nonoverlapping().
293- unsafe {
294- ptr:: copy_nonoverlapping ( self , dst, 1 ) ;
295- }
276+ // SAFETY: we're calling a specialization with the same contract
277+ unsafe { <T as self :: uninit:: CopySpec >:: clone_one ( self , dst) }
296278 }
297279}
298280
299281#[ unstable( feature = "clone_to_uninit" , issue = "126799" ) ]
300282unsafe impl < T : Clone > CloneToUninit for [ T ] {
283+ #[ inline]
301284 #[ cfg_attr( debug_assertions, track_caller) ]
302- default unsafe fn clone_to_uninit ( & self , dst : * mut Self ) {
303- let len = self . len ( ) ;
304- // This is the most likely mistake to make, so check it as a debug assertion.
305- debug_assert_eq ! (
306- len,
307- dst. len( ) ,
308- "clone_to_uninit() source and destination must have equal lengths" ,
309- ) ;
310-
311- // SAFETY: The produced `&mut` is valid because:
312- // * The caller is obligated to provide a pointer which is valid for writes.
313- // * All bytes pointed to are in MaybeUninit, so we don't care about the memory's
314- // initialization status.
315- let uninit_ref = unsafe { & mut * ( dst as * mut [ MaybeUninit < T > ] ) } ;
316-
317- // Copy the elements
318- let mut initializing = InitializingSlice :: from_fully_uninit ( uninit_ref) ;
319- for element_ref in self . iter ( ) {
320- // If the clone() panics, `initializing` will take care of the cleanup.
321- initializing. push ( element_ref. clone ( ) ) ;
322- }
323- // If we reach here, then the entire slice is initialized, and we've satisfied our
324- // responsibilities to the caller. Disarm the cleanup guard by forgetting it.
325- mem:: forget ( initializing) ;
285+ unsafe fn clone_to_uninit ( & self , dst : * mut Self ) {
286+ // SAFETY: we're calling a specialization with the same contract
287+ unsafe { <T as self :: uninit:: CopySpec >:: clone_slice ( self , dst) }
326288 }
327289}
328290
329291#[ unstable( feature = "clone_to_uninit" , issue = "126799" ) ]
330- unsafe impl < T : Copy > CloneToUninit for [ T ] {
292+ unsafe impl CloneToUninit for str {
293+ #[ inline]
331294 #[ cfg_attr( debug_assertions, track_caller) ]
332295 unsafe fn clone_to_uninit ( & self , dst : * mut Self ) {
333- let len = self . len ( ) ;
334- // This is the most likely mistake to make, so check it as a debug assertion.
335- debug_assert_eq ! (
336- len,
337- dst. len( ) ,
338- "clone_to_uninit() source and destination must have equal lengths" ,
339- ) ;
340-
341- // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
342- // ptr::copy_nonoverlapping().
343- unsafe {
344- ptr:: copy_nonoverlapping ( self . as_ptr ( ) , dst. as_mut_ptr ( ) , len) ;
345- }
296+ // SAFETY: str is just a [u8] with UTF-8 invariant
297+ unsafe { self . as_bytes ( ) . clone_to_uninit ( dst as * mut [ u8 ] ) }
346298 }
347299}
348300
349- /// Ownership of a collection of values stored in a non-owned `[MaybeUninit<T>]`, some of which
350- /// are not yet initialized. This is sort of like a `Vec` that doesn't own its allocation.
351- /// Its responsibility is to provide cleanup on unwind by dropping the values that *are*
352- /// initialized, unless disarmed by forgetting.
353- ///
354- /// This is a helper for `impl<T: Clone> CloneToUninit for [T]`.
355- struct InitializingSlice < ' a , T > {
356- data : & ' a mut [ MaybeUninit < T > ] ,
357- /// Number of elements of `*self.data` that are initialized.
358- initialized_len : usize ,
359- }
360-
361- impl < ' a , T > InitializingSlice < ' a , T > {
362- #[ inline]
363- fn from_fully_uninit ( data : & ' a mut [ MaybeUninit < T > ] ) -> Self {
364- Self { data, initialized_len : 0 }
365- }
366-
367- /// Push a value onto the end of the initialized part of the slice.
368- ///
369- /// # Panics
370- ///
371- /// Panics if the slice is already fully initialized.
372- #[ inline]
373- fn push ( & mut self , value : T ) {
374- MaybeUninit :: write ( & mut self . data [ self . initialized_len ] , value) ;
375- self . initialized_len += 1 ;
376- }
377- }
378-
379- impl < ' a , T > Drop for InitializingSlice < ' a , T > {
380- #[ cold] // will only be invoked on unwind
381- fn drop ( & mut self ) {
382- let initialized_slice = ptr:: slice_from_raw_parts_mut (
383- MaybeUninit :: slice_as_mut_ptr ( self . data ) ,
384- self . initialized_len ,
385- ) ;
386- // SAFETY:
387- // * the pointer is valid because it was made from a mutable reference
388- // * `initialized_len` counts the initialized elements as an invariant of this type,
389- // so each of the pointed-to elements is initialized and may be dropped.
390- unsafe {
391- ptr:: drop_in_place :: < [ T ] > ( initialized_slice) ;
392- }
301+ #[ unstable( feature = "clone_to_uninit" , issue = "126799" ) ]
302+ unsafe impl CloneToUninit for crate :: ffi:: CStr {
303+ #[ cfg_attr( debug_assertions, track_caller) ]
304+ unsafe fn clone_to_uninit ( & self , dst : * mut Self ) {
305+ // SAFETY: For now, CStr is just a #[repr(trasnsparent)] [c_char] with some invariants.
306+ // And we can cast [c_char] to [u8] on all supported platforms (see: to_bytes_with_nul).
307+ // The pointer metadata properly preserves the length (NUL included).
308+ // See: `cstr_metadata_is_length_with_nul` in tests.
309+ unsafe { self . to_bytes_with_nul ( ) . clone_to_uninit ( dst as * mut [ u8 ] ) }
393310 }
394311}
395312
0 commit comments