xo65 0.1.0

Library for parsing cc65 object files (xo65 format)
Documentation
use crate::parse::{parse_bail, parse_uleb128_at, ParseAt, ParseErrorContext as _, ParseResult};
use crate::xo65::Xo65Bytes;

#[derive(Debug)]
pub struct MetadataTable<'data> {
    bytes: Xo65Bytes<'data>,

    metas: Box<[Metadata]>,
}

impl<'data> MetadataTable<'data> {
    pub fn as_bytes(&self) -> &'data [u8] {
        self.bytes.as_inner()
    }

    pub fn count(&self) -> usize {
        self.metas.len()
    }

    pub fn get(&self, idx: usize) -> Option<&Metadata> {
        self.metas.get(idx)
    }

    pub fn iter(
        &self,
    ) -> impl DoubleEndedIterator<Item = &Metadata> + ExactSizeIterator + std::iter::FusedIterator + Clone
    {
        self.metas.iter()
    }

    pub(crate) fn parse(bytes: Xo65Bytes<'data>) -> ParseResult<Self> {
        let mut off = 0;

        let count = parse_uleb128_at(&bytes, &mut off)? as usize;
        let mut metas = Vec::<Metadata>::with_capacity(count);

        for i in 0..count {
            let meta = Metadata::parse_at(&bytes, &mut off)
                .with_context(|| format!("metadata {i} parse error"))?;
            metas.push(meta);
        }

        Ok(Self {
            bytes,
            metas: metas.into(),
        })
    }
}

#[derive(Debug)]
pub enum Metadata {
    Comment { str_idx: u32 },
    Author { str_idx: u32 },
    Translator { str_idx: u32 },
    Compiler { str_idx: u32 },
    Os { str_idx: u32 },
    DateTime { unix_time: i32 },
}

impl ParseAt<'_> for Metadata {
    fn parse_at(bytes: &Xo65Bytes<'_>, off: &mut usize) -> ParseResult<Self> {
        let kind = u8::parse_at(bytes, off)?;
        let value = parse_uleb128_at(bytes, off)?;

        let meta = match kind {
            0x00 => Self::Comment { str_idx: value },
            0x01 => Self::Author { str_idx: value },
            0x02 => Self::Translator { str_idx: value },
            0x03 => Self::Compiler { str_idx: value },
            0x04 => Self::Os { str_idx: value },
            0x40 => Self::DateTime {
                unix_time: value.cast_signed(),
            },
            _ => parse_bail!("unknown metadata kind: {kind:#X}"),
        };

        Ok(meta)
    }
}