yglnk-core 0.0.2

basic on-disk structured data helpers
Documentation
use super::{decode_location, trunc_key_at0};

#[derive(Clone, Copy, Debug)]
pub struct Entry<R> {
    pub name: R,
    pub typ: u32,
    pub location: u32,
    pub meta: u32,
    pub rest: R,
}

#[derive(Clone, Copy)]
pub struct Ref<'a> {
    cklen: usize,
    strtab: &'a [u8],
    data: &'a [u8],
}

impl<'a> Ref<'a> {
    pub fn parse(data: &'a [u8], location: u32) -> Option<Self> {
        let sel = decode_location(location)?;
        if data.len() < (sel + 16) {
            return None;
        }
        let sel = &data[sel..];
        let strtab_link = u32::from_be_bytes(sel[0..4].try_into().unwrap());
        let entcount = u16::from_be_bytes(sel[4..6].try_into().unwrap());
        let entsize = u16::from_be_bytes(sel[6..8].try_into().unwrap());
        let strtab_loc = decode_location(strtab_link)?;
        let dataspan = 16..(16 + 16 * usize::from(entsize) * usize::from(entcount));

        if data.len() <= strtab_loc || entsize == 0 {
            return None;
        }

        Some(Self {
            cklen: 16 * usize::from(entsize),
            strtab: &data[strtab_loc..],
            data: sel.get(dataspan)?,
        })
    }
}

impl<'a> Iterator for Ref<'a> {
    type Item = Entry<&'a [u8]>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.data.len() < self.cklen {
            debug_assert!(self.data.is_empty());
            return None;
        }
        let (i, j) = self.data.split_at(self.cklen);
        self.data = j;
        let name = usize::try_from(u32::from_be_bytes(i[0..4].try_into().unwrap())).unwrap();
        let name = trunc_key_at0(self.strtab.get(name..)?);
        Some(Entry {
            name,
            typ: u32::from_be_bytes(i[4..8].try_into().unwrap()),
            location: u32::from_be_bytes(i[8..12].try_into().unwrap()),
            meta: u32::from_be_bytes(i[12..16].try_into().unwrap()),
            rest: &i[16..],
        })
    }
}