datex_core/runtime/
memory.rs

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