Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #124275: Implemented Default for Arc<str> #124640

Merged
merged 3 commits into from
May 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions library/alloc/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,19 @@ impl From<&CStr> for Rc<CStr> {
}
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
impl Default for Rc<CStr> {
/// Creates an empty CStr inside an Rc
///
/// This may or may not share an allocation with other Rcs on the same thread.
#[inline]
fn default() -> Self {
let c_str: &CStr = Default::default();
Rc::from(c_str)
}
}

#[cfg(not(test))]
#[stable(feature = "default_box_extra", since = "1.17.0")]
impl Default for Box<CStr> {
Expand Down
25 changes: 25 additions & 0 deletions library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2224,6 +2224,31 @@ impl<T: Default> Default for Rc<T> {
}
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
impl Default for Rc<str> {
/// Creates an empty str inside an Rc
///
/// This may or may not share an allocation with other Rcs on the same thread.
#[inline]
fn default() -> Self {
Rc::from("")
}
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
impl<T> Default for Rc<[T]> {
/// Creates an empty `[T]` inside an Rc
///
/// This may or may not share an allocation with other Rcs on the same thread.
#[inline]
fn default() -> Self {
let arr: [T; 0] = [];
Rc::from(arr)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
trait RcEqIdent<T: ?Sized + PartialEq, A: Allocator> {
fn eq(&self, other: &Rc<T, A>) -> bool;
Expand Down
75 changes: 75 additions & 0 deletions library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3300,6 +3300,81 @@ impl<T: Default> Default for Arc<T> {
}
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
impl Default for Arc<str> {
/// Creates an empty str inside an Arc
///
/// This may or may not share an allocation with other Arcs.
#[inline]
fn default() -> Self {
let arc: Arc<[u8]> = Default::default();
debug_assert!(core::str::from_utf8(&*arc).is_ok());
let (ptr, alloc) = Arc::into_inner_with_allocator(arc);
unsafe { Arc::from_ptr_in(ptr.as_ptr() as *mut ArcInner<str>, alloc) }
}
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
impl Default for Arc<core::ffi::CStr> {
/// Creates an empty CStr inside an Arc
///
/// This may or may not share an allocation with other Arcs.
#[inline]
fn default() -> Self {
use core::ffi::CStr;
static STATIC_INNER_CSTR: ArcInner<[u8; 1]> = ArcInner {
strong: atomic::AtomicUsize::new(1),
weak: atomic::AtomicUsize::new(1),
data: [0],
};
let inner: NonNull<ArcInner<[u8]>> = NonNull::from(&STATIC_INNER_CSTR);
let inner: NonNull<ArcInner<CStr>> = NonNull::new(inner.as_ptr() as *mut ArcInner<CStr>).unwrap();
// `this` semantically is the Arc "owned" by the static, so make sure not to drop it.
let this: mem::ManuallyDrop<Arc<CStr>> = unsafe { mem::ManuallyDrop::new(Arc::from_inner(inner)) };
(*this).clone()
}
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
impl<T> Default for Arc<[T]> {
/// Creates an empty `[T]` inside an Arc
///
/// This may or may not share an allocation with other Arcs.
#[inline]
fn default() -> Self {
let alignment_of_t: usize = mem::align_of::<T>();
// We only make statics for the lowest five alignments.
// Alignments greater than that will use dynamic allocation.
macro_rules! use_static_inner_for_alignments {
($($alignment:literal),*) => {
$(if alignment_of_t == $alignment {
// Note: this must be in a new scope because static and type names are unhygenic.
#[repr(align($alignment))]
struct Aligned;
static ALIGNED_STATIC_INNER: ArcInner<Aligned> = ArcInner {
strong: atomic::AtomicUsize::new(1),
weak: atomic::AtomicUsize::new(1),
data: Aligned,
};
let inner: NonNull<ArcInner<Aligned>> = NonNull::from(&ALIGNED_STATIC_INNER);
let inner: NonNull<ArcInner<[T; 0]>> = inner.cast();
// `this` semantically is the Arc "owned" by the static, so make sure not to drop it.
let this: mem::ManuallyDrop<Arc<[T; 0]>> = unsafe { mem::ManuallyDrop::new(Arc::from_inner(inner)) };
return (*this).clone();
})*
};
}
use_static_inner_for_alignments!(1, 2, 4, 8, 16);

// If T's alignment is not one of the ones we have a static for, make a new unique allocation.
let arr: [T; 0] = [];
Arc::from(arr)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + Hash, A: Allocator> Hash for Arc<T, A> {
fn hash<H: Hasher>(&self, state: &mut H) {
Expand Down