1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! This module define the [Memory] struct and its implementation.

use std::ops::{Index, IndexMut};

use crate::data::atomic::Word;
use crate::data::composite::Array;
use crate::data::identification::{Address, Area, Identifier};

/// Describes the full memory available for a machine.
#[derive(Clone, Default, Debug)]
pub struct Memory {
    data: Vec<Word>,
}

/// Represents an error occurring during a memory operation.
#[derive(Debug)]
pub enum MemoryError {
    /// A memory operation requested a position out of valid (allocated) memory.
    OutOfBounds { requested: usize, memory_len: usize },
    /// Requested to free more memory than allocated.
    CannotFree { trying_to_free: usize, memory_len: usize },
}

/// The result of some memory operations which can fail.
pub type MemoryResult<T> = Result<T, MemoryError>;

impl Memory {
    /// Creates an empty (no allocation) memory.
    pub fn new() -> Self { Self::default() }

    /// Creates a memory with an arbitrary size.
    pub fn with_size(size: usize) -> Self {
        let mut mem = Self::default();
        mem.data.resize(size, Word::default());
        mem
    }

    /// The total memory size.
    pub fn len(&self) -> usize { self.data.len() }
    
    /// Returns `true` if the size of the memory is 0. 
    pub fn is_empty(&self) -> bool { self.data.is_empty() }

    /// Write a [Word] into the memory at the specified [Address].
    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(())
        }
    }

    /// Reads a [Word] from the memory at the specified [Address].
    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()])
        }
    }

    /// Reads a full [Array] from the memory between the specified [Address]es.
    pub fn array(&self, area: Area) -> MemoryResult<Array> {
        let slice = self.slice(area)?;
        Ok(Array::from(slice))
    }

    /// Reads a full sliced-[Array] from the memory between the specified [Address]es.
    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])
        }
    }

    /// Writes a full [Array] into the memory to the specified [Address].
    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(())
        }
    }

    /// Grow the memory with the specified size.
    pub fn alloc(&mut self, additional_size: usize) {
        self.data.resize(self.data.len() + additional_size, Word::default());
    }

    /// Free the memory from the specified size.
    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()] }
}