use core::slice;
use std::{str, vec::Vec};
#[derive(Default, Debug)]
pub struct CustomSections {
inner: CustomSectionsInner,
}
impl CustomSections {
#[inline]
pub fn iter(&self) -> CustomSectionsIter {
self.inner.iter()
}
}
#[derive(Default, Debug)]
pub struct CustomSectionsBuilder {
inner: CustomSectionsInner,
}
impl CustomSectionsBuilder {
#[inline]
pub fn push(&mut self, name: &str, data: &[u8]) {
self.inner.push(name, data);
}
#[inline]
pub fn finish(self) -> CustomSections {
CustomSections { inner: self.inner }
}
}
#[derive(Debug, Default)]
pub struct CustomSectionsInner {
items: Vec<CustomSectionInner>,
names_and_data: Vec<u8>,
}
#[derive(Debug, Copy, Clone)]
pub struct CustomSectionInner {
len_name: usize,
len_data: usize,
}
impl CustomSectionsInner {
#[inline]
pub fn push(&mut self, name: &str, data: &[u8]) {
let name_bytes = name.as_bytes();
self.names_and_data.extend_from_slice(name_bytes);
self.names_and_data.extend_from_slice(data);
self.items.push(CustomSectionInner {
len_name: name_bytes.len(),
len_data: data.len(),
})
}
#[inline]
pub fn iter(&self) -> CustomSectionsIter {
CustomSectionsIter {
items: self.items.iter(),
names_and_data: &self.names_and_data[..],
}
}
}
#[derive(Debug)]
pub struct CustomSection<'a> {
name: &'a str,
data: &'a [u8],
}
impl<'a> CustomSection<'a> {
#[inline]
pub fn name(&self) -> &'a str {
self.name
}
#[inline]
pub fn data(&self) -> &'a [u8] {
self.data
}
}
#[derive(Debug)]
pub struct CustomSectionsIter<'a> {
items: slice::Iter<'a, CustomSectionInner>,
names_and_data: &'a [u8],
}
impl<'a> Iterator for CustomSectionsIter<'a> {
type Item = CustomSection<'a>;
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.items.size_hint()
}
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let item = self.items.next()?;
let names_and_data = self.names_and_data;
let (name, names_and_data) = names_and_data.split_at(item.len_name);
let (data, names_and_data) = names_and_data.split_at(item.len_data);
self.names_and_data = names_and_data;
let name = unsafe { str::from_utf8_unchecked(name) };
Some(CustomSection { name, data })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let mut builder = CustomSectionsBuilder::default();
builder.push("A", b"first");
builder.push("B", b"second");
builder.push("C", b"third");
builder.push("", b"fourth"); builder.push("E", &[]); let custom_sections = builder.finish();
let mut iter = custom_sections.iter();
assert_eq!(
iter.next().map(|s| (s.name(), s.data())),
Some(("A", &b"first"[..]))
);
assert_eq!(
iter.next().map(|s| (s.name(), s.data())),
Some(("B", &b"second"[..]))
);
assert_eq!(
iter.next().map(|s| (s.name(), s.data())),
Some(("C", &b"third"[..]))
);
assert_eq!(
iter.next().map(|s| (s.name(), s.data())),
Some(("", &b"fourth"[..]))
);
assert_eq!(
iter.next().map(|s| (s.name(), s.data())),
Some(("E", &b""[..]))
);
assert_eq!(iter.next().map(|s| (s.name(), s.data())), None);
}
}