Skip to main content

datex_core/runtime/
memory.rs

1use crate::{
2    collections::HashMap,
3    global::protocol_structures::instructions::RawRemotePointerAddress,
4    libs::core::{CoreLibPointerId, load_core_lib},
5    shared_values::{
6        shared_container::SharedContainer,
7        shared_type_container::SharedTypeContainer,
8        shared_value_container::SharedValueContainer,
9    },
10    types::error::IllegalTypeError,
11    values::core_values::endpoint::Endpoint,
12};
13use binrw::io::Cursor;
14use core::{cell::RefCell, result::Result};
15
16use crate::{
17    prelude::*,
18    shared_values::{
19        pointer::Pointer,
20        pointer_address::{
21            OwnedPointerAddress, PointerAddress, ReferencedPointerAddress,
22        },
23    },
24};
25
26#[derive(Debug, Default)]
27pub struct Memory {
28    local_endpoint: Endpoint,
29    local_counter: u64,  // counter for local pointer ids
30    last_timestamp: u64, // last timestamp used for a new local pointer id
31    pointers: HashMap<PointerAddress, SharedContainer>, // all pointers
32}
33
34impl Memory {
35    /// Creates a new, Memory instance with the core library loaded.
36    pub fn new(endpoint: Endpoint) -> Memory {
37        let mut memory = Memory {
38            local_endpoint: endpoint,
39            local_counter: 0,
40            last_timestamp: 0,
41            pointers: HashMap::new(),
42        };
43        // load core library
44        load_core_lib(&mut memory);
45        memory
46    }
47
48    /// Registers a new shared container in memory. If the reference has no PointerAddress, a new local one is generated.
49    /// If the reference is already registered (has a PointerAddress), the existing address is returned and no new registration is done.
50    /// Returns the PointerAddress of the registered reference.
51    pub fn register_shared_container(&mut self, reference: &SharedContainer) {
52        let pointer_address = reference.pointer_address();
53        // check if reference is already registered (if it has an address, we assume it is registered)
54        self.pointers
55            .entry(pointer_address)
56            .or_insert_with(|| reference.clone());
57    }
58
59    /// Returns a reference stored at the given PointerAddress, if it exists.
60    pub fn get_reference(
61        &self,
62        pointer_address: &PointerAddress,
63    ) -> Option<&SharedContainer> {
64        self.pointers.get(pointer_address)
65    }
66
67    pub fn get_value_reference(
68        &self,
69        pointer_address: &PointerAddress,
70    ) -> Option<&Rc<RefCell<SharedValueContainer>>> {
71        self.get_reference(pointer_address).and_then(|r| match r {
72            SharedContainer::Value(v) => Some(v),
73            _ => None,
74        })
75    }
76
77    pub fn get_type_reference(
78        &self,
79        pointer_address: &PointerAddress,
80    ) -> Option<&Rc<RefCell<SharedTypeContainer>>> {
81        self.get_reference(pointer_address).and_then(|r| match r {
82            SharedContainer::Type(t) => Some(t),
83            _ => None,
84        })
85    }
86
87    /// Helper function to get a core value directly from memory
88    pub fn get_core_reference(
89        &self,
90        pointer_id: CoreLibPointerId,
91    ) -> &SharedContainer {
92        self.get_reference(&pointer_id.into())
93            .expect("core reference not found in memory")
94    }
95
96    /// Helper function to get a core type directly from memory if it can be used as a type
97    pub fn get_core_type_reference(
98        &self,
99        pointer_id: CoreLibPointerId,
100    ) -> Result<Rc<RefCell<SharedTypeContainer>>, IllegalTypeError> {
101        let reference = self
102            .get_reference(&pointer_id.into())
103            .ok_or(IllegalTypeError::TypeNotFound)?;
104        match reference {
105            SharedContainer::Type(def) => Ok(def.clone()),
106            _ => Err(IllegalTypeError::TypeNotFound),
107        }
108    }
109
110    /// Helper function to get a core type directly from memory, asserting that is can be used as a type
111    /// Panics if the core type is not found or cannot be used as a type.
112    pub fn get_core_type_reference_unchecked(
113        &self,
114        pointer_id: CoreLibPointerId,
115    ) -> Rc<RefCell<SharedTypeContainer>> {
116        // FIXME #415: Mark as unchecked
117        self.get_core_type_reference(pointer_id)
118            .expect("core type not found or cannot be used as a type")
119    }
120
121    /// Takes a RawFullPointerAddress and converts it to a PointerAddress::Local or PointerAddress::Remote,
122    /// depending on whether the pointer origin id matches the local endpoint.
123    pub fn get_pointer_address_from_raw_full_address(
124        &self,
125        raw_address: RawRemotePointerAddress,
126    ) -> PointerAddress {
127        if let Ok(endpoint) = raw_address.endpoint()
128            && endpoint == self.local_endpoint
129        {
130            // TODO #639: check if it makes sense to take the last 5 bytes only here
131            let last_bytes = &raw_address.id[raw_address.id.len() - 5..];
132            PointerAddress::owned(last_bytes.try_into().unwrap())
133        } else {
134            // combine raw_address.endpoint and raw_address.id to [u8; 26]
135            let writer = Cursor::new(Vec::new());
136            let mut bytes = writer.into_inner();
137            bytes.extend_from_slice(&raw_address.id);
138            PointerAddress::Referenced(ReferencedPointerAddress::Remote(
139                <[u8; 26]>::try_from(bytes).unwrap(),
140            ))
141        }
142    }
143
144    /// Creates a new unique local owned pointer.
145    pub fn get_new_owned_local_pointer(&mut self) -> Pointer {
146        let timestamp = crate::time::now_ms();
147        // new timestamp, reset counter
148        if timestamp != self.last_timestamp {
149            self.last_timestamp = timestamp;
150            self.local_counter = 0;
151        }
152        // same timestamp as last time, increment counter to prevent collision
153        else {
154            self.local_counter += 1;
155        }
156        self.local_counter += 1;
157
158        // create id: 4 bytes timestamp + 1 byte counter
159        let id: [u8; 5] = [
160            (timestamp >> 24) as u8,
161            (timestamp >> 16) as u8,
162            (timestamp >> 8) as u8,
163            timestamp as u8,
164            (self.local_counter & 0xFF) as u8,
165        ];
166
167        Pointer::new_owned(OwnedPointerAddress::new(id))
168    }
169}