#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
mod algorithm;
#[cfg(test)]
mod tests;
pub use algorithm::*;
use alloc::alloc::{alloc, handle_alloc_error};
use alloc::boxed::Box;
use alloc::str;
use core::alloc::Layout;
use core::marker::PhantomData;
use core::ops::Deref;
use core::ptr::NonNull;
use core::{mem, ptr};
#[doc(hidden)]
#[repr(C)]
pub struct FlexRcInner<META, META2, T: ?Sized> {
metadata: META,
phantom: PhantomData<META2>,
data: T,
}
impl<META, META2, T> FlexRcInner<META, META2, T>
where
META: Algorithm<META, META2>,
{
#[inline]
fn new(data: T) -> Self {
Self {
metadata: META::create(),
phantom: PhantomData,
data,
}
}
}
impl<META, META2, T> FlexRcInner<META, META2, [mem::MaybeUninit<T>]> {
#[inline]
unsafe fn assume_init(&mut self) -> &mut FlexRcInner<META, META2, [T]> {
&mut *(self as *mut Self as *mut FlexRcInner<META, META2, [T]>)
}
}
#[repr(C)]
pub struct FlexRc<META, META2, T>
where
META: Algorithm<META, META2>,
META2: Algorithm<META2, META>,
T: ?Sized,
{
ptr: NonNull<FlexRcInner<META, META2, T>>,
phantom: PhantomData<FlexRcInner<META, META2, T>>,
}
impl<META, META2, T> FlexRc<META, META2, T>
where
META: Algorithm<META, META2>,
META2: Algorithm<META2, META>,
{
#[inline]
pub fn new(data: T) -> Self {
let boxed = Box::new(FlexRcInner::new(data));
Self::from_inner(unsafe { NonNull::new_unchecked(Box::into_raw(boxed)) })
}
#[inline]
pub fn from_ref(data: &T) -> Self
where
T: Clone,
{
Self::new(data.clone())
}
#[inline]
fn is_unique(&self) -> bool {
self.as_inner().metadata.is_unique()
}
#[inline]
pub fn get_mut(&mut self) -> Option<&mut T> {
if self.is_unique() {
unsafe { Some(self.get_mut_unchecked()) }
} else {
None
}
}
#[inline]
pub unsafe fn get_mut_unchecked(&mut self) -> &mut T {
&mut (*self.ptr.as_ptr()).data
}
}
impl<META, META2, T> FlexRc<META, META2, [T]>
where
META: Algorithm<META, META2>,
META2: Algorithm<META2, META>,
T: Copy,
{
#[inline]
fn new_slice_uninit_inner<'a>(
len: usize,
) -> &'a mut FlexRcInner<META, META2, [mem::MaybeUninit<T>]> {
let array_layout = Layout::array::<mem::MaybeUninit<T>>(len).expect("valid array length");
let layout = Layout::new::<FlexRcInner<META, META2, ()>>()
.extend(array_layout)
.expect("valid inner layout")
.0
.pad_to_align();
let ptr = unsafe { alloc(layout) } as *mut mem::MaybeUninit<T>;
let ptr = match ptr::NonNull::new(ptr) {
Some(ptr) => ptr.as_ptr(),
None => handle_alloc_error(layout),
};
let inner = ptr::slice_from_raw_parts(ptr, len)
as *mut FlexRcInner<META, META2, [mem::MaybeUninit<T>]>;
unsafe {
ptr::write(&mut (*inner).metadata, META::create());
&mut (*inner)
}
}
#[inline]
pub fn new_slice_uninit(len: usize) -> FlexRc<META, META2, [mem::MaybeUninit<T>]> {
let inner = Self::new_slice_uninit_inner(len);
FlexRc::from_inner(inner.into())
}
#[cfg(not(feature = "str_deref"))]
#[inline]
pub fn from_slice(data: &[T]) -> Self {
Self::from_slice_priv(data)
}
#[inline]
fn from_slice_priv(data: &[T]) -> Self {
let inner = Self::new_slice_uninit_inner(data.len());
unsafe {
ptr::copy_nonoverlapping(
data.as_ptr(),
&mut (*inner).data as *mut [mem::MaybeUninit<T>] as *mut [T] as *mut T,
data.len(),
);
}
unsafe { Self::from_inner(inner.assume_init().into()) }
}
}
impl<META, META2, T> FlexRc<META, META2, [mem::MaybeUninit<T>]>
where
META: Algorithm<META, META2>,
META2: Algorithm<META2, META>,
{
#[inline]
pub unsafe fn assume_init(self) -> FlexRc<META, META2, [T]> {
FlexRc::from_inner(
mem::ManuallyDrop::new(self)
.ptr
.as_mut()
.assume_init()
.into(),
)
}
}
impl<META, META2> FlexRc<META, META2, [u8]>
where
META: Algorithm<META, META2>,
META2: Algorithm<META2, META>,
{
#[inline]
pub fn from_str_ref(s: impl AsRef<str>) -> FlexRc<META, META2, [u8]> {
FlexRc::from_slice_priv(s.as_ref().as_bytes())
}
}
impl<META, META2, T> FlexRc<META, META2, T>
where
META: Algorithm<META, META2>,
META2: Algorithm<META2, META>,
T: ?Sized,
{
#[inline(always)]
fn from_inner(inner: NonNull<FlexRcInner<META, META2, T>>) -> Self {
Self {
ptr: inner,
phantom: PhantomData,
}
}
#[inline(always)]
fn as_inner(&self) -> &FlexRcInner<META, META2, T> {
unsafe { self.ptr.as_ref() }
}
#[inline]
pub fn try_into_other(self) -> Result<FlexRc<META2, META, T>, Self> {
let meta = &self.as_inner().metadata;
match meta.try_into_other(self.ptr.as_ptr()) {
Ok(inner) => {
let inner = unsafe { NonNull::new_unchecked(inner) };
Ok(<FlexRc<META2, META, T>>::from_inner(inner))
}
Err(_) => Err(self),
}
}
#[inline]
pub fn into_other(self) -> FlexRc<META2, META, T>
where
T: Clone,
{
match self.try_into_other() {
Ok(other) => other,
Err(this) => <FlexRc<META2, META, T>>::from_ref(&*this),
}
}
#[inline]
pub fn try_to_other(&self) -> Result<FlexRc<META2, META, T>, &Self> {
let meta = &self.as_inner().metadata;
match meta.try_to_other(self.ptr.as_ptr()) {
Ok(inner) => {
let inner = unsafe { NonNull::new_unchecked(inner) };
Ok(<FlexRc<META2, META, T>>::from_inner(inner))
}
Err(_) => Err(self),
}
}
#[inline]
pub fn to_other(&self) -> FlexRc<META2, META, T>
where
T: Clone,
{
match self.try_to_other() {
Ok(other) => other,
Err(this) => <FlexRc<META2, META, T>>::from_ref(&*this),
}
}
}
impl<META, META2, T> Deref for FlexRc<META, META2, T>
where
META: Algorithm<META, META2>,
META2: Algorithm<META2, META>,
{
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.as_inner().data
}
}
#[cfg(feature = "str_deref")]
impl<META, META2> Deref for FlexRc<META, META2, [u8]>
where
META: Algorithm<META, META2>,
META2: Algorithm<META2, META>,
{
type Target = str;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { str::from_utf8_unchecked(&self.as_inner().data) }
}
}
impl<META, META2, T> Clone for FlexRc<META, META2, T>
where
META: Algorithm<META, META2>,
META2: Algorithm<META2, META>,
T: ?Sized,
{
#[inline(always)]
fn clone(&self) -> Self {
self.as_inner().metadata.clone();
Self::from_inner(self.ptr)
}
}
impl<META, META2, T> Drop for FlexRc<META, META2, T>
where
META: Algorithm<META, META2>,
META2: Algorithm<META2, META>,
T: ?Sized,
{
#[inline(always)]
fn drop(&mut self) {
let meta = &self.as_inner().metadata;
if meta.drop() {
unsafe {
Box::from_raw(self.ptr.as_ptr());
}
}
}
}