use core::fmt;
#[cfg(feature = "alloc")]
use crate::alloc::borrow::TryToOwned;
#[cfg(feature = "alloc")]
use crate::alloc::iter::IteratorExt;
#[cfg(feature = "alloc")]
use crate::alloc::{self, Vec};
#[cfg(feature = "alloc")]
use crate::item::Component;
use crate::item::{ComponentRef, IntoComponent, ItemBuf, Iter};
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Item {
content: [u8],
}
impl Item {
#[inline]
pub const fn new() -> &'static Self {
unsafe { Self::from_bytes(&[]) }
}
pub const unsafe fn from_bytes(content: &[u8]) -> &Self {
&*(content as *const _ as *const _)
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.content
}
pub fn as_crate(&self) -> Option<&str> {
if let Some(ComponentRef::Crate(s)) = self.iter().next() {
Some(s)
} else {
None
}
}
#[inline]
pub fn first(&self) -> Option<ComponentRef<'_>> {
self.iter().next()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.content.is_empty()
}
#[cfg(feature = "alloc")]
pub fn as_vec(&self) -> alloc::Result<Vec<Component>> {
self.iter()
.map(ComponentRef::into_component)
.try_collect::<Result<Vec<_>, _>>()?
}
pub fn as_local(&self) -> Option<&str> {
let mut it = self.iter();
match it.next_back_str() {
Some(last) if it.is_empty() => Some(last),
_ => None,
}
}
pub fn join(&self, other: impl IntoIterator<Item: IntoComponent>) -> alloc::Result<ItemBuf> {
let mut content = self.content.try_to_owned()?;
for c in other {
c.write_component(&mut content)?;
}
Ok(unsafe { ItemBuf::from_raw(content) })
}
pub fn extended<C>(&self, part: C) -> alloc::Result<ItemBuf>
where
C: IntoComponent,
{
let mut content = self.content.try_to_owned()?;
part.write_component(&mut content)?;
Ok(unsafe { ItemBuf::from_raw(content) })
}
#[inline]
pub fn last(&self) -> Option<ComponentRef<'_>> {
self.iter().next_back()
}
#[inline]
pub fn base_name(&self) -> Option<&str> {
self.iter().next_back()?.as_str()
}
#[inline]
pub fn iter(&self) -> Iter<'_> {
Iter::new(&self.content)
}
#[inline]
pub fn starts_with<U>(&self, other: U) -> bool
where
U: AsRef<Item>,
{
self.content.starts_with(&other.as_ref().content)
}
pub fn is_super_of<U>(&self, other: U, n: usize) -> bool
where
U: AsRef<Item>,
{
let other = other.as_ref();
if self == other {
return true;
}
let mut it = other.iter();
for _ in 0..n {
if it.next_back().is_none() {
return false;
}
if self == it {
return true;
}
}
false
}
pub fn ancestry<U>(&self, other: U) -> alloc::Result<(ItemBuf, ItemBuf)>
where
U: AsRef<Item>,
{
let mut a = self.iter();
let other = other.as_ref();
let mut b = other.iter();
let mut shared = ItemBuf::new();
let mut suffix = ItemBuf::new();
while let Some(v) = b.next() {
if let Some(u) = a.next() {
if u == v {
shared.push(v)?;
continue;
} else {
suffix.push(v)?;
suffix.extend(b)?;
return Ok((shared, suffix));
}
}
suffix.push(v)?;
break;
}
suffix.extend(b)?;
Ok((shared, suffix))
}
pub fn parent(&self) -> Option<&Item> {
let mut it = self.iter();
it.next_back()?;
Some(it.into_item())
}
pub fn unqalified(&self) -> Unqalified<'_> {
Unqalified::new(self)
}
}
impl AsRef<Item> for &Item {
#[inline]
fn as_ref(&self) -> &Item {
self
}
}
impl Default for &Item {
#[inline]
fn default() -> Self {
Item::new()
}
}
#[cfg(feature = "alloc")]
impl TryToOwned for Item {
type Owned = ItemBuf;
#[inline]
fn try_to_owned(&self) -> alloc::Result<Self::Owned> {
Ok(unsafe { ItemBuf::from_raw(self.content.try_to_owned()?) })
}
}
impl fmt::Display for Item {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut it = self.iter();
if let Some(last) = it.next_back() {
for p in it {
write!(f, "{}::", p)?;
}
write!(f, "{}", last)?;
} else {
f.write_str("{root}")?;
}
Ok(())
}
}
impl fmt::Debug for Item {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self)
}
}
impl<'a> IntoIterator for &'a Item {
type IntoIter = Iter<'a>;
type Item = ComponentRef<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl PartialEq<ItemBuf> for Item {
fn eq(&self, other: &ItemBuf) -> bool {
self.content == other.content
}
}
impl PartialEq<ItemBuf> for &Item {
fn eq(&self, other: &ItemBuf) -> bool {
self.content == other.content
}
}
impl PartialEq<Iter<'_>> for Item {
fn eq(&self, other: &Iter<'_>) -> bool {
self == other.as_item()
}
}
impl PartialEq<Iter<'_>> for &Item {
fn eq(&self, other: &Iter<'_>) -> bool {
*self == other.as_item()
}
}
pub struct Unqalified<'a> {
item: &'a Item,
}
impl<'a> Unqalified<'a> {
fn new(item: &'a Item) -> Self {
Self { item }
}
}
impl fmt::Display for Unqalified<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut it = self.item.iter();
if let Some(last) = it.next_back() {
for c in it {
match c {
ComponentRef::Crate(name) => {
write!(f, "{name}::")?;
}
ComponentRef::Str(name) => {
write!(f, "{name}::")?;
}
c => {
write!(f, "{c}::")?;
}
}
}
write!(f, "{}", last)?;
} else {
f.write_str("{root}")?;
}
Ok(())
}
}