use core::{fmt::Debug, marker::PhantomData};
use scroll::{
ctx::{MeasureWith, TryFromCtx, TryIntoCtx},
Pwrite,
};
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct ReadIterator<'a, Ctx, Type> {
pub bytes: Option<&'a [u8]>,
_phantom: PhantomData<(Ctx, Type)>,
}
impl<'a, Ctx, Type> ReadIterator<'a, Ctx, Type> {
pub const fn new(bytes: &'a [u8]) -> Self {
Self {
bytes: Some(bytes),
_phantom: PhantomData,
}
}
}
impl<Ctx, Type> TryIntoCtx for ReadIterator<'_, Ctx, Type> {
type Error = scroll::Error;
fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
buf.pwrite(self.bytes.unwrap_or_default(), 0)
}
}
impl<Ctx, Type> MeasureWith<()> for ReadIterator<'_, Ctx, Type> {
fn measure_with(&self, _ctx: &()) -> usize {
self.bytes.unwrap_or_default().len()
}
}
impl<'a, Ctx: Default + Copy, Type: TryFromCtx<'a, Ctx, Error = scroll::Error> + Debug + Copy> Debug
for ReadIterator<'a, Ctx, Type>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_list().entries(*self).finish()
}
}
#[cfg(feature = "defmt")]
impl<
'a,
Ctx: Default + Copy,
Type: TryFromCtx<'a, Ctx, Error = scroll::Error> + defmt::Format + Copy,
> defmt::Format for ReadIterator<'a, Ctx, Type>
{
fn format(&self, fmt: defmt::Formatter) {
let mut iter = *self;
defmt::write!(fmt, "[");
if let Some(first) = iter.next() {
defmt::write!(fmt, "{}", first);
for next in iter {
defmt::write!(fmt, ", {}", next);
}
}
defmt::write!(fmt, "]");
}
}
impl<'a, Ctx: Default + Copy, Type: TryFromCtx<'a, Ctx, Error = scroll::Error>> Iterator
for ReadIterator<'a, Ctx, Type>
{
type Item = Type;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let bytes = self.bytes?;
match Type::try_from_ctx(bytes, Ctx::default()) {
Ok((ret, offset)) => {
self.bytes = Some(&bytes[offset..]);
Some(ret)
}
Err(_) => {
self.bytes = None;
None
}
}
}
}
impl<
'a,
Ctx: Default + Copy,
Type: MeasureWith<()> + TryFromCtx<'a, Ctx, Error = scroll::Error>,
> ExactSizeIterator for ReadIterator<'a, Ctx, Type>
{
fn len(&self) -> usize {
self.bytes.map(|bytes| bytes.len()).unwrap_or_default()
}
}