use essential_types::Word;
use crate::error::MemoryError;
#[cfg(test)]
mod tests;
#[derive(Clone, Default, Debug, PartialEq)]
pub struct Memory(Vec<Word>);
impl Memory {
pub const SIZE_LIMIT: usize = 1024 * 10;
pub fn new() -> Self {
Self::default()
}
pub fn alloc(&mut self, size: Word) -> Result<(), MemoryError> {
let size = usize::try_from(size).map_err(|_| MemoryError::Overflow)?;
let new_size = self
.0
.len()
.checked_add(size)
.ok_or(MemoryError::Overflow)?;
if new_size > Self::SIZE_LIMIT {
return Err(MemoryError::Overflow);
}
self.0.resize(new_size, 0);
Ok(())
}
pub fn store(&mut self, address: Word, value: Word) -> Result<(), MemoryError> {
let index = usize::try_from(address).map_err(|_| MemoryError::IndexOutOfBounds)?;
*self.0.get_mut(index).ok_or(MemoryError::IndexOutOfBounds)? = value;
Ok(())
}
pub fn load(&self, address: Word) -> Result<Word, MemoryError> {
let index = usize::try_from(address).map_err(|_| MemoryError::IndexOutOfBounds)?;
Ok(*self.0.get(index).ok_or(MemoryError::IndexOutOfBounds)?)
}
pub fn store_range(&mut self, address: Word, values: &[Word]) -> Result<(), MemoryError> {
let address = usize::try_from(address).map_err(|_| MemoryError::IndexOutOfBounds)?;
let end = address
.checked_add(values.len())
.ok_or(MemoryError::Overflow)?;
if end > self.0.len() {
return Err(MemoryError::IndexOutOfBounds);
}
self.0[address..end].copy_from_slice(values);
Ok(())
}
pub fn load_range(&self, address: Word, size: Word) -> Result<Vec<Word>, MemoryError> {
let address = usize::try_from(address).map_err(|_| MemoryError::IndexOutOfBounds)?;
let size = usize::try_from(size).map_err(|_| MemoryError::Overflow)?;
let end = address.checked_add(size).ok_or(MemoryError::Overflow)?;
if end > self.0.len() {
return Err(MemoryError::IndexOutOfBounds);
}
Ok(self.0[address..end].to_vec())
}
pub fn free(&mut self, new_len: Word) -> Result<(), MemoryError> {
let new_len = usize::try_from(new_len).map_err(|_| MemoryError::IndexOutOfBounds)?;
if new_len > self.0.len() {
return Err(MemoryError::IndexOutOfBounds);
}
self.0.truncate(new_len);
self.0.shrink_to_fit();
Ok(())
}
pub fn len(&self) -> Result<Word, MemoryError> {
self.0.len().try_into().map_err(|_| MemoryError::Overflow)
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl From<Memory> for Vec<Word> {
fn from(m: Memory) -> Vec<Word> {
m.0
}
}
impl TryFrom<Vec<Word>> for Memory {
type Error = MemoryError;
fn try_from(words: Vec<Word>) -> Result<Self, Self::Error> {
if words.len() > Self::SIZE_LIMIT {
Err(MemoryError::Overflow)
} else {
Ok(Self(words))
}
}
}
impl core::ops::Deref for Memory {
type Target = [Word];
fn deref(&self) -> &Self::Target {
&self.0
}
}