From c6ee29606984863d008c2cf2209751ed0fa43b14 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 16 Jun 2024 14:34:18 +0900 Subject: [PATCH] util: impl Default for Arc<[T]> and Arc at Rust 1.51+ --- portable-atomic-util/CHANGELOG.md | 2 ++ portable-atomic-util/src/arc.rs | 36 +++++++++++++++++++++++++++++++ portable-atomic-util/tests/arc.rs | 17 ++++++++++++--- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/portable-atomic-util/CHANGELOG.md b/portable-atomic-util/CHANGELOG.md index a8bc1cc1..3f7878d6 100644 --- a/portable-atomic-util/CHANGELOG.md +++ b/portable-atomic-util/CHANGELOG.md @@ -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` in no-std at Rust 1.81+. +- Implement `Default` for `Arc<[T]>` and `Arc` 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)) diff --git a/portable-atomic-util/src/arc.rs b/portable-atomic-util/src/arc.rs index 5d7da595..09283814 100644 --- a/portable-atomic-util/src/arc.rs +++ b/portable-atomic-util/src/arc.rs @@ -118,6 +118,13 @@ impl core::panic::UnwindSafe for Arc impl std::panic::UnwindSafe for Arc {} impl Arc { + #[cfg(not(portable_atomic_no_min_const_generics))] + #[inline] + fn into_non_null(this: Self) -> NonNull> { + let this = mem::ManuallyDrop::new(this); + this.ptr + } + #[inline] unsafe fn from_inner(ptr: NonNull>) -> Self { Self { ptr, phantom: PhantomData } @@ -2090,6 +2097,34 @@ impl Default for Arc { } } +#[cfg(not(portable_atomic_no_min_const_generics))] +impl Default for Arc { + /// 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) } + } +} + +#[cfg(not(portable_atomic_no_min_const_generics))] +impl 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 Hash for Arc { fn hash(&self, state: &mut H) { (**self).hash(state); @@ -2428,6 +2463,7 @@ impl error::Error for Arc { // - 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 diff --git a/portable-atomic-util/tests/arc.rs b/portable-atomic-util/tests/arc.rs index d550852b..bff3576b 100644 --- a/portable-atomic-util/tests/arc.rs +++ b/portable-atomic-util/tests/arc.rs @@ -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`. @@ -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::::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 {