use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::mem::take;
use core::ops::Deref;
use core::str::FromStr;
use crate::alloc::alloc::{Allocator, Global};
use crate::alloc::clone::TryClone;
use crate::alloc::iter::TryFromIteratorIn;
use crate::alloc::{self, Vec};
use crate::item::{ComponentRef, IntoComponent, Item, Iter};
#[repr(transparent)]
pub struct ItemBuf<A: Allocator = Global> {
content: Vec<u8, A>,
}
impl<A: Allocator> ItemBuf<A> {
pub(crate) const fn new_in(alloc: A) -> Self {
Self {
content: Vec::new_in(alloc),
}
}
pub(super) const unsafe fn from_raw(content: Vec<u8, A>) -> Self {
Self { content }
}
pub(crate) fn with_item_in(
iter: impl IntoIterator<Item: IntoComponent>,
alloc: A,
) -> alloc::Result<Self> {
let mut content = Vec::new_in(alloc);
for c in iter {
c.write_component(&mut content)?;
}
Ok(Self { content })
}
pub fn push<C>(&mut self, c: C) -> alloc::Result<()>
where
C: IntoComponent,
{
c.write_component(&mut self.content)?;
Ok(())
}
pub fn pop(&mut self) -> bool {
let mut it = self.iter();
if it.next_back().is_none() {
return false;
};
let new_len = it.len();
unsafe {
debug_assert!(new_len < self.content.len());
self.content.set_len(new_len);
}
true
}
pub fn extend<I>(&mut self, i: I) -> alloc::Result<()>
where
I: IntoIterator,
I::Item: IntoComponent,
{
for c in i {
self.push(c)?;
}
Ok(())
}
pub fn clear(&mut self) {
self.content.clear();
}
}
impl ItemBuf {
pub const fn new() -> Self {
Self {
content: Vec::new(),
}
}
pub fn with_item(iter: impl IntoIterator<Item: IntoComponent>) -> alloc::Result<Self> {
Self::with_item_in(iter, Global)
}
pub fn with_crate(name: &str) -> alloc::Result<Self> {
Self::with_item(&[ComponentRef::Crate(name)])
}
pub fn with_crate_item<I>(name: &str, iter: I) -> alloc::Result<Self>
where
I: IntoIterator,
I::Item: IntoComponent,
{
let mut content = Vec::new();
ComponentRef::Crate(name).write_component(&mut content)?;
for c in iter {
c.write_component(&mut content)?;
}
Ok(Self { content })
}
}
impl<A: Allocator> Default for ItemBuf<A>
where
A: Default,
{
fn default() -> Self {
Self {
content: Vec::new_in(A::default()),
}
}
}
impl<A: Allocator> PartialEq for ItemBuf<A> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.content == other.content
}
}
impl<A: Allocator> Eq for ItemBuf<A> {}
impl<A: Allocator> PartialOrd for ItemBuf<A> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<A: Allocator> Ord for ItemBuf<A> {
fn cmp(&self, other: &Self) -> Ordering {
self.content.cmp(&other.content)
}
}
impl<A: Allocator> Hash for ItemBuf<A> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.content.hash(state);
}
}
impl<A: Allocator + Clone> TryClone for ItemBuf<A> {
#[inline]
fn try_clone(&self) -> alloc::Result<Self> {
Ok(Self {
content: self.content.try_clone()?,
})
}
}
impl<A: Allocator> AsRef<Item> for ItemBuf<A> {
#[inline]
fn as_ref(&self) -> &Item {
self
}
}
impl<A: Allocator> Borrow<Item> for ItemBuf<A> {
#[inline]
fn borrow(&self) -> &Item {
self
}
}
impl<C, A: Allocator> TryFromIteratorIn<C, A> for ItemBuf<A>
where
C: IntoComponent,
{
#[inline]
fn try_from_iter_in<T: IntoIterator<Item = C>>(iter: T, alloc: A) -> alloc::Result<Self> {
Self::with_item_in(iter, alloc)
}
}
impl<A: Allocator> Deref for ItemBuf<A> {
type Target = Item;
fn deref(&self) -> &Self::Target {
unsafe { Item::from_bytes(self.content.as_ref()) }
}
}
impl<A: Allocator> fmt::Display for ItemBuf<A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Item::fmt(self, f)
}
}
impl<A: Allocator> fmt::Debug for ItemBuf<A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Item::fmt(self, f)
}
}
impl<'a, A: Allocator> IntoIterator for &'a ItemBuf<A> {
type IntoIter = Iter<'a>;
type Item = ComponentRef<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<A: Allocator> PartialEq<Item> for ItemBuf<A> {
fn eq(&self, other: &Item) -> bool {
self.content.as_slice() == other.as_bytes()
}
}
impl<A: Allocator> PartialEq<Item> for &ItemBuf<A> {
fn eq(&self, other: &Item) -> bool {
self.content.as_slice() == other.as_bytes()
}
}
impl<A: Allocator> PartialEq<&Item> for ItemBuf<A> {
fn eq(&self, other: &&Item) -> bool {
self.content.as_slice() == other.as_bytes()
}
}
impl<A: Allocator> PartialEq<Iter<'_>> for ItemBuf<A> {
fn eq(&self, other: &Iter<'_>) -> bool {
self == other.as_item()
}
}
impl<A: Allocator> PartialEq<Iter<'_>> for &ItemBuf<A> {
fn eq(&self, other: &Iter<'_>) -> bool {
*self == other.as_item()
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct FromStrError {
kind: FromStrErrorKind,
}
impl From<alloc::Error> for FromStrError {
fn from(error: alloc::Error) -> Self {
Self {
kind: FromStrErrorKind::AllocError(error),
}
}
}
impl From<FromStrErrorKind> for FromStrError {
fn from(kind: FromStrErrorKind) -> Self {
Self { kind }
}
}
#[derive(Debug)]
enum FromStrErrorKind {
ParseError,
AllocError(alloc::Error),
}
impl fmt::Display for FromStrError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.kind {
FromStrErrorKind::ParseError => write!(f, "String is not a valid item"),
FromStrErrorKind::AllocError(error) => error.fmt(f),
}
}
}
impl core::error::Error for FromStrError {}
impl<A: Allocator> FromStr for ItemBuf<A>
where
A: Default,
{
type Err = FromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut item = ItemBuf::new_in(A::default());
let (s, mut next_crate) = if let Some(remainder) = s.strip_prefix("::") {
(remainder, true)
} else {
(s, false)
};
for c in s.split("::") {
if take(&mut next_crate) {
item.push(ComponentRef::Crate(c))?;
} else if let Some(num) = c.strip_prefix('$') {
item.push(ComponentRef::Id(
num.parse().map_err(|_| FromStrErrorKind::ParseError)?,
))?;
} else {
item.push(ComponentRef::Str(c))?;
}
}
Ok(item)
}
}