reznez 0.0.0

The high accuracy NES Emulator
Documentation
use std::fmt;
use std::str::FromStr;

#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
pub struct CpuAddress(u16);

impl CpuAddress {
    pub const ZERO: CpuAddress = CpuAddress::new(0x0000);

    pub const fn new(value: u16) -> CpuAddress {
        CpuAddress(value)
    }

    pub fn from_low_high(low: u8, high: u8) -> CpuAddress {
        CpuAddress::new(((u16::from(high)) << 8) + (u16::from(low)))
    }

    pub fn zero_page(low: u8) -> CpuAddress {
        CpuAddress::new(u16::from(low))
    }

    pub const fn to_raw(self) -> u16 {
        self.0
    }

    pub fn to_usize(self) -> usize {
        usize::from(self.0)
    }

    pub fn to_low_high(self) -> (u8, u8) {
        (self.0 as u8, (self.0 >> 8) as u8)
    }

    pub fn low_byte(self) -> u8 {
        u8::try_from(self.0 & 0x00FF).unwrap()
    }

    pub fn high_byte(self) -> u8 {
        u8::try_from(self.0 >> 8).unwrap()
    }

    pub fn advance(self, value: u8) -> CpuAddress {
        CpuAddress::new(self.0.wrapping_add(u16::from(value)))
    }

    pub fn offset(self, value: i8) -> CpuAddress {
        CpuAddress::new((i32::from(self.0)).wrapping_add(i32::from(value)) as u16)
    }

    pub fn offset_with_carry(&mut self, value: i8) -> i8 {
        let temp = self.offset(value);
        let carry = (i16::from(temp.high_byte()) - i16::from(self.high_byte())) as i8;
        *self = CpuAddress::from_low_high(temp.low_byte(), self.high_byte());
        carry
    }

    pub fn offset_low(&mut self, value: u8) -> bool {
        let (low, high) = self.to_low_high();
        let (low, carry) = low.overflowing_add(value);
        *self = CpuAddress::from_low_high(low, high);
        carry
    }

    pub fn offset_high(&mut self, value: i8) {
        let (low, high) = self.to_low_high();
        let high = high.wrapping_add_signed(value);
        *self = CpuAddress::from_low_high(low, high);
    }

    pub fn inc(&mut self) -> CpuAddress {
        self.0 = self.0.wrapping_add(1);
        *self
    }

    pub fn page(self) -> u8 {
        (self.0 >> 8) as u8
    }

    pub fn index_within_page(self) -> u8 {
        self.0 as u8
    }

    pub fn is_end_of_page(self) -> bool {
        self.index_within_page() == 0xFF
    }

    pub fn is_odd(self) -> bool {
        self.0 % 2 == 1
    }
}

impl fmt::Display for CpuAddress {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "${:04X}", self.0)
    }
}

impl FromStr for CpuAddress {
    type Err = String;

    fn from_str(value: &str) -> Result<CpuAddress, String> {
        let raw = u16::from_str(value).map_err(|err| err.to_string())?;
        Ok(CpuAddress(raw))
    }
}