use crate::{ALIGNMENT, DynSizedStructure, Header, increase_to_alignment};
use core::marker::PhantomData;
use core::mem;
#[derive(Clone, Debug)]
pub struct TagIter<'a, H: Header> {
next_tag_offset: usize,
buffer: &'a [u8],
_t: PhantomData<H>,
}
impl<'a, H: Header> TagIter<'a, H> {
#[must_use]
pub fn new(mem: &'a [u8]) -> Self {
assert_eq!(mem.as_ptr().align_offset(ALIGNMENT), 0);
TagIter {
next_tag_offset: 0,
buffer: mem,
_t: PhantomData,
}
}
}
impl<'a, H: Header + 'a> Iterator for TagIter<'a, H> {
type Item = &'a DynSizedStructure<H>;
fn next(&mut self) -> Option<Self::Item> {
if self.next_tag_offset == self.buffer.len() {
return None;
}
assert!(self.next_tag_offset < self.buffer.len());
let ptr = unsafe { self.buffer.as_ptr().add(self.next_tag_offset) }.cast::<H>();
let tag_hdr = unsafe { &*ptr };
let slice = {
let from = self.next_tag_offset;
let len = mem::size_of::<H>() + tag_hdr.payload_len();
let to = from + len;
let to = increase_to_alignment(to);
self.next_tag_offset += to - from;
&self.buffer[from..to]
};
let tag = DynSizedStructure::ref_from_slice(slice).unwrap();
Some(tag)
}
}
#[cfg(test)]
mod tests {
use crate::TagIter;
use crate::test_utils::{AlignedBytes, DummyTestHeader};
use core::borrow::Borrow;
#[test]
fn test_tag_iter() {
#[rustfmt::skip]
let bytes = AlignedBytes::new(
[
0xff, 0, 0, 0,
8, 0, 0, 0,
0xfe, 0, 0, 0,
12, 0, 0, 0,
1, 2, 3, 4,
0, 0, 0, 0,
0, 0, 0, 0,
8, 0, 0, 0,
],
);
let mut iter = TagIter::<DummyTestHeader>::new(bytes.borrow());
let first = iter.next().unwrap();
assert_eq!(first.header().typ(), 0xff);
assert_eq!(first.header().size(), 8);
assert!(first.payload().is_empty());
let second = iter.next().unwrap();
assert_eq!(second.header().typ(), 0xfe);
assert_eq!(second.header().size(), 12);
assert_eq!(&second.payload(), &[1, 2, 3, 4]);
let third = iter.next().unwrap();
assert_eq!(third.header().typ(), 0);
assert_eq!(third.header().size(), 8);
assert!(first.payload().is_empty());
assert_eq!(iter.next(), None);
}
}