use crate::{read::Reader, wire::Wire};
use std::{fmt, iter::FusedIterator};
pub struct ListRef<'a, T: Wire> {
elements: Reader<'a>,
len: u64,
_marker: std::marker::PhantomData<T>,
}
impl<'a, T: Wire> ListRef<'a, T> {
pub(crate) fn new(elements: Reader<'a>, len: u64) -> Self {
ListRef {
elements,
len,
_marker: std::marker::PhantomData,
}
}
pub fn len(&self) -> usize {
usize::try_from(self.len).unwrap_or(usize::MAX)
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn iter(&self) -> ListIter<'a, T> {
ListIter {
elements: self.elements,
remaining: self.len,
_marker: std::marker::PhantomData,
}
}
pub fn get(&self, index: usize) -> Option<T::Ref<'a>> {
if index >= self.len() {
return None;
}
match T::FIXED_SIZE {
Some(size) => {
let start = index.checked_mul(size)?;
let end = start.checked_add(size)?;
Some(T::read_span(self.elements.slice(start, end)))
}
None => self.iter().nth(index),
}
}
pub fn as_bytes(&self) -> &'a [u8] {
self.elements.as_slice()
}
pub fn to_vec(&self) -> Vec<T::Owned> {
let mut elements = self.elements;
(0..self.len)
.map(|_| T::read_owned(&mut elements))
.collect()
}
}
impl<T: Wire> Clone for ListRef<'_, T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: Wire> Copy for ListRef<'_, T> {}
impl<T: Wire> PartialEq for ListRef<'_, T> {
fn eq(&self, other: &Self) -> bool {
self.len == other.len && self.as_bytes() == other.as_bytes()
}
}
impl<'a, T: Wire> IntoIterator for ListRef<'a, T> {
type Item = T::Ref<'a>;
type IntoIter = ListIter<'a, T>;
fn into_iter(self) -> ListIter<'a, T> {
self.iter()
}
}
impl<'a, T: Wire> fmt::Debug for ListRef<'a, T>
where
T::Ref<'a>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
pub struct ListIter<'a, T: Wire> {
elements: Reader<'a>,
remaining: u64,
_marker: std::marker::PhantomData<T>,
}
impl<T: Wire> Clone for ListIter<'_, T> {
fn clone(&self) -> Self {
ListIter {
elements: self.elements,
remaining: self.remaining,
_marker: std::marker::PhantomData,
}
}
}
impl<'a, T: Wire> Iterator for ListIter<'a, T> {
type Item = T::Ref<'a>;
fn next(&mut self) -> Option<T::Ref<'a>> {
if self.remaining == 0 {
return None;
}
self.remaining -= 1;
Some(T::read(&mut self.elements))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = usize::try_from(self.remaining).unwrap_or(usize::MAX);
(remaining, Some(remaining))
}
}
impl<T: Wire> ExactSizeIterator for ListIter<'_, T> {}
impl<T: Wire> FusedIterator for ListIter<'_, T> {}