xo65 0.1.0

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

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

    imports: Box<[Import]>,
}

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

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

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

    pub fn iter(
        &self,
    ) -> impl DoubleEndedIterator<Item = &Import> + ExactSizeIterator + std::iter::FusedIterator + Clone
    {
        self.imports.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 imports = Vec::<Import>::with_capacity(count);

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

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

#[derive(Debug)]
pub struct Import {
    addr_size: u8,
    name: u32,
    def_lines: Box<[u32]>,
    ref_lines: Box<[u32]>,
}

impl Import {
    pub fn addr_size(&self) -> u8 {
        self.addr_size
    }

    pub fn name(&self) -> u32 {
        self.name
    }

    pub fn def_lines(&self) -> &[u32] {
        &self.def_lines
    }

    pub fn ref_lines(&self) -> &[u32] {
        &self.ref_lines
    }
}

impl ParseAt<'_> for Import {
    fn parse_at(bytes: &Xo65Bytes<'_>, off: &mut usize) -> ParseResult<Self> {
        let addr_size = u8::parse_at(bytes, off)?;
        let name = parse_uleb128_at(bytes, off)?;
        let def_lines = parse_lines_at(bytes, off)?;
        let ref_lines = parse_lines_at(bytes, off)?;

        Ok(Self {
            addr_size,
            name,
            def_lines,
            ref_lines,
        })
    }
}

fn parse_lines_at(bytes: &Xo65Bytes<'_>, off: &mut usize) -> ParseResult<Box<[u32]>> {
    let count = parse_uleb128_at(bytes, off)? as usize;
    let mut lines = Vec::<u32>::with_capacity(count);

    for _ in 0..count {
        let line = parse_uleb128_at(bytes, off)?;
        lines.push(line);
    }

    Ok(lines.into())
}