Skip to content

Commit

Permalink
util: impl Default for Arc<[T]> and Arc<str> at Rust 1.51+
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Jun 16, 2024
1 parent b84b3ee commit c6ee296
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 3 deletions.
2 changes: 2 additions & 0 deletions portable-atomic-util/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com

- Support `impl Error for Arc<T: Error>` in no-std at Rust 1.81+.

- Implement `Default` for `Arc<[T]>` and `Arc<str>` at Rust 1.51+. (align to the [std Arc change in Rust 1.80](https://github.com/rust-lang/rust/pull/124640))

## [0.2.0] - 2024-05-07

- Rewrite `Arc` based on `std::sync::Arc`'s implementation. ([#142](https://github.com/taiki-e/portable-atomic/pull/142))
Expand Down
36 changes: 36 additions & 0 deletions portable-atomic-util/src/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ impl<T: ?Sized + core::panic::RefUnwindSafe> core::panic::UnwindSafe for Arc<T>
impl<T: ?Sized + std::panic::RefUnwindSafe> std::panic::UnwindSafe for Arc<T> {}

impl<T: ?Sized> Arc<T> {
#[cfg(not(portable_atomic_no_min_const_generics))]
#[inline]
fn into_non_null(this: Self) -> NonNull<ArcInner<T>> {
let this = mem::ManuallyDrop::new(this);
this.ptr
}

#[inline]
unsafe fn from_inner(ptr: NonNull<ArcInner<T>>) -> Self {
Self { ptr, phantom: PhantomData }
Expand Down Expand Up @@ -2090,6 +2097,34 @@ impl<T: Default> Default for Arc<T> {
}
}

#[cfg(not(portable_atomic_no_min_const_generics))]
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]> = Arc::default();
debug_assert!(core::str::from_utf8(&arc).is_ok());
let ptr = Arc::into_non_null(arc);
unsafe { Arc::from_ptr(ptr.as_ptr() as *mut ArcInner<str>) }
}
}

#[cfg(not(portable_atomic_no_min_const_generics))]
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 {
// TODO: we cannot use non-allocation optimization (https://github.com/rust-lang/rust/blob/bc3618f31ea3866e6abea6995ec3979d12ffc65d/library/alloc/src/sync.rs#L3449-L3460)
// for now due to casting Arc<[T; N]> -> Arc<[T]> requires unstable CoerceUnsized.
let arr: [T; 0] = [];
Arc::from(arr)
}
}

impl<T: ?Sized + Hash> Hash for Arc<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
Expand Down Expand Up @@ -2428,6 +2463,7 @@ impl<T: ?Sized + error::Error> error::Error for Arc<T> {
// - alloc::ffi
// - https://doc.rust-lang.org/nightly/alloc/sync/struct.Arc.html#impl-From%3C%26CStr%3E-for-Arc%3CCStr%3E
// - https://doc.rust-lang.org/nightly/alloc/sync/struct.Arc.html#impl-From%3CCString%3E-for-Arc%3CCStr%3E
// - https://doc.rust-lang.org/nightly/alloc/sync/struct.Arc.html#impl-Default-for-Arc%3CCStr%3E
// - Currently, we cannot implement these since CStr layout is not stable.
// - std::ffi
// - https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#impl-From%3C%26OsStr%3E-for-Arc%3COsStr%3E
Expand Down
17 changes: 14 additions & 3 deletions portable-atomic-util/tests/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@

use portable_atomic_util::Arc;

#[derive(Debug, PartialEq)]
#[repr(align(128))]
struct Aligned(u32);

// https://github.com/taiki-e/portable-atomic/issues/37
#[test]
fn over_aligned() {
#[repr(align(128))]
struct Aligned(u32);

let value = Arc::new(Aligned(128));
let ptr = Arc::into_raw(value);
// SAFETY: `ptr` should always be a valid `Aligned`.
Expand All @@ -19,6 +20,16 @@ fn over_aligned() {
assert_eq!(value.0, 128);
}

#[test]
fn default() {
let v = Arc::<[Aligned]>::default();
assert_eq!(v[..], []);
let v = Arc::<[()]>::default();
assert_eq!(v[..], []);
let v = Arc::<str>::default();
assert_eq!(&v[..], "");
}

// https://github.com/rust-lang/rust/blob/5151b8c42712c473e7da56e213926b929d0212ef/library/alloc/src/sync/tests.rs
#[allow(clippy::many_single_char_names, clippy::undocumented_unsafe_blocks)]
mod alloc_tests {
Expand Down

0 comments on commit c6ee296

Please sign in to comment.