Skip to content

Commit ef2f42b

Browse files
committed
add CloneFromCopy and Cell::get_cloned
1 parent e8a792d commit ef2f42b

File tree

5 files changed

+101
-3
lines changed

5 files changed

+101
-3
lines changed

library/alloc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
#![feature(bstr)]
104104
#![feature(bstr_internals)]
105105
#![feature(cast_maybe_uninit)]
106+
#![feature(cell_get_cloned)]
106107
#![feature(char_internals)]
107108
#![feature(char_max_len)]
108109
#![feature(clone_to_uninit)]

library/alloc/src/rc.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@
242242
#![stable(feature = "rust1", since = "1.0.0")]
243243

244244
use core::any::Any;
245-
use core::cell::Cell;
245+
use core::cell::{Cell, CloneFromCopy};
246246
#[cfg(not(no_global_oom_handling))]
247247
use core::clone::CloneToUninit;
248248
use core::clone::UseCloned;
@@ -338,6 +338,11 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Rc<U, A>> for
338338
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
339339
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T> {}
340340

341+
// SAFETY: The bitwise copy has the same `RcInner` pointer as the original, so the clone increments
342+
// the right counts and maintains the invariants.
343+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
344+
unsafe impl<T: ?Sized> CloneFromCopy for Rc<T> {}
345+
341346
impl<T: ?Sized> Rc<T> {
342347
#[inline]
343348
unsafe fn from_inner(ptr: NonNull<RcInner<T>>) -> Self {
@@ -3032,6 +3037,11 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Weak<U, A>> f
30323037
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
30333038
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {}
30343039

3040+
// SAFETY: The bitwise copy has the same `RcInner` pointer as the original, so the clone increments
3041+
// the right counts and maintains the invariants.
3042+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
3043+
unsafe impl<T: ?Sized> CloneFromCopy for Weak<T> {}
3044+
30353045
impl<T> Weak<T> {
30363046
/// Constructs a new `Weak<T>`, without allocating any memory.
30373047
/// Calling [`upgrade`] on the return value always gives [`None`].

library/alloc/src/sync.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
//! `#[cfg(target_has_atomic = "ptr")]`.
1010
1111
use core::any::Any;
12+
use core::cell::CloneFromCopy;
1213
#[cfg(not(no_global_oom_handling))]
1314
use core::clone::CloneToUninit;
1415
use core::clone::UseCloned;
@@ -281,6 +282,11 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Arc<U, A>> fo
281282
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
282283
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Arc<U>> for Arc<T> {}
283284

285+
// SAFETY: The bitwise copy has the same `ArcInner` pointer as the original, so the clone increments
286+
// the right counts and maintains the invariants.
287+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
288+
unsafe impl<T: ?Sized> CloneFromCopy for Arc<T> {}
289+
284290
impl<T: ?Sized> Arc<T> {
285291
unsafe fn from_inner(ptr: NonNull<ArcInner<T>>) -> Self {
286292
unsafe { Self::from_inner_in(ptr, Global) }
@@ -356,6 +362,11 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Weak<U, A>> f
356362
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
357363
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {}
358364

365+
// SAFETY: The bitwise copy has the same `ArcInner` pointer as the original, so the clone increments
366+
// the right counts and maintains the invariants.
367+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
368+
unsafe impl<T: ?Sized> CloneFromCopy for Weak<T> {}
369+
359370
#[stable(feature = "arc_weak", since = "1.4.0")]
360371
impl<T: ?Sized, A: Allocator> fmt::Debug for Weak<T, A> {
361372
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

library/core/src/cell.rs

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,12 @@
253253
use crate::cmp::Ordering;
254254
use crate::fmt::{self, Debug, Display};
255255
use crate::marker::{PhantomData, Unsize};
256-
use crate::mem;
257-
use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn};
256+
use crate::mem::{self, ManuallyDrop};
257+
use crate::ops::{self, CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn};
258258
use crate::panic::const_panic;
259259
use crate::pin::PinCoerceUnsized;
260260
use crate::ptr::{self, NonNull};
261+
use crate::range;
261262

262263
mod lazy;
263264
mod once;
@@ -712,6 +713,71 @@ impl<T, const N: usize> Cell<[T; N]> {
712713
}
713714
}
714715

716+
/// Types that can be cloned from a copy of the value.
717+
///
718+
/// # Safety
719+
///
720+
/// Implementing this trait is safe for any type that can be safely bitwise copied while the
721+
/// original is still valid, provided the copy is never dropped. This is true if and only if the
722+
/// following code is sound:
723+
///
724+
/// ```
725+
/// pub fn clone_from_copy<T: CloneFromCopy>(v: &Cell<T>) -> T {
726+
/// let copy = unsafe { ManuallyDrop::new(ptr::read(v).into_inner()) };
727+
/// T::clone(&copy)
728+
/// }
729+
/// ```
730+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
731+
// Allow potential overlapping implementations in user code
732+
#[marker]
733+
pub unsafe trait CloneFromCopy: Clone {}
734+
735+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
736+
unsafe impl<T: Copy> CloneFromCopy for T {}
737+
738+
// `CloneFromCopy` can be implemented for types that don't have indirection. A commonly-used subset is covered here.
739+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
740+
unsafe impl<T: CloneFromCopy, const N: usize> CloneFromCopy for [T; N] {}
741+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
742+
unsafe impl<T: CloneFromCopy> CloneFromCopy for Option<T> {}
743+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
744+
unsafe impl<T: CloneFromCopy, E: CloneFromCopy> CloneFromCopy for Result<T, E> {}
745+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
746+
unsafe impl<T: CloneFromCopy> CloneFromCopy for PhantomData<T> {}
747+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
748+
unsafe impl<T: CloneFromCopy> CloneFromCopy for ManuallyDrop<T> {}
749+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
750+
unsafe impl<T: CloneFromCopy> CloneFromCopy for ops::Range<T> {}
751+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
752+
unsafe impl<T: CloneFromCopy> CloneFromCopy for range::Range<T> {}
753+
754+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
755+
impl<T: CloneFromCopy> Cell<T> {
756+
/// Get a clone of the `Cell` that contains a copy of the original value.
757+
///
758+
/// This allows a cheaply `Clone`-able type like an `Rc` to be stored in a `Cell`, exposing the
759+
/// cheaper `clone()` method.
760+
///
761+
/// # Examples
762+
///
763+
/// ```
764+
/// #![feature(cell_get_cloned)]
765+
///
766+
/// use core::cell::Cell;
767+
/// use std::rc::Rc;
768+
///
769+
/// let rc = Rc::new(1usize);
770+
/// let c1 = Cell::new(rc);
771+
/// let c2 = c1.get_cloned();
772+
/// assert_eq!(*c2.into_inner(), 1);
773+
/// ```
774+
pub fn get_cloned(&self) -> Self {
775+
// SAFETY: T is CloneFromCopy, which guarantees that this is sound.
776+
let copy = ManuallyDrop::new(unsafe { self.as_ptr().read() });
777+
Cell::new(T::clone(&*copy))
778+
}
779+
}
780+
715781
/// A mutable memory location with dynamically checked borrow rules
716782
///
717783
/// See the [module-level documentation](self) for more.

library/core/src/tuple.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// See core/src/primitive_docs.rs for documentation.
22

3+
use crate::cell::CloneFromCopy;
34
use crate::cmp::Ordering::{self, *};
45
use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy};
56
use crate::ops::ControlFlow::{self, Break, Continue};
@@ -155,6 +156,15 @@ macro_rules! tuple_impls {
155156
}
156157
}
157158
}
159+
160+
maybe_tuple_doc! {
161+
$($T)+ @
162+
// SAFETY: tuples introduce no additional indirection, so they can be copied whenever T
163+
// can.
164+
#[unstable(feature = "cell_get_cloned", issue = "145329")]
165+
unsafe impl<$($T: CloneFromCopy),+> CloneFromCopy for ($($T,)+)
166+
{}
167+
}
158168
}
159169
}
160170

0 commit comments

Comments
 (0)