use std::fmt::{Debug, Display};
use serde::{Deserialize, Serialize};
use crate::state::{Addr, Area};
pub type MemoryEntry = (Addr, Permissions, Vec<u8>);
#[derive(Clone, Default, PartialEq, Eq)]
pub struct MemoryState {
data: Box<[MemoryEntry]>,
}
struct DisplayBytesAsHex<'a>(&'a [u8]);
impl Debug for DisplayBytesAsHex<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}]", hex::encode(self.0))
}
}
impl Display for DisplayBytesAsHex<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", hex::encode(self.0))
}
}
impl Debug for MemoryState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut c = f.debug_struct("Memory");
for (addr, perms, data) in self.iter() {
c.field(&format!("0x{addr:X}({perms:?})"), &DisplayBytesAsHex(data));
}
c.finish()
}
}
impl Display for MemoryState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (addr, perms, data) in self.iter() {
let qualifier = match perms {
Permissions::Read => "R.Mem",
Permissions::ReadWrite => "RwMem",
Permissions::Execute => "X.Mem",
};
writeln!(f, "{}[0x{:X}] = {}", qualifier, addr, &DisplayBytesAsHex(data))?;
}
Ok(())
}
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Permissions {
Read,
ReadWrite,
Execute,
}
pub struct MemoryStateItemMut<'m> {
memory_state: &'m mut MemoryState,
index: usize,
}
impl MemoryStateItemMut<'_> {
#[inline]
pub fn set_data(&mut self, new_data: &[u8]) {
let vec = &mut self.memory_state.data[self.index].2;
vec.clear();
vec.extend_from_slice(new_data);
}
#[inline]
pub fn modify_data(&mut self, f: impl FnOnce(&mut [u8])) {
f(&mut self.memory_state.data[self.index].2)
}
#[inline]
pub fn crop_data(&mut self, max_size: usize) {
let vec = &mut self.memory_state.data[self.index].2;
if vec.len() > max_size {
self.memory_state.data[self.index].2.resize(max_size, 0)
}
}
#[inline]
pub fn set_addr(&mut self, new_addr: Addr) {
self.memory_state.data[self.index].0 = new_addr;
}
#[inline]
pub fn addr(&self) -> Addr {
self.memory_state.data[self.index].0
}
#[inline]
pub fn permissions(&self) -> Permissions {
self.memory_state.data[self.index].1
}
#[inline]
pub fn data(&self) -> &[u8] {
&self.memory_state.data[self.index].2
}
}
impl MemoryState {
#[inline]
pub fn new<I: Iterator<Item = MemoryEntry>>(items: I) -> MemoryState {
MemoryState {
data: items.collect(),
}
}
#[inline]
pub fn from_vec(data: Vec<MemoryEntry>) -> MemoryState {
MemoryState {
data: data.into_boxed_slice(),
}
}
#[inline]
pub fn get_mut(&mut self, index: usize) -> MemoryStateItemMut<'_> {
MemoryStateItemMut {
memory_state: self,
index,
}
}
#[inline]
pub fn iter(&self) -> std::slice::Iter<'_, MemoryEntry> {
self.data.iter()
}
#[inline]
pub fn areas(&self) -> impl ExactSizeIterator<Item = Area> + '_ {
self.data.iter().map(|(addr, _, data)| addr.into_area(data.len() as u64))
}
#[inline]
pub fn get(&self, index: usize) -> &MemoryEntry {
&self.data[index]
}
#[must_use]
#[inline]
pub fn get_checked(&self, index: usize) -> Option<&MemoryEntry> {
self.data.get(index)
}
#[must_use]
#[inline]
pub fn addr(&self, index: usize) -> Addr {
self.data[index].0
}
#[must_use]
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
#[must_use]
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}