#![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::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!();
}
}
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) };
}
}
impl<T> RcBox<T> {
#[inline]
fn try_allocate<'a>(meta: RcMeta) -> Result<&'a mut 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 { ptr.as_mut().unwrap() })
}
}
#[inline]
fn allocate<'a>(meta: RcMeta) -> &'a mut 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 }
}
#[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 {
this.data()
}
#[inline]
pub fn downgrade(this: &Self) -> Weak<T> {
this.meta().inc_weak();
Weak { ptr: this.ptr }
}
#[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 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 weak_count(this: &Self) -> usize {
match this.meta().weak.load(Ordering::SeqCst) {
usize::MAX => 0,
count => count - 1,
}
}
#[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 inner = RcBox::allocate(Self::build_new_meta());
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.into())
}
#[inline]
pub fn new_zeroed() -> HybridRc<mem::MaybeUninit<T>, State> {
let inner = RcBox::allocate(Self::build_new_meta());
inner.data = mem::MaybeUninit::zeroed();
HybridRc::from_inner(inner.into())
}
#[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 inner = RcBox::try_allocate(Self::build_new_meta()).map_err(|_| AllocError)?;
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 inner = RcBox::try_allocate(Self::build_new_meta()).map_err(|_| AllocError)?;
inner.data = mem::MaybeUninit::zeroed();
Ok(HybridRc::from_inner(inner.into()))
}
#[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)
}
}
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,
}
}
}
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, 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)
}
}
}
#[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> {
Weak { 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> {}