use alloc::{alloc::Layout, boxed::Box};
use core::borrow::{Borrow, BorrowMut};
use core::convert::TryFrom;
use core::fmt::{self, Debug, Display, Formatter};
use core::mem::{ManuallyDrop, MaybeUninit};
use core::ops::{Deref, DerefMut};
use core::ptr::{self, NonNull};
use core::sync::atomic::AtomicUsize;
use super::{Arc, ArcRef, ArcInner};
#[repr(transparent)]
pub struct ArcBox<T: ?Sized>(pub(crate) Arc<T>);
impl<T> ArcBox<T> {
#[inline]
pub fn new(data: T) -> Self {
ArcBox(Arc::new(data))
}
#[inline]
pub fn new_uninit() -> ArcBox<MaybeUninit<T>> {
unsafe {
let layout = Layout::new::<ArcInner<MaybeUninit<T>>>();
let ptr = alloc::alloc::alloc(layout);
let mut p = NonNull::new(ptr)
.unwrap_or_else(|| alloc::alloc::handle_alloc_error(layout))
.cast::<ArcInner<MaybeUninit<T>>>();
ptr::write(&mut p.as_mut().count, AtomicUsize::new(1));
ArcBox(Arc::from_raw_inner(p))
}
}
pub fn into_inner(this: Self) -> T {
let this = ManuallyDrop::new(this.0);
debug_assert!(
Arc::is_unique(&this),
"attempted to call `.into_inner()` on a `ArcBox` with a non-zero ref count",
);
unsafe { Box::from_raw(this.ptr()).data }
}
#[inline]
pub fn shareable_ref(self) -> ArcRef<'static, T> {
ArcRef::from_arc(self.0)
}
}
impl<T: ?Sized> ArcBox<T> {
#[inline]
pub fn shareable(self) -> Arc<T> {
self.0
}
pub(crate) unsafe fn from_arc(arc: Arc<T>) -> Self {
debug_assert_eq!(Arc::count(&arc), 1);
Self(arc)
}
}
impl<T> ArcBox<MaybeUninit<T>> {
#[inline]
pub unsafe fn assume_init(this: Self) -> ArcBox<T> {
ArcBox(Arc::from_raw_inner(this.0.into_raw_inner().cast()))
}
}
impl<T: ?Sized> TryFrom<Arc<T>> for ArcBox<T> {
type Error = Arc<T>;
fn try_from(arc: Arc<T>) -> Result<Self, Self::Error> {
Arc::try_unique(arc)
}
}
impl<T: ?Sized> Deref for ArcBox<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&*self.0
}
}
impl<T: ?Sized> DerefMut for ArcBox<T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut (*self.0.ptr()).data }
}
}
impl<T: Clone> Clone for ArcBox<T> {
#[inline]
fn clone(&self) -> ArcBox<T> {
ArcBox(Arc::new(self.0.deref().clone()))
}
}
impl<T: Default> Default for ArcBox<T> {
#[inline]
fn default() -> ArcBox<T> {
ArcBox::new(Default::default())
}
}
impl<T: Debug> Debug for ArcBox<T> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.0, f)
}
}
impl<T: Display> Display for ArcBox<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl<T: ?Sized> Borrow<T> for ArcBox<T> {
#[inline]
fn borrow(&self) -> &T {
&**self
}
}
impl<T: ?Sized> AsRef<T> for ArcBox<T> {
#[inline]
fn as_ref(&self) -> &T {
&**self
}
}
impl<T: ?Sized> BorrowMut<T> for ArcBox<T> {
#[inline]
fn borrow_mut(&mut self) -> &mut T {
&mut **self
}
}
impl<T: ?Sized> AsMut<T> for ArcBox<T> {
#[inline]
fn as_mut(&mut self) -> &mut T {
&mut **self
}
}
#[cfg(feature = "unsize")]
unsafe impl<T, U: ?Sized> unsize::CoerciblePtr<U> for ArcBox<T> {
type Pointee = T;
type Output = ArcBox<U>;
fn as_sized_ptr(&mut self) -> *mut T {
unsize::CoerciblePtr::<U>::as_sized_ptr(&mut self.0)
}
unsafe fn replace_ptr(self, new: *mut U) -> ArcBox<U> {
let inner = ManuallyDrop::new(self);
ArcBox(ptr::read(&inner.0).replace_ptr(new))
}
}
#[cfg(test)]
mod tests {
use crate::{Arc, ArcBox};
use core::convert::TryFrom;
#[test]
fn unique_into_inner() {
let unique = ArcBox::new(10u64);
assert_eq!(ArcBox::into_inner(unique), 10);
}
#[test]
fn try_from_arc() {
let x = Arc::new(10_000);
let y = x.clone();
assert!(ArcBox::try_from(x).is_err());
assert_eq!(ArcBox::into_inner(ArcBox::try_from(y).unwrap()), 10_000,);
}
}