use std::alloc::Layout;
use std::cmp::Ordering;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ptr::NonNull;
use std::slice;
use std::str;
use std::str::Utf8Error;
use crate::raw::RawYarn;
use crate::Utf8Chunks;
use crate::YarnRef;
#[cfg(doc)]
use crate::*;
#[repr(transparent)]
pub struct YarnBox<'a, Buf = [u8]>
where
Buf: crate::Buf + ?Sized,
{
raw: RawYarn,
_ph: PhantomData<&'a Buf>,
}
impl<'a, Buf> YarnBox<'a, Buf>
where
Buf: crate::Buf + ?Sized,
{
pub fn empty<'b>() -> &'b Self {
unsafe {
mem::transmute::<&'b RawYarn, &'b Self>(RawYarn::empty())
}
}
pub const fn new(buf: &'a Buf) -> Self {
YarnRef::new(buf).to_box()
}
pub const fn inlined(buf: &Buf) -> Option<Self> {
match YarnRef::inlined(buf) {
Some(y) => Some(y.to_box()),
None => None,
}
}
pub const fn aliased(&self) -> YarnBox<Buf> {
self.as_ref().to_box()
}
pub fn copy(buf: &Buf) -> Self {
YarnBox::new(buf).immortalize()
}
pub const fn from_char(c: char) -> Self {
YarnRef::<Buf>::from_char(c).to_box()
}
pub const fn is_empty(&self) -> bool {
self.as_ref().is_empty()
}
pub const fn len(&self) -> usize {
self.as_ref().len()
}
pub const fn as_slice(&self) -> &Buf {
unsafe {
buf_trait::as_buf(self.as_bytes())
}
}
pub const fn as_ref(&self) -> YarnRef<Buf> {
if let Some(inl) = YarnRef::inlined(self.as_slice()) {
return inl;
}
let raw = match self.raw.on_heap() {
true => unsafe {
RawYarn::alias_slice(
buf_trait::layout_of(self.as_slice()),
self.as_bytes().as_ptr(),
)
},
false => self.raw,
};
unsafe {
YarnRef::from_raw(raw)
}
}
pub const fn to_ref(&self) -> Option<YarnRef<'a, Buf>> {
if self.raw.on_heap() {
return None;
}
unsafe {
Some(YarnRef::from_raw(self.raw))
}
}
pub const fn as_bytes(&self) -> &[u8] {
self.raw.as_slice()
}
pub const fn into_bytes(self) -> YarnBox<'a, [u8]> {
unsafe {
YarnBox::from_raw(self.into_raw())
}
}
pub fn from_box(bytes: Box<Buf>) -> Self {
let raw = RawYarn::from_heap(bytes.into());
unsafe { Self::from_raw(raw) }
}
pub fn into_box(self) -> Box<Buf> {
if !self.raw.on_heap() {
unsafe {
let layout = buf_trait::layout_of(self.as_slice());
let ptr = match layout.size() {
0 => NonNull::<Buf::Element>::dangling().as_ptr() as *mut u8,
_ => std::alloc::alloc(layout),
};
if ptr.is_null() {
std::alloc::handle_alloc_error(layout);
}
let raw = self.into_raw();
ptr.copy_from_nonoverlapping(raw.as_slice().as_ptr(), raw.len());
return Box::from_raw(buf_trait::as_buf_mut(
slice::from_raw_parts_mut(ptr, raw.len()),
));
}
}
let mut raw = self.into_raw();
unsafe {
Box::from_raw(Buf::from_bytes_mut(raw.as_mut_slice()))
}
}
pub fn into_boxed_bytes(self) -> Box<[u8]> {
self.into_bytes().into_box()
}
pub fn into_byte_vec(self) -> Vec<u8> {
self.into_bytes().into_vec()
}
pub fn immortalize<'b>(self) -> YarnBox<'b, Buf> {
if self.raw.is_immortal() {
unsafe {
return YarnBox::from_raw(self.into_raw());
}
}
unsafe {
let raw = RawYarn::copy_slice(
buf_trait::layout_of(self.as_slice()),
self.as_slice() as *const Buf as *const u8,
);
YarnBox::from_raw(raw)
}
}
pub fn concat(bufs: &[impl AsRef<Buf>]) -> Self {
let total_len = bufs.iter().map(|b| b.as_ref().byte_len()).sum();
let iter = bufs.iter().map(|b| b.as_ref().as_bytes());
unsafe {
Self::from_raw(RawYarn::concat(
Layout::from_size_align_unchecked(
total_len,
mem::align_of::<Buf::Element>(),
),
iter,
))
}
}
pub fn inline_in_place(&mut self) {
if let Some(inlined) = Self::inlined(self.as_slice()) {
*self = inlined;
}
}
pub fn leak(&mut self) {
if !self.raw.on_heap() {
return;
}
unsafe {
self.raw = RawYarn::from_ptr_len_tag(
self.as_bytes().as_ptr(),
self.len(),
RawYarn::STATIC,
);
}
}
pub fn utf8_chunks(&self) -> Utf8Chunks {
Utf8Chunks::new(self.as_bytes())
}
pub(crate) const unsafe fn from_raw(raw: RawYarn) -> Self {
Self { raw, _ph: PhantomData }
}
pub(crate) const fn into_raw(self) -> RawYarn {
let raw = self.raw;
mem::forget(self);
raw
}
}
impl<Buf> YarnBox<'static, Buf>
where
Buf: crate::Buf + ?Sized,
{
pub const fn from_static(buf: &'static Buf) -> Self {
YarnRef::from_static(buf).to_box()
}
}
impl<'a> YarnBox<'a, [u8]> {
pub fn from_boxed_str(string: Box<str>) -> Self {
let raw = RawYarn::from_heap(string.into());
unsafe {
Self::from_raw(raw)
}
}
pub fn from_string(string: String) -> Self {
Self::from_boxed_str(string.into())
}
pub const fn from_byte(c: u8) -> Self {
YarnRef::from_byte(c).to_box()
}
pub fn to_utf8(self) -> Result<YarnBox<'a, str>, Utf8Error> {
self.to_utf8_or_bytes().map_err(|(_, e)| e)
}
pub fn to_utf8_or_bytes(self) -> Result<YarnBox<'a, str>, (Self, Utf8Error)> {
if let Err(e) = str::from_utf8(self.as_bytes()) {
return Err((self, e));
}
unsafe { Ok(YarnBox::from_raw(self.into_raw())) }
}
}
impl<'a, T> YarnBox<'a, [T]>
where
[T]: crate::Buf,
{
pub fn from_vec(bytes: Vec<T>) -> Self {
Self::from_box(bytes.into_boxed_slice())
}
pub fn into_vec(self) -> Vec<T> {
self.into_box().into()
}
pub fn try_mut(&mut self) -> Option<&mut [T]> {
self.inline_in_place();
if !self.raw.on_heap() && !self.raw.is_small() {
return None;
}
Some(self.as_mut())
}
#[allow(clippy::should_implement_trait)]
pub fn as_mut(&mut self) -> &mut [T] {
self.inline_in_place();
if !self.raw.on_heap() && !self.raw.is_small() {
*self = Self::from_box(mem::take(self).into_box());
}
unsafe { buf_trait::as_buf_mut(self.raw.as_mut_slice()) }
}
}
impl YarnBox<'_, str> {
pub fn from_boxed_str(string: Box<str>) -> Self {
let raw = RawYarn::from_heap(string.into());
unsafe {
Self::from_raw(raw)
}
}
pub fn from_string(string: String) -> Self {
Self::from_boxed_str(string.into())
}
pub fn from_fmt(args: fmt::Arguments) -> Self {
unsafe { YarnBox::from_raw(RawYarn::from_fmt_args(args)) }
}
pub fn as_str(&self) -> &str {
self.as_slice()
}
pub fn into_boxed_str(self) -> Box<str> {
self.into_string().into()
}
pub fn into_string(self) -> String {
unsafe { String::from_utf8_unchecked(self.into_bytes().into_vec()) }
}
}
impl<Buf> Deref for YarnBox<'_, Buf>
where
Buf: crate::Buf + ?Sized,
{
type Target = Buf;
fn deref(&self) -> &Buf {
self.as_slice()
}
}
impl<Buf> Drop for YarnBox<'_, Buf>
where
Buf: crate::Buf + ?Sized,
{
fn drop(&mut self) {
unsafe { self.raw.destroy(buf_trait::layout_of(self.as_slice())) }
}
}
impl<Buf> Clone for YarnBox<'_, Buf>
where
Buf: crate::Buf + ?Sized,
{
fn clone(&self) -> Self {
if let Some(yr) = self.to_ref() {
return yr.to_box();
}
unsafe {
let copy = RawYarn::copy_slice(
buf_trait::layout_of(self.as_slice()),
self.as_bytes().as_ptr(),
);
Self::from_raw(copy)
}
}
}
impl<Buf: crate::Buf + ?Sized> fmt::Debug for YarnBox<'_, Buf> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.as_ref(), f)
}
}
impl<Buf: crate::Buf + ?Sized> fmt::Display for YarnBox<'_, Buf> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.as_ref(), f)
}
}
impl<Slice, Buf> PartialEq<Slice> for YarnBox<'_, Buf>
where
Buf: crate::Buf + PartialEq + ?Sized,
Slice: AsRef<Buf> + ?Sized,
{
fn eq(&self, that: &Slice) -> bool {
self.as_slice() == that.as_ref()
}
}
impl<Buf: crate::Buf + Eq + ?Sized> Eq for YarnBox<'_, Buf> {}
impl<Slice, Buf> PartialOrd<Slice> for YarnBox<'_, Buf>
where
Buf: crate::Buf + PartialOrd + ?Sized,
Slice: AsRef<Buf> + ?Sized,
{
fn partial_cmp(&self, that: &Slice) -> Option<Ordering> {
self.as_slice().partial_cmp(that.as_ref())
}
}
impl<Buf: crate::Buf + Ord + ?Sized> Ord for YarnBox<'_, Buf> {
fn cmp(&self, that: &Self) -> Ordering {
self.as_slice().cmp(that.as_slice())
}
}
impl<Buf: crate::Buf + Hash + ?Sized> Hash for YarnBox<'_, Buf> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_slice().hash(state)
}
}
impl<Buf: crate::Buf + ?Sized> Default for YarnBox<'_, Buf> {
fn default() -> Self {
<&Self>::default().clone()
}
}
impl<Buf: crate::Buf + ?Sized> Default for &YarnBox<'_, Buf> {
fn default() -> Self {
YarnBox::empty()
}
}