use core::{fmt, ops};
#[cfg(feature = "pyo3")]
use pyo3::prelude::*;
use crate::vram::VramOffset;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "pyo3", pyclass(module = "rabbitizer", eq, from_py_object))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Vram {
inner: u32,
}
impl Vram {
#[must_use]
pub const fn new(value: u32) -> Self {
Self { inner: value }
}
#[must_use]
pub const fn inner(&self) -> u32 {
self.inner
}
#[must_use]
pub const fn add_offset(&self, rhs: &VramOffset) -> Self {
Self::new(self.inner.wrapping_add_signed(rhs.inner()))
}
#[must_use]
pub const fn sub_vram(&self, rhs: &Self) -> VramOffset {
VramOffset::new((self.inner as i32).wrapping_sub_unsigned(rhs.inner()))
}
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn align_down(&self, alignment: u8) -> Self {
let shift = alignment.ilog2();
Self::new((self.inner >> shift) << shift)
}
}
impl ops::Add<VramOffset> for Vram {
type Output = Self;
fn add(self, rhs: VramOffset) -> Self::Output {
self.add_offset(&rhs)
}
}
impl ops::Add<&VramOffset> for Vram {
type Output = Self;
fn add(self, rhs: &VramOffset) -> Self::Output {
self.add_offset(rhs)
}
}
impl ops::AddAssign<VramOffset> for Vram {
fn add_assign(&mut self, rhs: VramOffset) {
*self = self.add_offset(&rhs)
}
}
impl ops::AddAssign<&VramOffset> for Vram {
fn add_assign(&mut self, rhs: &VramOffset) {
*self = self.add_offset(rhs)
}
}
impl ops::Sub<Self> for Vram {
type Output = VramOffset;
fn sub(self, rhs: Self) -> Self::Output {
self.sub_vram(&rhs)
}
}
impl ops::Sub<&Self> for Vram {
type Output = VramOffset;
fn sub(self, rhs: &Self) -> Self::Output {
self.sub_vram(rhs)
}
}
impl fmt::Debug for Vram {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Vram {{ 0x{:08X} }}", self.inner)
}
}
impl fmt::Display for Vram {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:08X}", self.inner)
}
}
#[cfg(feature = "pyo3")]
pub(crate) mod python_bindings {
use super::*;
#[pymethods]
impl Vram {
#[new]
#[must_use]
pub const fn py_new(value: u32) -> Self {
Self::new(value)
}
#[pyo3(name = "inner")]
#[must_use]
pub const fn py_inner(&self) -> u32 {
self.inner()
}
}
}