use std::alloc;
use std::fmt;
use std::fmt::Write;
use std::mem;
use std::mem::ManuallyDrop;
use std::mem::MaybeUninit;
use std::num::NonZeroUsize;
use std::ptr;
use std::slice;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct RawYarn {
ptr: *const u8,
len: NonZeroUsize,
}
#[repr(C)]
#[derive(Copy, Clone)]
struct Small {
data: [u8; mem::size_of::<RawYarn>() - 1],
len: u8,
}
#[repr(C)]
#[derive(Copy, Clone)]
struct Slice {
ptr: *const u8,
len: usize,
}
enum Layout<'a> {
Small(&'a Small),
Slice(&'a Slice),
}
enum LayoutMut<'a> {
Small(&'a mut Small),
Slice(&'a mut Slice),
}
unsafe impl Send for RawYarn {}
unsafe impl Sync for RawYarn {}
#[test]
fn has_niche() {
assert_eq!(mem::size_of::<RawYarn>(), mem::size_of::<Option<RawYarn>>());
}
impl RawYarn {
pub const SSO_LEN: usize = {
let bytes_usable = mem::size_of::<usize>() * 2 - 1;
let max_len = 1 << (8 - 2);
let sso_len = if bytes_usable < max_len { bytes_usable } else { max_len };
assert!(
sso_len >= 4,
"yarns are not supported on architectures with pointers this small"
);
sso_len
};
pub const SMALL: u8 = 0b11;
pub const STATIC: u8 = 0b01;
pub const HEAP: u8 = 0b10;
pub const ALIASED: u8 = 0b00;
const SHIFT8: u32 = u8::BITS - 2;
const SHIFT: u32 = usize::BITS - 2;
const MASK8: usize = !0 << Self::SHIFT8;
const MASK: usize = !0 << Self::SHIFT;
#[inline(always)]
pub const fn kind(&self) -> u8 {
(self.len.get() >> Self::SHIFT) as u8
}
#[inline(always)]
pub const unsafe fn from_ptr_len_tag(
ptr: *const u8,
len: usize,
tag: u8,
) -> Self {
assert!(
len < usize::MAX / 4,
"yarns cannot be larger than a quarter of the address space"
);
debug_assert!(
tag != 0 || len != 0,
"zero-length and zero tag are not permitted simultaneously."
);
debug_assert!(tag != Self::SMALL);
Self {
ptr,
len: NonZeroUsize::new_unchecked(len | (tag as usize) << Self::SHIFT),
}
}
#[inline(always)]
const fn layout(&self) -> Layout {
match self.is_small() {
true => unsafe {
Layout::Small(mem::transmute::<&RawYarn, &Small>(self))
},
false => unsafe {
Layout::Slice(mem::transmute::<&RawYarn, &Slice>(self))
},
}
}
#[inline(always)]
fn layout_mut(&mut self) -> LayoutMut {
match self.is_small() {
true => unsafe {
LayoutMut::Small(mem::transmute::<&mut RawYarn, &mut Small>(self))
},
false => unsafe {
LayoutMut::Slice(mem::transmute::<&mut RawYarn, &mut Slice>(self))
},
}
}
#[inline]
pub fn empty<'a>() -> &'a RawYarn {
static STORAGE: MaybeUninit<RawYarn> = MaybeUninit::new(RawYarn::new(b""));
unsafe {
STORAGE.assume_init_ref()
}
}
#[inline]
pub const fn new(s: &'static [u8]) -> Self {
if s.len() < Self::SSO_LEN {
unsafe {
return Self::from_slice_inlined_unchecked(s.as_ptr(), s.len());
}
}
unsafe {
Self::from_ptr_len_tag(s.as_ptr(), s.len(), Self::STATIC)
}
}
#[inline(always)]
pub const fn len(self) -> usize {
match self.layout() {
Layout::Small(s) => s.len as usize & !Self::MASK8,
Layout::Slice(s) => s.len & !Self::MASK,
}
}
#[inline(always)]
pub const fn on_heap(self) -> bool {
self.kind() == Self::HEAP
}
#[inline(always)]
pub const fn is_small(self) -> bool {
self.kind() == Self::SMALL
}
#[inline(always)]
pub const fn is_immortal(self) -> bool {
self.kind() != Self::ALIASED
}
#[inline(always)]
pub unsafe fn destroy(self, layout: alloc::Layout) {
if !self.on_heap() {
return;
}
debug_assert!(layout.size() > 0);
alloc::dealloc(self.ptr as *mut u8, layout)
}
#[inline(always)]
pub const fn as_ptr(&self) -> *const u8 {
match self.layout() {
Layout::Small(s) => s.data.as_ptr().cast(),
Layout::Slice(s) => s.ptr,
}
}
#[inline(always)]
pub fn as_mut_ptr(&mut self) -> *mut u8 {
match self.layout_mut() {
LayoutMut::Small(s) => s.data.as_mut_ptr().cast(),
LayoutMut::Slice(s) => s.ptr.cast_mut(),
}
}
#[inline(always)]
pub const fn as_slice(&self) -> &[u8] {
unsafe {
slice::from_raw_parts(self.as_ptr(), self.len())
}
}
#[inline(always)]
pub unsafe fn as_mut_slice(&mut self) -> &mut [u8] {
debug_assert!(self.is_small() || self.on_heap());
unsafe {
slice::from_raw_parts_mut(self.as_mut_ptr(), self.len())
}
}
#[inline(always)]
pub unsafe fn copy_slice(layout: alloc::Layout, ptr: *const u8) -> Self {
match Self::from_slice_inlined(layout, ptr) {
Some(inl) => inl,
None => Self::from_heap(AlignedBox::new(layout, ptr)),
}
}
#[inline(always)]
pub const unsafe fn alias_slice(
layout: alloc::Layout,
ptr: *const u8,
) -> Self {
if let Some(inlined) = Self::from_slice_inlined(layout, ptr) {
return inlined;
}
Self::from_ptr_len_tag(ptr, layout.size(), Self::ALIASED)
}
#[inline]
pub const unsafe fn from_slice_inlined_unchecked(
ptr: *const u8,
len: usize,
) -> Self {
debug_assert!(len <= Self::SSO_LEN);
if len > Self::SSO_LEN {
std::hint::unreachable_unchecked();
}
let tagged_len = (len as u8) | Self::SMALL << Self::SHIFT8;
if mem::size_of::<Self>() == 16 {
let register = if len > 8 {
let x0 = ptr.cast::<u64>().read_unaligned() as u128;
let x1 = ptr.add(len - 8).cast::<u64>().read_unaligned() as u128;
x0 | (x1 << ((len - 8) * 8))
} else if len > 3 {
let x0 = ptr.cast::<u32>().read_unaligned() as u128;
let x1 = ptr.add(len - 4).cast::<u32>().read_unaligned() as u128;
x0 | (x1 << ((len - 4) * 8))
} else if len > 0 {
let x0 = ptr.read() as u128;
let x1 = ptr.add(len / 2).read() as u128;
let x2 = ptr.add(len - 1).read() as u128;
x0 | x1 << (len / 2 * 8) | x2 << ((len - 1) * 8)
} else {
0
};
let mut small = (®ister as *const u128).cast::<Small>().read();
small.len = tagged_len;
return mem::transmute::<Small, RawYarn>(small);
}
let mut small = Small {
data: [0; Self::SSO_LEN],
len: tagged_len,
};
let mut i = 0;
while i < len {
small.data[i] = *ptr.add(i);
i += 1;
}
mem::transmute::<Small, RawYarn>(small)
}
#[inline]
pub const fn from_slice_inlined(
layout: alloc::Layout,
ptr: *const u8,
) -> Option<Self> {
assert!(
layout.align() <= mem::align_of::<Self>(),
"cannot store types with alignment greater than a pointer in a Yarn"
);
if layout.size() > Self::SSO_LEN {
return None;
}
unsafe {
Some(Self::from_slice_inlined_unchecked(ptr, layout.size()))
}
}
#[inline(always)]
pub const fn from_char(c: char) -> Self {
let (data, len) = crate::utf8::encode_utf8(c);
unsafe {
Self::from_slice_inlined_unchecked(data.as_ptr(), len)
}
}
#[inline(always)]
pub const fn from_byte(c: u8) -> Self {
unsafe {
Self::from_slice_inlined_unchecked(&c, 1)
}
}
pub unsafe fn concat<'a>(
layout: alloc::Layout,
iter: impl IntoIterator<Item = &'a [u8]>,
) -> Self {
if layout.size() > Self::SSO_LEN {
return Self::from_heap(AlignedBox::concat(layout, iter));
}
let mut cursor = 0;
let mut data = [0; Self::SSO_LEN];
for b in iter {
data[cursor..cursor + b.len()].copy_from_slice(b);
cursor += b.len();
}
Self::from_slice_inlined(layout, data[..cursor].as_ptr()).unwrap_unchecked()
}
#[inline]
pub fn from_heap(s: AlignedBox) -> Self {
if let Some(inline) =
Self::from_slice_inlined(s.layout(), s.as_slice().as_ptr())
{
return inline;
}
let (ptr, len) = s.into_raw_parts();
unsafe {
Self::from_ptr_len_tag(ptr, len, Self::HEAP)
}
}
pub fn from_fmt_args(args: fmt::Arguments) -> Self {
if let Some(constant) = args.as_str() {
return Self::new(constant.as_bytes());
}
enum Buf {
Sso(usize, [u8; RawYarn::SSO_LEN]),
Vec(Vec<u8>),
}
impl fmt::Write for Buf {
fn write_str(&mut self, s: &str) -> fmt::Result {
match self {
Self::Sso(len, bytes) => {
let new_len = *len + s.len();
if new_len > RawYarn::SSO_LEN {
let mut vec = Vec::from(&bytes[..*len]);
vec.extend_from_slice(s.as_bytes());
*self = Self::Vec(vec);
} else {
let _ = &bytes[*len..new_len].copy_from_slice(s.as_bytes());
*len = new_len;
}
}
Self::Vec(vec) => vec.extend_from_slice(s.as_bytes()),
}
Ok(())
}
}
let mut w = Buf::Sso(0, [0; RawYarn::SSO_LEN]);
let _ = w.write_fmt(args);
match w {
Buf::Sso(len, bytes) => {
let chunk = &bytes[..len];
Self::from_slice_inlined(
alloc::Layout::for_value(chunk),
chunk.as_ptr(),
)
.unwrap()
}
Buf::Vec(vec) => Self::from_heap(unsafe {
AlignedBox::from_vec(1, vec)
}),
}
}
}
pub struct AlignedBox {
data: Box<[u8]>,
align: usize,
}
impl<T: ?Sized> From<Box<T>> for AlignedBox {
fn from(value: Box<T>) -> Self {
let len = mem::size_of_val(&*value);
let align = mem::align_of_val(&*value);
let ptr = Box::into_raw(value) as *mut u8;
Self {
data: unsafe { Box::from_raw(ptr::slice_from_raw_parts_mut(ptr, len)) },
align,
}
}
}
impl AlignedBox {
unsafe fn new(layout: alloc::Layout, data: *const u8) -> Self {
Self::concat(layout, [slice::from_raw_parts(data, layout.size())])
}
unsafe fn from_vec(align: usize, data: Vec<u8>) -> Self {
if align == 1 {
return Self { data: data.into(), align };
}
Self::new(
alloc::Layout::from_size_align_unchecked(data.len(), align),
data.as_ptr(),
)
}
unsafe fn concat<'a>(
layout: alloc::Layout,
slices: impl IntoIterator<Item = &'a [u8]>,
) -> Self {
let mut ptr = alloc::alloc(layout);
if ptr.is_null() {
alloc::handle_alloc_error(layout);
}
for slice in slices {
ptr.copy_from_nonoverlapping(slice.as_ptr(), slice.len());
ptr = ptr.add(slice.len());
}
ptr = ptr.sub(layout.size());
let ptr = ptr::slice_from_raw_parts_mut(ptr, layout.size());
Self {
data: Box::from_raw(ptr),
align: layout.align(),
}
}
fn layout(&self) -> alloc::Layout {
unsafe {
alloc::Layout::from_size_align_unchecked(self.data.len(), self.align)
}
}
fn as_slice(&self) -> &[u8] {
self.data.as_ref()
}
fn into_raw_parts(self) -> (*mut u8, usize) {
let len = self.data.len();
let ptr = ManuallyDrop::new(self).data.as_mut_ptr();
(ptr, len)
}
}
impl Drop for AlignedBox {
fn drop(&mut self) {
let len = self.data.len();
if len == 0 {
return;
}
let ptr =
ManuallyDrop::new(mem::replace(&mut self.data, [].into())).as_mut_ptr();
unsafe {
alloc::dealloc(
ptr,
alloc::Layout::from_size_align_unchecked(len, self.align),
)
}
}
}