use std::borrow::{Borrow, Cow};
use std::rc::Rc;
use std::{cmp, fmt, hash, marker, mem, ops, ptr, slice, str};
pub struct CowRcStr<'a> {
ptr: ptr::NonNull<()>,
borrowed_len_or_max: usize,
phantom: marker::PhantomData<Result<&'a str, Rc<String>>>,
}
fn _static_assert_same_size() {
let _ = mem::transmute::<CowRcStr<'_>, Option<CowRcStr<'_>>>;
}
impl<'a> From<Cow<'a, str>> for CowRcStr<'a> {
#[inline]
fn from(s: Cow<'a, str>) -> Self {
match s {
Cow::Borrowed(s) => CowRcStr::from(s),
Cow::Owned(s) => CowRcStr::from(s),
}
}
}
impl<'a> From<&'a str> for CowRcStr<'a> {
#[inline]
fn from(s: &'a str) -> Self {
let len = s.len();
assert!(len < usize::MAX);
CowRcStr {
ptr: unsafe { ptr::NonNull::new_unchecked(s.as_ptr() as *mut ()) },
borrowed_len_or_max: len,
phantom: marker::PhantomData,
}
}
}
impl<'a> From<String> for CowRcStr<'a> {
#[inline]
fn from(s: String) -> Self {
CowRcStr::from_rc(Rc::new(s))
}
}
impl<'a> CowRcStr<'a> {
#[inline]
fn from_rc(s: Rc<String>) -> Self {
let ptr = unsafe { ptr::NonNull::new_unchecked(Rc::into_raw(s) as *mut ()) };
CowRcStr {
ptr,
borrowed_len_or_max: usize::MAX,
phantom: marker::PhantomData,
}
}
#[inline]
fn unpack(&self) -> Result<&'a str, *const String> {
if self.borrowed_len_or_max == usize::MAX {
Err(self.ptr.as_ptr() as *const String)
} else {
unsafe {
Ok(str::from_utf8_unchecked(slice::from_raw_parts(
self.ptr.as_ptr() as *const u8,
self.borrowed_len_or_max,
)))
}
}
}
}
impl<'a> Clone for CowRcStr<'a> {
#[inline]
fn clone(&self) -> Self {
match self.unpack() {
Err(ptr) => {
let rc = unsafe { Rc::from_raw(ptr) };
let new_rc = rc.clone();
mem::forget(rc); CowRcStr::from_rc(new_rc)
}
Ok(_) => CowRcStr { ..*self },
}
}
}
impl<'a> Drop for CowRcStr<'a> {
#[inline]
fn drop(&mut self) {
if let Err(ptr) = self.unpack() {
mem::drop(unsafe { Rc::from_raw(ptr) })
}
}
}
impl<'a> ops::Deref for CowRcStr<'a> {
type Target = str;
#[inline]
fn deref(&self) -> &str {
self.unpack().unwrap_or_else(|ptr| unsafe { &**ptr })
}
}
impl<'a> AsRef<str> for CowRcStr<'a> {
#[inline]
fn as_ref(&self) -> &str {
self
}
}
impl<'a> Borrow<str> for CowRcStr<'a> {
#[inline]
fn borrow(&self) -> &str {
self
}
}
impl<'a> Default for CowRcStr<'a> {
#[inline]
fn default() -> Self {
Self::from("")
}
}
impl<'a> hash::Hash for CowRcStr<'a> {
#[inline]
fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
str::hash(self, hasher)
}
}
impl<'a, T: AsRef<str>> PartialEq<T> for CowRcStr<'a> {
#[inline]
fn eq(&self, other: &T) -> bool {
str::eq(self, other.as_ref())
}
}
impl<'a, T: AsRef<str>> PartialOrd<T> for CowRcStr<'a> {
#[inline]
fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
str::partial_cmp(self, other.as_ref())
}
}
impl<'a> Eq for CowRcStr<'a> {}
impl<'a> Ord for CowRcStr<'a> {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
str::cmp(self, other)
}
}
impl<'a> fmt::Display for CowRcStr<'a> {
#[inline]
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
str::fmt(self, formatter)
}
}
impl<'a> fmt::Debug for CowRcStr<'a> {
#[inline]
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
str::fmt(self, formatter)
}
}