use std::{
alloc::{self, Layout},
borrow::Borrow,
cmp,
hash::{Hash, Hasher},
mem,
ptr::{self, NonNull},
slice, str,
};
const UTF8_MASK: u32 = 1 << 31;
const REFCNT_MASK: u32 = !UTF8_MASK;
#[repr(C)]
struct InnerHeader {
size: u32,
utf8_refcnt: u32,
}
impl InnerHeader {
const fn new(size: u32, is_utf8: bool) -> Self {
Self {
size,
utf8_refcnt: 1 | (if is_utf8 { UTF8_MASK } else { 0 }),
}
}
const fn refcnt(&self) -> u32 {
self.utf8_refcnt & REFCNT_MASK
}
const fn is_utf8(&self) -> bool {
self.utf8_refcnt & UTF8_MASK != 0
}
fn set_refcnt(&mut self, cnt: u32) {
assert_eq!(cnt & UTF8_MASK, 0);
self.utf8_refcnt &= UTF8_MASK;
self.utf8_refcnt |= cnt;
}
fn set_is_utf8(&mut self) {
self.utf8_refcnt |= UTF8_MASK;
}
}
pub struct Inner(NonNull<u8>);
impl Inner {
#[allow(clippy::cast_ptr_alignment)]
unsafe fn new_raw(bytes: &[u8], is_utf8: bool) -> Self {
unsafe {
let data = alloc::alloc(Layout::from_size_align_unchecked(
mem::size_of::<InnerHeader>() + bytes.len(),
mem::align_of::<InnerHeader>(),
));
assert!(!data.is_null());
*data.cast::<InnerHeader>() =
InnerHeader::new(bytes.len().try_into().expect("bytes > 4GB"), is_utf8);
ptr::copy_nonoverlapping(
bytes.as_ptr(),
data.add(mem::size_of::<InnerHeader>()),
bytes.len(),
);
Self(NonNull::new_unchecked(data))
}
}
pub fn new_bytes(bytes: &[u8]) -> Self {
unsafe { Self::new_raw(bytes, false) }
}
#[allow(dead_code)]
pub fn new_str(str: &str) -> Self {
unsafe { Self::new_raw(str.as_bytes(), true) }
}
#[allow(clippy::missing_const_for_fn)]
pub fn as_slice(&self) -> &[u8] {
let header = Self::header(self);
let size = unsafe { (*header).size };
unsafe {
slice::from_raw_parts(
self.0.as_ptr().add(mem::size_of::<InnerHeader>()),
size as usize,
)
}
}
pub unsafe fn as_str_unchecked(&self) -> &str {
unsafe { str::from_utf8_unchecked(self.as_slice()) }
}
pub fn check_utf8(this: &Self) -> bool {
let header = Self::header_mut(this);
if unsafe { (*header).is_utf8() } {
return true;
}
if str::from_utf8(this.as_slice()).is_ok() {
unsafe { (*header).set_is_utf8() };
true
} else {
false
}
}
pub unsafe fn assume_utf8(this: &Self) {
let header = Self::header_mut(this);
unsafe { (*header).set_is_utf8() }
}
const fn header(this: &Self) -> *const InnerHeader {
#![allow(clippy::cast_ptr_alignment)]
this.0.as_ptr() as *const InnerHeader
}
const fn header_mut(this: &Self) -> *mut InnerHeader {
#![allow(clippy::cast_ptr_alignment)]
this.0.as_ptr().cast::<InnerHeader>()
}
fn clone(this: &Self) -> Self {
let header = Self::header_mut(this);
unsafe {
let refcnt = (*header).refcnt() + 1;
(*header).set_refcnt(refcnt);
}
Self(this.0)
}
pub fn ptr_eq(a: &Self, b: &Self) -> bool {
a.0 == b.0
}
pub const fn as_ptr(this: &Self) -> *const u8 {
unsafe { this.0.as_ptr().add(mem::size_of::<InnerHeader>()) }
}
pub const fn strong_count(this: &Self) -> u32 {
let header = Self::header(this);
unsafe { (*header).refcnt() }
}
}
impl Clone for Inner {
fn clone(&self) -> Self {
Self::clone(self)
}
}
impl Drop for Inner {
fn drop(&mut self) {
#[cold]
#[inline(never)]
fn dealloc(val: &Inner) {
let header = Inner::header_mut(val);
unsafe {
alloc::dealloc(
val.0.as_ptr(),
Layout::from_size_align_unchecked(
mem::size_of::<InnerHeader>() + (*header).size as usize,
mem::align_of::<InnerHeader>(),
),
);
}
}
let header = Self::header_mut(self);
let refcnt = unsafe {
let refcnt = (*header).refcnt() - 1;
(*header).set_refcnt(refcnt);
refcnt
};
if refcnt == 0 {
dealloc(self);
}
}
}
impl PartialEq for Inner {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0 || self.as_slice().eq(other.as_slice())
}
}
impl Hash for Inner {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_slice().hash(state);
}
}
impl Eq for Inner {}
impl PartialOrd for Inner {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.as_slice().partial_cmp(other.as_slice())
}
}
impl Ord for Inner {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.as_slice().cmp(other.as_slice())
}
}
impl Borrow<[u8]> for Inner {
fn borrow(&self) -> &[u8] {
self.as_slice()
}
}