from __future__ import annotations

from .formatting import h16


class DecodeError(Exception):
    pass


class Rom:
    def __init__(self, data: bytes, base: int = 0) -> None:
        self.data = data
        self.base = base

    @property
    def end(self) -> int:
        return self.base + len(self.data)

    def offset(self, address: int) -> int:
        return address - self.base

    def contains(self, address: int, size: int = 1) -> bool:
        off = self.offset(address)
        return 0 <= off and off + size <= len(self.data)

    def u8(self, address: int) -> int:
        if not self.contains(address):
            raise DecodeError(f"address out of ROM: {h16(address)}")
        return self.data[self.offset(address)]

    def u16(self, address: int) -> int:
        if not self.contains(address, 2):
            raise DecodeError(f"word out of ROM: {h16(address)}")
        off = self.offset(address)
        return (self.data[off] << 8) | self.data[off + 1]

    def slice(self, address: int, size: int) -> bytes:
        if not self.contains(address, size):
            raise DecodeError(f"range out of ROM: {h16(address)}+{size}")
        off = self.offset(address)
        return self.data[off : off + size]

