#![cfg_attr(not(feature = "std"), no_std)]
#![deny(unsafe_op_in_unsafe_fn)]
extern crate alloc;
use alloc::alloc::Layout;
use alloc::borrow::{Cow, ToOwned};
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
use core::any::Any;
use core::borrow::Borrow;
use core::cell::Cell;
use core::convert::Infallible;
use core::convert::TryFrom;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::ops::Deref;
#[cfg(not(feature = "std"))]
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::pin::Pin;
use core::ptr::NonNull;
use core::sync::atomic;
use core::sync::atomic::Ordering;
use core::{cmp, fmt, iter, mem, ptr};
#[cfg(feature = "std")]
use std::panic::{RefUnwindSafe, UnwindSafe};
mod atomic_thread_id;
use atomic_thread_id::{AtomicOptionThreadId, ThreadId};
mod slice_builder;
use slice_builder::SliceBuilder;
mod tests;
mod thread_id;
#[inline]
const fn senitel<T>() -> NonNull<T> {
unsafe { NonNull::new_unchecked(usize::MAX as *mut T) }
}
#[inline]
fn is_senitel<T: ?Sized>(ptr: *const T) -> bool {
ptr.cast::<()>() == senitel().as_ptr()
}
mod state_trait {
use core::fmt::Debug;
pub trait RcState: Debug {
const SHARED: bool;
}
}
use state_trait::RcState;
pub mod state {
#[derive(Debug, Clone, Copy)]
pub enum Shared {}
impl super::RcState for Shared {
const SHARED: bool = true;
}
#[derive(Debug, Clone, Copy)]
pub enum Local {}
impl super::RcState for Local {
const SHARED: bool = false;
}
}
use state::{Local, Shared};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum UpgradeError {
ValueDropped,
WrongThread,
}
impl fmt::Display for UpgradeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::ValueDropped => f.write_str("value was already dropped"),
Self::WrongThread => {
f.write_str("tried to get a local reference while another thread was the owner")
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for UpgradeError {}
impl From<Infallible> for UpgradeError {
fn from(x: Infallible) -> UpgradeError {
match x {}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct AllocError;
impl fmt::Display for AllocError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("memory allocation failed")
}
}
#[cfg(feature = "std")]
impl std::error::Error for AllocError {}
impl From<Infallible> for AllocError {
fn from(_: Infallible) -> AllocError {
unreachable!();
}
}
#[inline]
fn set_ptr_value<T: ?Sized, U>(mut meta_ptr: *const T, addr_ptr: *mut U) -> *mut T {
let thin = (&mut meta_ptr as *mut *const T).cast::<*const u8>();
unsafe { *thin = addr_ptr.cast() };
meta_ptr as *mut T
}
struct RcMeta {
owner: AtomicOptionThreadId,
strong_local: Cell<usize>,
strong_shared: atomic::AtomicUsize,
weak: atomic::AtomicUsize,
}
#[repr(C)]
struct RcBox<T: ?Sized> {
meta: RcMeta,
data: T,
}
impl<T: ?Sized> RcBox<T> {
#[inline]
unsafe fn dealloc(ptr: NonNull<RcBox<T>>) {
unsafe { ptr::addr_of_mut!((*ptr.as_ptr()).meta).drop_in_place() };
let layout = Layout::for_value(unsafe { ptr.as_ref() });
unsafe { alloc::alloc::dealloc(ptr.as_ptr().cast(), layout) };
}
#[inline]
fn try_allocate_for_val(
meta: RcMeta,
example: &T,
zeroed: bool,
) -> Result<NonNull<RcBox<T>>, Layout> {
let layout = Layout::new::<RcBox<()>>();
let layout = layout
.extend(Layout::for_value(example))
.map_err(|_| layout)?
.0
.pad_to_align();
let ptr = unsafe {
if zeroed {
alloc::alloc::alloc_zeroed(layout)
} else {
alloc::alloc::alloc(layout)
}
}
.cast::<RcBox<()>>();
unsafe { ptr::addr_of_mut!((*ptr).meta).write(meta) };
let result = set_ptr_value(example, ptr);
NonNull::new(result as *mut RcBox<T>).ok_or(layout)
}
#[inline]
fn allocate_for_val(meta: RcMeta, example: &T, zeroed: bool) -> NonNull<RcBox<T>> {
match Self::try_allocate_for_val(meta, example, zeroed) {
Ok(result) => result,
Err(layout) => alloc::alloc::handle_alloc_error(layout),
}
}
#[inline]
unsafe fn ptr_from_data_ptr(ptr: *const T) -> *const RcBox<T> {
let base_layout = Layout::new::<RcBox<()>>();
let value_alignment = mem::align_of_val(unsafe { &*ptr });
let value_offset_layout =
Layout::from_size_align(0, value_alignment).expect("invalid memory layout");
let layout = base_layout
.extend(value_offset_layout)
.expect("invalid memory layout")
.0;
let rcbox = unsafe { ptr.cast::<u8>().offset(-(layout.size() as isize)) };
set_ptr_value(ptr, rcbox as *mut u8) as *const RcBox<T>
}
}
impl<T> RcBox<T> {
#[inline]
fn try_allocate(meta: RcMeta) -> Result<NonNull<RcBox<mem::MaybeUninit<T>>>, Layout> {
let layout = Layout::new::<RcBox<T>>();
let ptr = unsafe { alloc::alloc::alloc(layout) }.cast::<RcBox<mem::MaybeUninit<T>>>();
if ptr.is_null() {
Err(layout)
} else {
unsafe { ptr::addr_of_mut!((*ptr).meta).write(meta) };
Ok(unsafe { NonNull::new_unchecked(ptr) })
}
}
#[inline]
fn allocate(meta: RcMeta) -> NonNull<RcBox<mem::MaybeUninit<T>>> {
match Self::try_allocate(meta) {
Ok(result) => result,
Err(layout) => alloc::alloc::handle_alloc_error(layout),
}
}
#[inline]
fn try_allocate_slice<'a>(
meta: RcMeta,
len: usize,
zeroed: bool,
) -> Result<&'a mut RcBox<[mem::MaybeUninit<T>]>, Layout> {
let layout = Layout::new::<RcBox<[T; 0]>>();
let payload_layout = Layout::array::<T>(len).map_err(|_| layout)?;
let layout = layout
.extend(payload_layout)
.map_err(|_| layout)?
.0
.pad_to_align();
let ptr = unsafe {
if zeroed {
alloc::alloc::alloc_zeroed(layout)
} else {
alloc::alloc::alloc(layout)
}
};
let ptr = ptr::slice_from_raw_parts_mut(ptr.cast::<mem::MaybeUninit<u8>>(), len)
as *mut RcBox<[mem::MaybeUninit<T>]>;
if ptr.is_null() {
Err(layout)
} else {
unsafe { ptr::addr_of_mut!((*ptr).meta).write(meta) };
Ok(unsafe { ptr.as_mut().unwrap() })
}
}
#[inline]
fn allocate_slice<'a>(
meta: RcMeta,
len: usize,
zeroed: bool,
) -> &'a mut RcBox<[mem::MaybeUninit<T>]> {
match Self::try_allocate_slice(meta, len, zeroed) {
Ok(result) => result,
Err(layout) => alloc::alloc::handle_alloc_error(layout),
}
}
}
impl<T> RcBox<mem::MaybeUninit<T>> {
#[inline]
unsafe fn assume_init(&mut self) -> &mut RcBox<T> {
unsafe { (self as *mut Self).cast::<RcBox<T>>().as_mut() }.unwrap()
}
}
impl<T> RcBox<[mem::MaybeUninit<T>]> {
#[inline]
unsafe fn assume_init(&mut self) -> &mut RcBox<[T]> {
unsafe { (self as *mut _ as *mut RcBox<[T]>).as_mut() }.unwrap()
}
}
impl RcMeta {
#[inline(always)]
fn inc_strong_local(&self) {
let counter = self.strong_local.get();
if counter == usize::MAX {
panic!("reference counter overflow");
}
self.strong_local.set(counter + 1);
}
#[inline]
fn try_inc_strong_local(&self) -> Result<(), ()> {
let counter = self.strong_local.get();
if counter == usize::MAX {
panic!("reference counter overflow");
} else if counter == 0 {
self.try_inc_strong_shared()?;
}
self.strong_local.set(counter + 1);
Ok(())
}
#[inline(always)]
fn dec_strong_local(&self) -> bool {
let counter = self.strong_local.get();
self.strong_local.set(counter - 1);
if counter == 1 {
self.remove_last_local_reference()
} else {
false
}
}
fn remove_last_local_reference(&self) -> bool {
let old_shared = self.strong_shared.fetch_sub(1, Ordering::Release);
if old_shared == 0 {
panic!("reference counter underflow");
}
self.owner.store(None, Ordering::Release);
old_shared == 1
}
#[inline]
fn inc_strong_shared(&self) {
let old_counter = self.strong_shared.fetch_add(1, Ordering::Relaxed);
if old_counter == usize::MAX {
panic!("reference counter overflow");
}
}
#[inline]
fn try_inc_strong_shared(&self) -> Result<(), ()> {
self.strong_shared
.fetch_update(
Ordering::Relaxed,
Ordering::Relaxed,
|old_counter| match old_counter {
0 => None,
usize::MAX => panic!("reference counter overflow"),
_ => Some(old_counter + 1),
},
)
.map(|_| ())
.map_err(|_| ())
}
#[inline]
fn dec_strong_shared(&self) -> bool {
let old_counter = self.strong_shared.fetch_sub(1, Ordering::Release);
if old_counter == 0 {
panic!("reference counter underflow");
}
old_counter == 1 && self.owner.load(Ordering::Relaxed).is_none()
}
#[inline]
fn inc_weak(&self) {
const MAX_COUNT: usize = usize::MAX - 1;
let mut counter = self.weak.load(Ordering::Relaxed);
loop {
match counter {
usize::MAX => {
core::hint::spin_loop();
counter = self.weak.load(Ordering::Relaxed);
continue;
}
MAX_COUNT => panic!("weak counter overflow"),
0 => panic!("BUG: weak resurrection of dead counted reference"),
_ => {
let result = self.weak.compare_exchange_weak(
counter,
counter + 1,
Ordering::Acquire,
Ordering::Relaxed,
);
match result {
Ok(_) => break,
Err(old) => counter = old,
}
}
}
}
}
#[inline]
fn inc_weak_nolock(&self) {
const MAX_COUNT: usize = usize::MAX - 1;
match self.weak.fetch_add(1, Ordering::Relaxed) {
usize::MAX => panic!("BUG: weak counter locked"),
MAX_COUNT => panic!("weak counter overflow"),
0 => panic!("BUG: weak resurrection of dead counted reference"),
_ => (),
}
}
#[inline]
fn dec_weak(&self) -> bool {
let old_counter = self.weak.fetch_sub(1, Ordering::Release);
if old_counter == 0 {
panic!("weak counter underflow");
}
old_counter == 1
}
#[inline]
fn has_unique_ref(&self, is_local: bool) -> bool {
let result =
self.weak
.compare_exchange(1, usize::MAX, Ordering::Acquire, Ordering::Relaxed);
if result.is_ok() {
let mut count = self.strong_shared.load(Ordering::Acquire);
if count == 1 {
let owner = self.owner.load(Ordering::Relaxed);
match owner {
None => {}
Some(tid) if is_local || tid == ThreadId::current_thread() => {
count = self.strong_local.get();
}
Some(_) => {
count = 2;
}
}
}
self.weak.store(1, Ordering::Release);
count == 1
} else {
false
}
}
}
#[must_use]
pub struct HybridRc<T: ?Sized, State: RcState> {
ptr: NonNull<RcBox<T>>,
phantom: PhantomData<State>,
phantom2: PhantomData<RcBox<T>>,
}
pub type Rc<T> = HybridRc<T, Local>;
pub type Arc<T> = HybridRc<T, Shared>;
impl<T: ?Sized, State: RcState> HybridRc<T, State> {
#[inline(always)]
fn from_inner(ptr: NonNull<RcBox<T>>) -> Self {
Self {
ptr,
phantom: PhantomData,
phantom2: PhantomData,
}
}
#[inline(always)]
fn data(&self) -> &T {
unsafe { &(*self.ptr.as_ptr()).data }
}
#[inline(always)]
fn meta(&self) -> &RcMeta {
unsafe { &(*self.ptr.as_ptr()).meta }
}
#[inline(always)]
unsafe fn pin_get_ref(this: &Pin<Self>) -> &Self {
unsafe { &*(this as *const Pin<Self>).cast::<Self>() }
}
#[must_use]
#[inline]
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
unsafe { &mut (*this.ptr.as_ptr()).data }
}
#[must_use]
#[inline]
pub fn get_mut(this: &mut Self) -> Option<&mut T> {
if this.meta().has_unique_ref(!State::SHARED) {
unsafe { Some(Self::get_mut_unchecked(this)) }
} else {
None
}
}
#[must_use]
#[inline]
pub fn as_ptr(this: &Self) -> *const T {
let ptr = this.ptr.as_ptr();
unsafe { ptr::addr_of_mut!((*ptr).data) }
}
#[must_use = "Memory will leak if the result is not used"]
pub fn into_raw(this: Self) -> *const T {
let ptr = Self::as_ptr(&this);
mem::forget(this);
ptr
}
pub unsafe fn from_raw(ptr: *const T) -> Self {
let box_ptr = unsafe { RcBox::<T>::ptr_from_data_ptr(ptr) };
Self::from_inner(NonNull::new(box_ptr as *mut _).expect("invalid pointer"))
}
#[inline]
pub fn downgrade(this: &Self) -> Weak<T> {
this.meta().inc_weak();
Weak { ptr: this.ptr }
}
#[inline]
pub fn downgrade_pin(this: &Pin<Self>) -> PinWeak<T> {
let this = unsafe { Self::pin_get_ref(this) };
PinWeak(Self::downgrade(this))
}
#[inline]
pub fn ptr_eq<S: RcState>(this: &Self, other: &HybridRc<T, S>) -> bool {
this.ptr.as_ptr() == other.ptr.as_ptr()
}
#[inline]
pub fn ptr_eq_pin<S: RcState>(this: &Pin<Self>, other: &Pin<HybridRc<T, S>>) -> bool {
let this = unsafe { Self::pin_get_ref(this) };
let other = unsafe { HybridRc::<T, S>::pin_get_ref(other) };
this.ptr.as_ptr() == other.ptr.as_ptr()
}
#[inline]
pub fn strong_count(this: &Self) -> usize {
let meta = this.meta();
meta.strong_shared.load(Ordering::SeqCst)
+ if State::SHARED {
0
} else {
meta.strong_local.get() - 1
}
}
#[inline]
pub fn strong_count_pin(this: &Pin<Self>) -> usize {
let this = unsafe { Self::pin_get_ref(this) };
Self::strong_count(this)
}
#[inline]
pub fn weak_count(this: &Self) -> usize {
match this.meta().weak.load(Ordering::SeqCst) {
usize::MAX => 0,
count => count - 1,
}
}
#[inline]
pub fn weak_count_pin(this: &Pin<Self>) -> usize {
let this = unsafe { Self::pin_get_ref(this) };
Self::weak_count(this)
}
#[inline]
fn build_new_meta() -> RcMeta {
RcMeta {
owner: if State::SHARED {
None.into()
} else {
ThreadId::current_thread().into()
},
strong_local: Cell::new(if State::SHARED { 0 } else { 1 }),
strong_shared: 1.into(),
weak: 1.into(),
}
}
unsafe fn drop_contents_and_maybe_box(&mut self) {
unsafe {
ptr::drop_in_place(Self::get_mut_unchecked(self));
}
if self.meta().dec_weak() {
unsafe {
RcBox::dealloc(self.ptr);
}
}
}
}
impl<T, State: RcState> HybridRc<T, State> {
#[inline]
pub fn new(data: T) -> Self {
let mut inner = RcBox::allocate(Self::build_new_meta());
let inner = unsafe { inner.as_mut() };
inner.data.write(data);
Self::from_inner(unsafe { inner.assume_init() }.into())
}
#[inline]
pub fn new_uninit() -> HybridRc<mem::MaybeUninit<T>, State> {
let inner = RcBox::allocate(Self::build_new_meta());
HybridRc::from_inner(inner)
}
#[inline]
pub fn new_zeroed() -> HybridRc<mem::MaybeUninit<T>, State> {
let mut inner = RcBox::allocate(Self::build_new_meta());
unsafe { inner.as_mut() }.data = mem::MaybeUninit::zeroed();
HybridRc::from_inner(inner)
}
#[inline]
pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> HybridRc<T, State> {
let meta = RcMeta {
owner: if State::SHARED {
None.into()
} else {
ThreadId::current_thread().into()
},
strong_local: Cell::new(0),
strong_shared: 0.into(),
weak: 1.into(),
};
let inner = RcBox::<T>::allocate(meta);
let weak: Weak<T> = Weak { ptr: NonNull::from(inner).cast() };
let data = data_fn(&weak);
unsafe { &mut *ptr::addr_of_mut!((*inner.as_ptr()).data) }.write(data);
mem::forget(weak);
{
let meta = unsafe { &*ptr::addr_of!((*inner.as_ptr()).meta) };
if !State::SHARED {
meta.inc_strong_local()
}
meta.strong_shared.fetch_add(1, Ordering::Release);
}
Self::from_inner(inner.cast())
}
#[inline]
pub fn pin(data: T) -> Pin<Self> {
unsafe { Pin::new_unchecked(Self::new(data)) }
}
#[inline]
pub fn try_new(data: T) -> Result<Self, AllocError> {
let mut inner = RcBox::try_allocate(Self::build_new_meta()).map_err(|_| AllocError)?;
let inner = unsafe { inner.as_mut() };
inner.data.write(data);
Ok(Self::from_inner(unsafe { inner.assume_init() }.into()))
}
#[inline]
pub fn try_new_uninit() -> Result<HybridRc<mem::MaybeUninit<T>, State>, AllocError> {
let inner = RcBox::try_allocate(Self::build_new_meta()).map_err(|_| AllocError)?;
Ok(HybridRc::from_inner(inner.into()))
}
#[inline]
pub fn try_new_zeroed() -> Result<HybridRc<mem::MaybeUninit<T>, State>, AllocError> {
let mut inner = RcBox::try_allocate(Self::build_new_meta()).map_err(|_| AllocError)?;
unsafe { inner.as_mut() }.data = mem::MaybeUninit::zeroed();
Ok(HybridRc::from_inner(inner))
}
#[inline]
pub fn try_unwrap(this: Self) -> Result<T, Self> {
if State::SHARED {
Self::try_unwrap_internal(this)
} else {
let local_count = this.meta().strong_local.get();
if local_count == 1 {
this.meta().strong_local.set(0);
match Self::try_unwrap_internal(this) {
Ok(result) => Ok(result),
Err(this) => {
this.meta().strong_local.set(local_count);
Err(this)
}
}
} else {
Err(this)
}
}
}
#[inline]
fn try_unwrap_internal(this: Self) -> Result<T, Self> {
let meta = this.meta();
if meta
.strong_shared
.compare_exchange(1, 0, Ordering::AcqRel, Ordering::Relaxed)
.is_err()
{
Err(this)
} else {
meta.owner.store(None, Ordering::Relaxed);
let copy = unsafe { ptr::read(Self::as_ptr(&this)) };
let _weak = Weak { ptr: this.ptr };
mem::forget(this);
Ok(copy)
}
}
}
impl<T, State: RcState> HybridRc<[T], State> {
#[inline]
pub fn new_uninit_slice(len: usize) -> HybridRc<[mem::MaybeUninit<T>], State> {
let inner = RcBox::allocate_slice(Self::build_new_meta(), len, false);
HybridRc::from_inner(inner.into())
}
#[inline]
pub fn new_zeroed_slice(len: usize) -> HybridRc<[mem::MaybeUninit<T>], State> {
let inner = RcBox::allocate_slice(Self::build_new_meta(), len, true);
HybridRc::from_inner(inner.into())
}
#[inline]
unsafe fn copy_from_slice_unchecked(src: &[T]) -> Self {
let len = src.len();
let inner = RcBox::allocate_slice(Self::build_new_meta(), len, false);
let dest = ptr::addr_of_mut!((*inner).data).cast();
unsafe {
src.as_ptr().copy_to_nonoverlapping(dest, src.len());
HybridRc::from_inner(inner.assume_init().into())
}
}
}
impl<T: Copy, State: RcState> HybridRc<[T], State> {
#[inline]
pub fn copy_from_slice(src: &[T]) -> Self {
unsafe { Self::copy_from_slice_unchecked(src) }
}
}
impl<T: ?Sized> Rc<T> {
#[inline]
pub fn to_shared(this: &Self) -> Arc<T> {
this.meta().inc_strong_shared();
Arc::from_inner(this.ptr)
}
#[inline]
pub fn to_shared_pin(this: &Pin<Self>) -> Pin<Arc<T>> {
unsafe {
let this = Self::pin_get_ref(this);
Pin::new_unchecked(Self::to_shared(this))
}
}
#[inline]
pub unsafe fn increment_local_strong_count(ptr: *const T) {
unsafe {
let box_ptr = RcBox::<T>::ptr_from_data_ptr(ptr as *mut T);
(*box_ptr).meta.inc_strong_local();
}
}
#[inline]
pub unsafe fn decrement_local_strong_count(ptr: *const T) {
mem::drop(unsafe { Rc::from_raw(ptr) });
}
}
impl<T: ?Sized> Arc<T> {
#[must_use]
#[inline]
pub fn to_local(this: &Self) -> Option<Rc<T>> {
let meta = this.meta();
let current_thread = ThreadId::current_thread();
let owner = match meta.owner.store_if_none(
Some(current_thread),
Ordering::Acquire,
Ordering::Relaxed,
) {
Ok(_) => None,
Err(owner) => owner,
};
match owner {
None => {
meta.try_inc_strong_local()
.expect("inconsistent reference count (shared == 0)");
Some(Rc::from_inner(this.ptr))
}
Some(v) if v == current_thread => {
meta.inc_strong_local();
Some(Rc::from_inner(this.ptr))
}
Some(_) => None,
}
}
#[must_use]
#[inline]
pub fn to_local_pin(this: &Pin<Self>) -> Option<Pin<Rc<T>>> {
unsafe {
let this = Self::pin_get_ref(this);
Some(Pin::new_unchecked(Self::to_local(this)?))
}
}
#[inline]
pub unsafe fn increment_shared_strong_count(ptr: *const T) {
unsafe {
let box_ptr = RcBox::<T>::ptr_from_data_ptr(ptr);
(*box_ptr).meta.inc_strong_shared();
}
}
#[inline]
pub unsafe fn decrement_shared_strong_count(ptr: *const T) {
mem::drop(unsafe { Arc::from_raw(ptr) });
}
}
impl<T: Clone, State: RcState> HybridRc<T, State> {
#[inline]
pub fn make_mut(this: &mut Self) -> &mut T {
let meta = this.meta();
if State::SHARED {
Self::make_mut_internal(this, false)
} else {
let local_count = meta.strong_local.get();
Self::make_mut_internal(this, local_count > 1)
}
}
#[inline]
fn make_mut_internal(this: &mut Self, force_clone: bool) -> &mut T {
let meta = this.meta();
if force_clone
|| meta
.strong_shared
.compare_exchange(1, 0, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
let mut donor = this.clone_allocation();
mem::swap(&mut this.ptr, &mut donor.ptr);
} else {
if meta.weak.load(Ordering::Relaxed) != 1 {
let _weak = Weak { ptr: this.ptr };
let mut donor = Self::new_uninit();
unsafe {
let uninit = HybridRc::get_mut_unchecked(&mut donor);
uninit.as_mut_ptr().copy_from_nonoverlapping(&**this, 1);
let donor = donor.assume_init();
this.ptr = donor.ptr;
mem::forget(donor);
}
} else {
meta.strong_shared.store(1, Ordering::Release);
}
}
unsafe { Self::get_mut_unchecked(this) }
}
#[inline]
fn clone_allocation(&self) -> Self {
let mut result = Self::new_uninit();
let uninit = unsafe { HybridRc::get_mut_unchecked(&mut result) };
uninit.write((*self.data()).clone());
unsafe { result.assume_init() }
}
}
impl<T, State: RcState> HybridRc<mem::MaybeUninit<T>, State> {
#[inline]
pub unsafe fn assume_init(self) -> HybridRc<T, State> {
HybridRc::from_inner(mem::ManuallyDrop::new(self).ptr.cast())
}
}
impl<T, State: RcState> HybridRc<[mem::MaybeUninit<T>], State> {
#[inline]
pub unsafe fn assume_init(self) -> HybridRc<[T], State> {
HybridRc::from_inner(unsafe {
mem::ManuallyDrop::new(self)
.ptr
.as_mut()
.assume_init()
.into()
})
}
}
impl<State: RcState> HybridRc<dyn Any, State> {
#[inline]
pub fn downcast<T: Any>(self) -> Result<HybridRc<T, State>, Self> {
if (*self).is::<T>() {
let ptr = self.ptr.cast::<RcBox<T>>();
mem::forget(self);
Ok(HybridRc::from_inner(ptr))
} else {
Err(self)
}
}
}
impl<State: RcState> HybridRc<dyn Any + Sync + Send, State> {
#[inline]
pub fn downcast<T: Any + Sync + Send>(self) -> Result<HybridRc<T, State>, Self> {
if (*self).is::<T>() {
let ptr = self.ptr.cast::<RcBox<T>>();
mem::forget(self);
Ok(HybridRc::from_inner(ptr))
} else {
Err(self)
}
}
}
impl<T: ?Sized> Clone for HybridRc<T, Local> {
#[inline]
fn clone(&self) -> Self {
self.meta().inc_strong_local();
Self::from_inner(self.ptr)
}
}
impl<T: ?Sized> Clone for HybridRc<T, Shared> {
#[inline]
fn clone(&self) -> Self {
self.meta().inc_strong_shared();
Self::from_inner(self.ptr)
}
}
impl<T: ?Sized, State: RcState> Drop for HybridRc<T, State> {
#[inline]
fn drop(&mut self) {
let no_more_strong_refs = if State::SHARED {
self.meta().dec_strong_shared()
} else {
self.meta().dec_strong_local()
};
if no_more_strong_refs {
unsafe {
self.drop_contents_and_maybe_box();
}
}
}
}
impl<T: ?Sized, State: RcState> Deref for HybridRc<T, State> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.data()
}
}
impl<T: ?Sized, State: RcState> Borrow<T> for HybridRc<T, State> {
#[inline]
fn borrow(&self) -> &T {
&**self
}
}
impl<T: ?Sized, State: RcState> AsRef<T> for HybridRc<T, State> {
#[inline]
fn as_ref(&self) -> &T {
&**self
}
}
unsafe impl<T: ?Sized + Sync + Send> Send for HybridRc<T, Shared> {}
unsafe impl<T: ?Sized + Sync + Send> Sync for HybridRc<T, Shared> {}
impl<T: RefUnwindSafe + ?Sized, State: RcState> UnwindSafe for HybridRc<T, State> {}
impl<T: RefUnwindSafe> RefUnwindSafe for HybridRc<T, Shared> {}
impl<T: Any + 'static, State: RcState> From<HybridRc<T, State>>
for HybridRc<dyn Any + 'static, State>
{
#[inline]
fn from(src: HybridRc<T, State>) -> Self {
let ptr = src.ptr.as_ptr() as *mut RcBox<dyn Any>;
mem::forget(src);
Self::from_inner(unsafe { NonNull::new_unchecked(ptr) })
}
}
impl<T: Any + Sync + Send + 'static, State: RcState> From<HybridRc<T, State>>
for HybridRc<dyn Any + Sync + Send + 'static, State>
{
#[inline]
fn from(src: HybridRc<T, State>) -> Self {
let ptr = src.ptr.as_ptr() as *mut RcBox<dyn Any + Sync + Send>;
mem::forget(src);
Self::from_inner(unsafe { NonNull::new_unchecked(ptr) })
}
}
impl<T, State: RcState, const N: usize> From<HybridRc<[T; N], State>> for HybridRc<[T], State> {
#[inline]
fn from(src: HybridRc<[T; N], State>) -> Self {
let ptr = src.ptr.as_ptr() as *mut RcBox<[T]>;
mem::forget(src);
Self::from_inner(unsafe { NonNull::new_unchecked(ptr) })
}
}
impl<T: ?Sized> From<Rc<T>> for HybridRc<T, Shared> {
#[inline]
fn from(src: Rc<T>) -> Self {
HybridRc::to_shared(&src)
}
}
impl<T: ?Sized> TryFrom<Arc<T>> for HybridRc<T, Local> {
type Error = Arc<T>;
#[inline]
fn try_from(src: Arc<T>) -> Result<Self, Self::Error> {
match HybridRc::to_local(&src) {
Some(result) => Ok(result),
None => Err(src),
}
}
}
impl<T, State: RcState, const N: usize> TryFrom<HybridRc<[T], State>> for HybridRc<[T; N], State> {
type Error = HybridRc<[T], State>;
#[inline]
fn try_from(src: HybridRc<[T], State>) -> Result<Self, Self::Error> {
if src.len() == N {
let ptr = src.ptr.as_ptr().cast();
mem::forget(src);
Ok(Self::from_inner(unsafe { NonNull::new_unchecked(ptr) }))
} else {
Err(src)
}
}
}
impl<T, State: RcState> From<T> for HybridRc<T, State> {
#[inline]
fn from(src: T) -> Self {
Self::new(src)
}
}
impl<T: Clone, State: RcState> From<&[T]> for HybridRc<[T], State> {
#[inline]
fn from(src: &[T]) -> Self {
let mut builder = SliceBuilder::new(Self::build_new_meta(), src.len());
for item in src {
builder.append(Clone::clone(item));
}
Self::from_inner(builder.finish().into())
}
}
impl<T, State: RcState> From<Vec<T>> for HybridRc<[T], State> {
#[inline]
fn from(mut src: Vec<T>) -> Self {
unsafe {
let result = HybridRc::<_, State>::copy_from_slice_unchecked(&src[..]);
src.set_len(0);
result
}
}
}
impl<State: RcState> From<&str> for HybridRc<str, State> {
#[inline]
fn from(src: &str) -> Self {
let bytes = HybridRc::<_, State>::copy_from_slice(src.as_bytes());
let inner = unsafe { (bytes.ptr.as_ptr() as *mut _ as *mut RcBox<str>).as_mut() }.unwrap();
mem::forget(bytes);
Self::from_inner(inner.into())
}
}
impl<State: RcState> From<String> for HybridRc<str, State> {
#[inline]
fn from(src: String) -> Self {
Self::from(&src[..])
}
}
impl<'a, T: ToOwned + ?Sized, State: RcState> From<Cow<'a, T>> for HybridRc<T, State>
where
HybridRc<T, State>: From<&'a T> + From<T::Owned>,
{
#[inline]
fn from(src: Cow<'a, T>) -> HybridRc<T, State> {
match src {
Cow::Borrowed(value) => HybridRc::from(value),
Cow::Owned(value) => HybridRc::from(value),
}
}
}
impl<T: ?Sized, State: RcState> From<Box<T>> for HybridRc<T, State> {
#[inline]
fn from(src: Box<T>) -> HybridRc<T, State> {
let len = mem::size_of_val(&*src);
let inner = RcBox::allocate_for_val(Self::build_new_meta(), &*src, false);
let dest = unsafe { ptr::addr_of_mut!((*inner.as_ptr()).data) }.cast();
unsafe {
(&*src as *const T)
.cast::<u8>()
.copy_to_nonoverlapping(dest, len);
}
mem::drop(unsafe { mem::transmute::<Box<T>, Box<mem::ManuallyDrop<T>>>(src) });
HybridRc::from_inner(inner)
}
}
impl<T, State: RcState> iter::FromIterator<T> for HybridRc<[T], State> {
fn from_iter<I: iter::IntoIterator<Item = T>>(iter: I) -> Self {
let vec: Vec<T> = iter.into_iter().collect();
vec.into()
}
}
impl<T: Default, State: RcState> Default for HybridRc<T, State> {
#[inline]
fn default() -> Self {
Self::new(Default::default())
}
}
impl<T: ?Sized + PartialEq, S1: RcState, S2: RcState> PartialEq<HybridRc<T, S2>>
for HybridRc<T, S1>
{
#[inline]
fn eq(&self, other: &HybridRc<T, S2>) -> bool {
**self == **other
}
}
impl<T: ?Sized + Eq, State: RcState> Eq for HybridRc<T, State> {}
impl<T: ?Sized + Hash, State: RcState> Hash for HybridRc<T, State> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
Self::data(self).hash(state);
}
}
impl<T: ?Sized + PartialOrd, S1: RcState, S2: RcState> PartialOrd<HybridRc<T, S2>>
for HybridRc<T, S1>
{
#[inline]
fn partial_cmp(&self, other: &HybridRc<T, S2>) -> Option<cmp::Ordering> {
(**self).partial_cmp(&**other)
}
}
impl<T: ?Sized + Ord, State: RcState> Ord for HybridRc<T, State> {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
(**self).cmp(&**other)
}
}
impl<T: ?Sized + fmt::Display, State: RcState> fmt::Display for HybridRc<T, State> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&Self::data(self), f)
}
}
impl<T: ?Sized + fmt::Debug, State: RcState> fmt::Debug for HybridRc<T, State> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&Self::data(self), f)
}
}
impl<T: ?Sized, State: RcState> fmt::Pointer for HybridRc<T, State> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
fmt::Pointer::fmt(&Self::as_ptr(self), f)?;
f.write_str(if State::SHARED {
" [shared]"
} else {
" [local]"
})
} else {
fmt::Pointer::fmt(&Self::as_ptr(self), f)
}
}
}
impl<T: ?Sized, State: RcState> Unpin for HybridRc<T, State> {}
#[must_use]
pub struct Weak<T: ?Sized> {
ptr: NonNull<RcBox<T>>,
}
impl<T: ?Sized> Weak<T> {
#[inline]
fn meta(&self) -> Option<&RcMeta> {
if is_senitel(self.ptr.as_ptr()) {
None
} else {
Some(unsafe { &(*self.ptr.as_ptr()).meta })
}
}
#[must_use]
#[inline]
pub fn as_ptr(&self) -> *const T {
let ptr: *mut RcBox<T> = self.ptr.as_ptr();
if is_senitel(ptr) {
ptr as *const T
} else {
unsafe { ptr::addr_of_mut!((*ptr).data) }
}
}
#[inline]
pub fn upgrade_local(&self) -> Result<Rc<T>, UpgradeError> {
let meta = self.meta().ok_or(UpgradeError::ValueDropped)?;
let current_thread = ThreadId::current_thread();
let owner = match meta.owner.store_if_none(
Some(current_thread),
Ordering::Acquire,
Ordering::Relaxed,
) {
Ok(_) => None,
Err(owner) => owner,
};
if owner == None || owner == Some(current_thread) {
if meta.try_inc_strong_local().is_ok() {
Ok(HybridRc::<T, Local>::from_inner(self.ptr))
} else {
meta.owner.store(None, Ordering::Relaxed);
Err(UpgradeError::ValueDropped)
}
} else {
Err(UpgradeError::WrongThread)
}
}
#[inline]
pub fn upgrade(&self) -> Result<Arc<T>, UpgradeError> {
let meta = self.meta().ok_or(UpgradeError::ValueDropped)?;
meta.try_inc_strong_shared()
.map_err(|_| UpgradeError::ValueDropped)?;
Ok(HybridRc::<T, Shared>::from_inner(self.ptr))
}
#[inline]
pub fn strong_count(&self) -> usize {
if let Some(meta) = self.meta() {
meta.strong_shared.load(Ordering::SeqCst)
} else {
0
}
}
#[inline]
pub fn weak_count(&self) -> usize {
if let Some(meta) = self.meta() {
let weak = meta.weak.load(Ordering::SeqCst);
if weak == usize::MAX {
0
} else if meta.strong_shared.load(Ordering::SeqCst) > 0 {
weak - 1
} else {
weak
}
} else {
0
}
}
}
impl<T> Weak<T> {
pub fn new() -> Weak<T> {
Self { ptr: senitel() }
}
}
impl<T: ?Sized> fmt::Debug for Weak<T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(Weak)")
}
}
impl<T: ?Sized> fmt::Pointer for Weak<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
fmt::Pointer::fmt(&Self::as_ptr(self), f)?;
f.write_str(" [weak]")
} else {
fmt::Pointer::fmt(&Self::as_ptr(self), f)
}
}
}
impl<T> Default for Weak<T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<T: ?Sized> Clone for Weak<T> {
#[inline]
fn clone(&self) -> Self {
if let Some(meta) = self.meta() {
meta.inc_weak_nolock();
}
Self { ptr: self.ptr }
}
}
impl<T: ?Sized> Drop for Weak<T> {
#[inline]
fn drop(&mut self) {
if let Some(meta) = self.meta() {
let last_reference = meta.dec_weak();
if last_reference {
unsafe {
RcBox::dealloc(self.ptr);
}
}
}
}
}
unsafe impl<T: ?Sized + Sync + Send> Send for Weak<T> {}
unsafe impl<T: ?Sized + Sync + Send> Sync for Weak<T> {}
#[repr(transparent)]
pub struct PinWeak<T: ?Sized>(Weak<T>);
impl<T: ?Sized> PinWeak<T> {
#[inline]
pub fn upgrade_local(&self) -> Result<Pin<Rc<T>>, UpgradeError> {
Ok(unsafe { Pin::new_unchecked(self.0.upgrade_local()?) })
}
#[inline]
pub fn upgrade(&self) -> Result<Pin<Arc<T>>, UpgradeError> {
Ok(unsafe { Pin::new_unchecked(self.0.upgrade()?) })
}
#[inline]
pub fn strong_count(&self) -> usize {
self.0.strong_count()
}
#[inline]
pub fn weak_count(&self) -> usize {
self.0.weak_count()
}
#[inline]
pub unsafe fn into_inner_unchecked(self) -> Weak<T> {
self.0
}
}
impl<T> PinWeak<T> {
pub fn new() -> PinWeak<T> {
Self(Weak::new())
}
}
impl<T: ?Sized + Unpin> PinWeak<T> {
#[inline]
pub fn into_inner(self) -> Weak<T> {
self.0
}
}
impl<T: ?Sized> fmt::Debug for PinWeak<T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Pin<(Weak)>")
}
}
impl<T: ?Sized> fmt::Pointer for PinWeak<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
fmt::Pointer::fmt(&self.0.as_ptr(), f)?;
f.write_str(" [weak]")
} else {
fmt::Pointer::fmt(&self.0.as_ptr(), f)
}
}
}
impl<T: ?Sized> Clone for PinWeak<T> {
#[inline]
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<T> Default for PinWeak<T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
unsafe impl<T: ?Sized + Sync + Send> Send for PinWeak<T> {}
unsafe impl<T: ?Sized + Sync + Send> Sync for PinWeak<T> {}