use std::cmp::Ordering;
use std::fmt;
use std::fmt::Write;
use std::hash::Hash;
use std::hash::Hasher;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::str;
use std::str::Utf8Error;
use crate::raw::RawYarn;
use crate::Utf8Chunks;
use crate::YarnBox;
#[cfg(doc)]
use crate::*;
#[repr(transparent)]
pub struct YarnRef<'a, Buf>
where
Buf: crate::Buf + ?Sized,
{
raw: RawYarn,
_ph: PhantomData<&'a Buf>,
}
impl<'a, Buf> YarnRef<'a, Buf>
where
Buf: crate::Buf + ?Sized,
{
pub(crate) const unsafe fn from_raw(raw: RawYarn) -> Self {
debug_assert!(!raw.on_heap());
let yarn = Self { raw, _ph: PhantomData };
if cfg!(miri) {
let _slice = yarn.as_slice();
}
yarn
}
pub fn empty<'b>() -> &'b Self {
unsafe {
mem::transmute::<&'b RawYarn, &'b Self>(RawYarn::empty())
}
}
pub const fn new(buf: &'a Buf) -> Self {
unsafe {
let raw = RawYarn::alias_slice(
buf_trait::layout_of(buf),
buf as *const Buf as *const u8,
);
Self::from_raw(raw)
}
}
pub const fn inlined(buf: &Buf) -> Option<Self> {
let Some(raw) = RawYarn::from_slice_inlined(
buf_trait::layout_of(buf),
buf as *const Buf as *const u8,
) else {
return None;
};
unsafe {
Some(Self::from_raw(raw))
}
}
pub const fn from_char(c: char) -> Self {
let raw = RawYarn::from_char(c);
unsafe {
Self::from_raw(raw)
}
}
pub const fn is_empty(self) -> bool {
self.len() == 0
}
pub const fn len(self) -> usize {
self.raw.len()
}
pub const fn as_slice(&self) -> &Buf {
unsafe { buf_trait::as_buf(self.as_bytes()) }
}
pub const fn as_bytes(&self) -> &[u8] {
self.raw.as_slice()
}
pub const fn to_box(self) -> YarnBox<'a, Buf> {
unsafe {
YarnBox::from_raw(self.raw)
}
}
pub fn to_boxed_bytes(self) -> Box<[u8]> {
self.to_box().into_bytes().into_box()
}
pub fn to_byte_vec(self) -> Vec<u8> {
self.to_box().into_bytes().into_vec()
}
pub const fn into_bytes(self) -> YarnRef<'a, [u8]> {
unsafe {
YarnRef::from_raw(self.raw)
}
}
pub fn immortalize(self) -> Option<YarnRef<'static, Buf>> {
if !self.raw.is_immortal() {
return None;
}
unsafe {
Some(YarnRef::<'static, Buf>::from_raw(self.raw))
}
}
pub fn inline_in_place(&mut self) {
if let Some(inlined) = Self::inlined(self.as_slice()) {
*self = inlined;
}
}
pub fn utf8_chunks(&self) -> Utf8Chunks {
Utf8Chunks::new(self.as_bytes())
}
}
impl<Buf> YarnRef<'static, Buf>
where
Buf: crate::Buf + ?Sized,
{
pub const fn from_static(buf: &'static Buf) -> Self {
let raw = RawYarn::new(buf_trait::as_bytes(buf));
unsafe { Self::from_raw(raw) }
}
}
impl<'a> YarnRef<'a, [u8]> {
pub const fn from_byte(c: u8) -> Self {
let raw = RawYarn::from_byte(c);
unsafe { Self::from_raw(raw) }
}
pub fn to_utf8(self) -> Result<YarnRef<'a, str>, Utf8Error> {
str::from_utf8(self.as_bytes())?;
unsafe { Ok(YarnRef::from_raw(self.raw)) }
}
}
impl<'a> YarnRef<'a, str> {
pub fn as_str(&self) -> &str {
self.as_slice()
}
pub fn to_boxed_str(self) -> Box<str> {
self.to_box().into_boxed_str()
}
#[allow(clippy::inherent_to_string_shadow_display)]
pub fn to_string(self) -> String {
self.to_box().into_string()
}
}
impl<Buf> Deref for YarnRef<'_, Buf>
where
Buf: crate::Buf + ?Sized,
{
type Target = Buf;
fn deref(&self) -> &Buf {
self.as_slice()
}
}
impl<Buf> Copy for YarnRef<'_, Buf> where Buf: crate::Buf + ?Sized {}
impl<Buf> Clone for YarnRef<'_, Buf>
where
Buf: crate::Buf + ?Sized,
{
fn clone(&self) -> Self {
*self
}
}
impl<Buf: crate::Buf + ?Sized> fmt::Debug for YarnRef<'_, Buf> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\"")?;
for chunk in self.utf8_chunks() {
match chunk {
Ok(utf8) => write!(f, "{}", utf8.escape_debug())?,
Err(bytes) => {
for b in bytes {
write!(f, "\\x{:02X}", b)?;
}
}
}
}
write!(f, "\"")
}
}
impl<Buf: crate::Buf + ?Sized> fmt::Display for YarnRef<'_, Buf> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for chunk in self.utf8_chunks() {
match chunk {
Ok(utf8) => f.write_str(utf8)?,
Err(..) => f.write_char(char::REPLACEMENT_CHARACTER)?,
}
}
Ok(())
}
}
impl<Slice, Buf> PartialEq<Slice> for YarnRef<'_, 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 YarnRef<'_, Buf> {}
impl<Slice, Buf> PartialOrd<Slice> for YarnRef<'_, 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 YarnRef<'_, Buf> {
fn cmp(&self, that: &Self) -> Ordering {
self.as_slice().cmp(that.as_slice())
}
}
impl<Buf: crate::Buf + Hash + ?Sized> Hash for YarnRef<'_, Buf> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_slice().hash(state)
}
}
impl<Buf: crate::Buf + ?Sized> Default for YarnRef<'_, Buf> {
fn default() -> Self {
*<&Self>::default()
}
}
impl<Buf: crate::Buf + ?Sized> Default for &YarnRef<'_, Buf> {
fn default() -> Self {
YarnRef::empty()
}
}