Skip to content

Commit 76cba19

Browse files
committed
Add CloneToUninit::clone_to_init
This is necessary to properly support `Clone::clone_from`.
1 parent fd15c13 commit 76cba19

File tree

6 files changed

+92
-1
lines changed

6 files changed

+92
-1
lines changed

library/core/src/clone.rs

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,16 @@ pub struct AssertParamIsCopy<T: Copy + PointeeSized> {
439439
/// // All fields of the struct have been initialized; therefore, the struct is initialized,
440440
/// // and we have satisfied our `unsafe impl CloneToUninit` obligations.
441441
/// }
442+
///
443+
/// unsafe fn clone_to_init(&self, dest: *mut u8) {
444+
/// // SAFETY: The caller must provide a `dest` such that these field offsets are valid
445+
/// // to write to.
446+
/// unsafe {
447+
/// let offset_of_contents = (&raw const self.contents).byte_offset_from_unsigned(self);
448+
/// self.contents.clone_to_init(dest.add(offset_of_contents));
449+
/// self.label.clone_to_init(dest.add(offset_of!(Self, label)));
450+
/// }
451+
/// }
442452
/// }
443453
///
444454
/// fn main() {
@@ -509,6 +519,15 @@ pub unsafe trait CloneToUninit {
509519
/// cloned, and the second of the three calls to `Foo::clone()` unwinds, then the first `Foo`
510520
/// cloned should be dropped.)
511521
unsafe fn clone_to_uninit(&self, dest: *mut u8);
522+
523+
/// Clones `self` to `dest`
524+
///
525+
/// This is similar to `Clone::clone_from`, but unsafe and dyn-compatible.
526+
///
527+
/// # Safety
528+
///
529+
/// `dest` must be a valid pointer to a valid value of the same concrete type than `self`.
530+
unsafe fn clone_to_init(&self, dest: *mut u8);
512531
}
513532

514533
#[unstable(feature = "clone_to_uninit", issue = "126799")]
@@ -518,6 +537,13 @@ unsafe impl<T: Clone> CloneToUninit for T {
518537
// SAFETY: we're calling a specialization with the same contract
519538
unsafe { <T as self::uninit::CopySpec>::clone_one(self, dest.cast::<T>()) }
520539
}
540+
541+
#[inline]
542+
unsafe fn clone_to_init(&self, dest: *mut u8) {
543+
// SAFETY: by contract, `dest` is a valid pointer to `T`
544+
let dest = unsafe { dest.cast::<T>().as_mut_unchecked() };
545+
dest.clone_from(self);
546+
}
521547
}
522548

523549
#[unstable(feature = "clone_to_uninit", issue = "126799")]
@@ -529,6 +555,15 @@ unsafe impl<T: Clone> CloneToUninit for [T] {
529555
// SAFETY: we're calling a specialization with the same contract
530556
unsafe { <T as self::uninit::CopySpec>::clone_slice(self, dest) }
531557
}
558+
559+
#[inline]
560+
#[cfg_attr(debug_assertions, track_caller)]
561+
unsafe fn clone_to_init(&self, dest: *mut u8) {
562+
// SAFETY: by contract, `dest` is a valid pointer to a `[T]` with the
563+
// same length as `self`
564+
let dest = unsafe { dest.with_metadata_of(self).as_mut_unchecked() };
565+
dest.clone_from_slice(self);
566+
}
532567
}
533568

534569
#[unstable(feature = "clone_to_uninit", issue = "126799")]
@@ -539,18 +574,33 @@ unsafe impl CloneToUninit for str {
539574
// SAFETY: str is just a [u8] with UTF-8 invariant
540575
unsafe { self.as_bytes().clone_to_uninit(dest) }
541576
}
577+
578+
#[inline]
579+
#[cfg_attr(debug_assertions, track_caller)]
580+
unsafe fn clone_to_init(&self, dest: *mut u8) {
581+
// SAFETY: str is just a [u8] with UTF-8 invariant
582+
unsafe { self.as_bytes().clone_to_init(dest) }
583+
}
542584
}
543585

544586
#[unstable(feature = "clone_to_uninit", issue = "126799")]
545587
unsafe impl CloneToUninit for crate::ffi::CStr {
546588
#[cfg_attr(debug_assertions, track_caller)]
547589
unsafe fn clone_to_uninit(&self, dest: *mut u8) {
548-
// SAFETY: For now, CStr is just a #[repr(trasnsparent)] [c_char] with some invariants.
590+
// SAFETY: For now, CStr is just a #[repr(transparent)] [c_char] with some invariants.
549591
// And we can cast [c_char] to [u8] on all supported platforms (see: to_bytes_with_nul).
550592
// The pointer metadata properly preserves the length (so NUL is also copied).
551593
// See: `cstr_metadata_is_length_with_nul` in tests.
552594
unsafe { self.to_bytes_with_nul().clone_to_uninit(dest) }
553595
}
596+
597+
unsafe fn clone_to_init(&self, dest: *mut u8) {
598+
// SAFETY: For now, CStr is just a #[repr(transparent)] [c_char] with some invariants.
599+
// And we can cast [c_char] to [u8] on all supported platforms (see: to_bytes_with_nul).
600+
// The pointer metadata properly preserves the length (so NUL is also copied).
601+
// See: `cstr_metadata_is_length_with_nul` in tests.
602+
unsafe { self.to_bytes_with_nul().clone_to_init(dest) }
603+
}
554604
}
555605

556606
#[unstable(feature = "bstr", issue = "134915")]
@@ -561,6 +611,12 @@ unsafe impl CloneToUninit for crate::bstr::ByteStr {
561611
// SAFETY: ByteStr is a `#[repr(transparent)]` wrapper around `[u8]`
562612
unsafe { self.as_bytes().clone_to_uninit(dst) }
563613
}
614+
615+
#[inline]
616+
unsafe fn clone_to_init(&self, dst: *mut u8) {
617+
// SAFETY: ByteStr is a `#[repr(transparent)]` wrapper around `[u8]`
618+
unsafe { self.as_bytes().clone_to_uninit(dst) }
619+
}
564620
}
565621

566622
/// Implementations of `Clone` for primitive types.

library/core/src/wtf8.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,4 +594,11 @@ unsafe impl CloneToUninit for Wtf8 {
594594
// SAFETY: we're just a transparent wrapper around [u8]
595595
unsafe { self.bytes.clone_to_uninit(dst) }
596596
}
597+
598+
#[inline]
599+
#[cfg_attr(debug_assertions, track_caller)]
600+
unsafe fn clone_to_init(&self, dst: *mut u8) {
601+
// SAFETY: we're just a transparent wrapper around [u8]
602+
unsafe { self.bytes.clone_to_init(dst) }
603+
}
597604
}

library/std/src/ffi/os_str.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,13 @@ unsafe impl CloneToUninit for OsStr {
13451345
// SAFETY: we're just a transparent wrapper around a platform-specific Slice
13461346
unsafe { self.inner.clone_to_uninit(dst) }
13471347
}
1348+
1349+
#[inline]
1350+
#[cfg_attr(debug_assertions, track_caller)]
1351+
unsafe fn clone_to_init(&self, dst: *mut u8) {
1352+
// SAFETY: we're just a transparent wrapper around a platform-specific Slice
1353+
unsafe { self.inner.clone_to_init(dst) }
1354+
}
13481355
}
13491356

13501357
#[stable(feature = "shared_from_slice2", since = "1.24.0")]

library/std/src/path.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3340,6 +3340,13 @@ unsafe impl CloneToUninit for Path {
33403340
// SAFETY: Path is just a transparent wrapper around OsStr
33413341
unsafe { self.inner.clone_to_uninit(dst) }
33423342
}
3343+
3344+
#[inline]
3345+
#[cfg_attr(debug_assertions, track_caller)]
3346+
unsafe fn clone_to_init(&self, dst: *mut u8) {
3347+
// SAFETY: Path is just a transparent wrapper around OsStr
3348+
unsafe { self.inner.clone_to_init(dst) }
3349+
}
33433350
}
33443351

33453352
#[stable(feature = "rust1", since = "1.0.0")]

library/std/src/sys/os_str/bytes.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,4 +382,11 @@ unsafe impl CloneToUninit for Slice {
382382
// SAFETY: we're just a transparent wrapper around [u8]
383383
unsafe { self.inner.clone_to_uninit(dst) }
384384
}
385+
386+
#[inline]
387+
#[cfg_attr(debug_assertions, track_caller)]
388+
unsafe fn clone_to_init(&self, dst: *mut u8) {
389+
// SAFETY: we're just a transparent wrapper around [u8]
390+
unsafe { self.inner.clone_to_init(dst) }
391+
}
385392
}

library/std/src/sys/os_str/wtf8.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,4 +329,11 @@ unsafe impl CloneToUninit for Slice {
329329
// SAFETY: we're just a transparent wrapper around Wtf8
330330
unsafe { self.inner.clone_to_uninit(dst) }
331331
}
332+
333+
#[inline]
334+
#[cfg_attr(debug_assertions, track_caller)]
335+
unsafe fn clone_to_init(&self, dst: *mut u8) {
336+
// SAFETY: we're just a transparent wrapper around Wtf8
337+
unsafe { self.inner.clone_to_init(dst) }
338+
}
332339
}

0 commit comments

Comments
 (0)