use std::ops::{Index, IndexMut};
use crate::data::atomic::Word;
use crate::data::composite::Array;
use crate::data::identification::{Address, Area, Identifier};
#[derive(Clone, Default, Debug)]
pub struct Memory {
data: Vec<Word>,
}
#[derive(Debug)]
pub enum MemoryError {
OutOfBounds { requested: usize, memory_len: usize },
CannotFree { trying_to_free: usize, memory_len: usize },
}
pub type MemoryResult<T> = Result<T, MemoryError>;
impl Memory {
pub fn new() -> Self { Self::default() }
pub fn with_size(size: usize) -> Self {
let mut mem = Self::default();
mem.data.resize(size, Word::default());
mem
}
pub fn len(&self) -> usize { self.data.len() }
pub fn is_empty(&self) -> bool { self.data.is_empty() }
pub fn store(&mut self, address: Address, datum: Word) -> MemoryResult<()> {
if address.to_usize() >= self.data.len() {
Err(MemoryError::OutOfBounds { requested: address.to_usize(), memory_len: self.len() })
} else {
self.data[address.to_usize()] = datum;
Ok(())
}
}
pub fn load(&self, address: Address) -> MemoryResult<Word> {
if address.to_usize() >= self.data.len() {
Err(MemoryError::OutOfBounds { requested: address.to_usize(), memory_len: self.len() })
} else {
Ok(self.data[address.to_usize()])
}
}
pub fn array(&self, area: Area) -> MemoryResult<Array> {
let slice = self.slice(area)?;
Ok(Array::from(slice))
}
pub fn slice(&self, area: Area) -> MemoryResult<&[Word]> {
let start = area.start().to_usize();
let end = area.end().to_usize();
if start >= self.data.len() || end >= self.data.len() {
Err(MemoryError::OutOfBounds { requested: start.max(end), memory_len: self.len() })
} else {
Ok(&self.data[start..=end])
}
}
pub fn copy(&mut self, to: Address, data: Array) -> MemoryResult<()> {
let start = to.to_usize();
let end = start + data.len();
if start >= self.data.len() || end >= self.data.len() {
Err(MemoryError::OutOfBounds { requested: start.max(end), memory_len: self.len() })
} else {
let mut current = start;
for datum in data.iter() {
self.data[current] = *datum;
current += 1;
};
Ok(())
}
}
pub fn alloc(&mut self, additional_size: usize) {
self.data.resize(self.data.len() + additional_size, Word::default());
}
pub fn free(&mut self, sub_size: usize) -> MemoryResult<()> {
if sub_size > self.data.len() {
return Err(MemoryError::CannotFree { trying_to_free: sub_size, memory_len: self.len() });
}
self.data.resize(self.data.len() - sub_size, Word::default());
Ok(())
}
}
impl Index<Address> for Memory {
type Output = Word;
fn index(&self, index: Address) -> &Self::Output { &self.data[index.to_usize()] }
}
impl IndexMut<Address> for Memory {
fn index_mut(&mut self, index: Address) -> &mut Self::Output { &mut self.data[index.to_usize()] }
}