use core::str;
use crate::item::internal;
use crate::item::{ComponentRef, Item, ItemBuf};
#[derive(Clone)]
pub struct Iter<'a> {
content: &'a [u8],
}
impl<'a> Iter<'a> {
pub(super) fn new(content: &'a [u8]) -> Self {
Self { content }
}
pub(super) fn len(&self) -> usize {
self.content.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.content.is_empty()
}
#[inline]
pub fn as_item(&self) -> &Item {
unsafe { Item::from_bytes(self.content) }
}
#[inline]
pub fn into_item(self) -> &'a Item {
unsafe { Item::from_bytes(self.content) }
}
pub fn next_str(&mut self) -> Option<&'a str> {
match self.next()? {
ComponentRef::Str(s) => Some(s),
_ => None,
}
}
pub fn next_back_str(&mut self) -> Option<&'a str> {
match self.next_back()? {
ComponentRef::Str(s) => Some(s),
_ => None,
}
}
}
impl<'a> Iterator for Iter<'a> {
type Item = ComponentRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.content.is_empty() {
return None;
}
let (head_tag, content) = self.content.split_at(internal::TAG_BYTES);
let (b, n) = internal::read_tag(head_tag);
let c = match b {
internal::CRATE => {
let (s, content, tail_tag) = internal::read_string(content, n);
debug_assert_eq!(head_tag, tail_tag);
self.content = content;
return Some(ComponentRef::Crate(s));
}
internal::STRING => {
let (s, content, tail_tag) = internal::read_string(content, n);
debug_assert_eq!(head_tag, tail_tag);
self.content = content;
return Some(ComponentRef::Str(s));
}
internal::ID => ComponentRef::Id(n),
internal::Tag(b) => panic!("unsupported control byte {:?}", b),
};
self.content = content;
Some(c)
}
}
impl DoubleEndedIterator for Iter<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.content.is_empty() {
return None;
}
let content = self.content;
let (content, tail) = content.split_at(
content
.len()
.checked_sub(internal::TAG_BYTES)
.expect("length underflow"),
);
let (b, n) = internal::read_tag(tail);
let c = match b {
internal::CRATE => {
let (s, content) = read_string_back(content, n);
self.content = content;
return Some(ComponentRef::Crate(s));
}
internal::STRING => {
let (s, content) = read_string_back(content, n);
self.content = content;
return Some(ComponentRef::Str(s));
}
internal::ID => ComponentRef::Id(n),
internal::Tag(b) => panic!("unsupported control byte {:?}", b),
};
self.content = content;
return Some(c);
fn read_string_back(content: &[u8], n: usize) -> (&str, &[u8]) {
let (content, buf) =
content.split_at(content.len().checked_sub(n).expect("length underflow"));
let (content, _) = content.split_at(
content
.len()
.checked_sub(internal::TAG_BYTES)
.expect("length underflow"),
);
let s = unsafe { str::from_utf8_unchecked(buf) };
(s, content)
}
}
}
impl PartialEq<ItemBuf> for Iter<'_> {
fn eq(&self, other: &ItemBuf) -> bool {
self.as_item() == other
}
}
impl PartialEq<Item> for Iter<'_> {
fn eq(&self, other: &Item) -> bool {
self.as_item() == other
}
}