Skip to main content

cairo_vm/vm/vm_memory/
memory.rs

1use std::{borrow::Cow, collections::HashMap, fmt};
2
3use crate::types::errors::math_errors::MathError;
4use crate::vm::runners::cairo_pie::CairoPieMemory;
5use crate::Felt252;
6use crate::{
7    types::relocatable::{MaybeRelocatable, Relocatable},
8    utils::from_relocatable_to_indexes,
9    vm::errors::memory_errors::MemoryError,
10};
11use bitvec::prelude as bv;
12use core::cmp::Ordering;
13use num_traits::ToPrimitive;
14
15pub struct ValidationRule(
16    #[allow(clippy::type_complexity)]
17    pub  Box<dyn Fn(&Memory, Relocatable) -> Result<Vec<Relocatable>, MemoryError>>,
18);
19
20/// [`MemoryCell`] represents an optimized storage layout for the VM memory.
21/// It's specified to have both size an alignment of 32 bytes to optimize cache access.
22/// Typical cache sizes are 64 bytes, a few cases might be 128 bytes, meaning 32 bytes aligned to
23/// 32 bytes boundaries will never get split into two separate lines, avoiding double stalls and
24/// reducing false sharing and evictions.
25/// The trade off is extra computation for conversion to our "in-flight" `MaybeRelocatable` and
26/// `Felt252` as well as some extra copies. Empirically, this seems to be offset by the improved
27/// locality of the bigger structure for Lambdaworks. There is a big hit from the conversions when
28/// using the `BigUint` implementation, since those force allocations on the heap, but since that's
29/// dropped in later versions anyway it's not a priority. For Lambdaworks the new copies are mostly
30/// to the stack, which is typically already in the cache.
31/// The layout uses the 4 MSB in the first `u64` as flags:
32/// - BIT63: NONE flag, 1 when the cell is actually empty.
33/// - BIT62: ACCESS flag, 1 when the cell has been accessed in a way observable to Cairo.
34/// - BIT61: RELOCATABLE flag, 1 when the contained value is a `Relocatable`, 0 when it is a
35///   `Felt252`.
36///
37/// `Felt252` values are stored in big-endian order to keep the flag bits free.
38/// `Relocatable` values are stored as native endian, with the 3rd word storing the segment index
39/// and the 4th word storing the offset.
40#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd, Debug)]
41#[repr(align(32))]
42pub(crate) struct MemoryCell([u64; 4]);
43
44impl MemoryCell {
45    pub const NONE_MASK: u64 = 1 << 63;
46    pub const ACCESS_MASK: u64 = 1 << 62;
47    pub const RELOCATABLE_MASK: u64 = 1 << 61;
48    pub const NONE: Self = Self([Self::NONE_MASK, 0, 0, 0]);
49
50    pub fn new(value: MaybeRelocatable) -> Self {
51        value.into()
52    }
53
54    pub fn is_none(&self) -> bool {
55        self.0[0] & Self::NONE_MASK == Self::NONE_MASK
56    }
57
58    pub fn is_some(&self) -> bool {
59        !self.is_none()
60    }
61
62    pub fn mark_accessed(&mut self) {
63        self.0[0] |= Self::ACCESS_MASK;
64    }
65
66    pub fn is_accessed(&self) -> bool {
67        self.0[0] & Self::ACCESS_MASK == Self::ACCESS_MASK
68    }
69
70    pub fn get_value(&self) -> Option<MaybeRelocatable> {
71        self.is_some().then(|| (*self).into())
72    }
73}
74
75impl From<MaybeRelocatable> for MemoryCell {
76    fn from(value: MaybeRelocatable) -> Self {
77        match value {
78            MaybeRelocatable::Int(x) => Self(x.to_raw()),
79            MaybeRelocatable::RelocatableValue(x) => Self([
80                Self::RELOCATABLE_MASK,
81                0,
82                // NOTE: hack around signedness
83                usize::from_ne_bytes(x.segment_index.to_ne_bytes()) as u64,
84                x.offset as u64,
85            ]),
86        }
87    }
88}
89
90impl From<MemoryCell> for MaybeRelocatable {
91    fn from(cell: MemoryCell) -> Self {
92        debug_assert!(cell.is_some());
93        let flags = cell.0[0];
94        match flags & MemoryCell::RELOCATABLE_MASK {
95            MemoryCell::RELOCATABLE_MASK => Self::from((
96                // NOTE: hack around signedness
97                isize::from_ne_bytes((cell.0[2] as usize).to_ne_bytes()),
98                cell.0[3] as usize,
99            )),
100            _ => {
101                let mut value = cell.0;
102                // Remove all flag bits
103                value[0] &= 0x0fffffffffffffff;
104                Self::Int(Felt252::from_raw(value))
105            }
106        }
107    }
108}
109
110pub struct AddressSet(Vec<bv::BitVec>);
111
112impl AddressSet {
113    pub(crate) fn new() -> Self {
114        Self(Vec::new())
115    }
116
117    pub(crate) fn contains(&self, addr: &Relocatable) -> bool {
118        let segment = addr.segment_index;
119        if segment.is_negative() {
120            return false;
121        }
122
123        self.0
124            .get(segment as usize)
125            .and_then(|segment| segment.get(addr.offset))
126            .map(|bit| *bit)
127            .unwrap_or(false)
128    }
129
130    pub(crate) fn extend(&mut self, addresses: &[Relocatable]) {
131        for addr in addresses {
132            let segment = addr.segment_index;
133            if segment.is_negative() {
134                continue;
135            }
136            let segment = segment as usize;
137            if segment >= self.0.len() {
138                self.0.resize(segment + 1, bv::BitVec::new());
139            }
140
141            let offset = addr.offset;
142            if offset >= self.0[segment].len() {
143                self.0[segment].resize(offset + 1, false);
144            }
145            self.0[segment].replace(offset, true);
146        }
147    }
148}
149
150#[cfg(test)]
151impl AddressSet {
152    pub(crate) fn len(&self) -> usize {
153        self.0
154            .iter()
155            .map(|segment| segment.iter().map(|bit| *bit as usize).sum::<usize>())
156            .sum()
157    }
158}
159
160pub struct Memory {
161    pub(crate) data: Vec<Vec<MemoryCell>>,
162    /// Temporary segments are used when it's necessary to write data, but we
163    /// don't know yet where it will be located. These segments will eventually
164    /// be relocated to the main memory according to the `relocation_rules`. For
165    /// example, dictionaries are required to be contiguous, so each is stored in a
166    /// temporary segment and eventually relocated to a single segment.
167    pub(crate) temp_data: Vec<Vec<MemoryCell>>,
168    // relocation_rules's keys map to temp_data's indices and therefore begin at
169    // zero; that is, segment_index = -1 maps to key 0, -2 to key 1...
170    #[cfg(not(feature = "extensive_hints"))]
171    pub(crate) relocation_rules: HashMap<usize, Relocatable>,
172    #[cfg(feature = "extensive_hints")]
173    pub(crate) relocation_rules: HashMap<usize, MaybeRelocatable>,
174    pub validated_addresses: AddressSet,
175    validation_rules: Vec<Option<ValidationRule>>,
176}
177
178impl Memory {
179    pub fn new() -> Memory {
180        Memory {
181            data: Vec::new(),
182            temp_data: Vec::new(),
183            relocation_rules: HashMap::new(),
184            validated_addresses: AddressSet::new(),
185            validation_rules: Vec::with_capacity(7),
186        }
187    }
188
189    fn get_segment(&mut self, key: Relocatable) -> Result<&mut Vec<MemoryCell>, MemoryError> {
190        let (value_index, _) = from_relocatable_to_indexes(key);
191        let data = if key.segment_index.is_negative() {
192            &mut self.temp_data
193        } else {
194            &mut self.data
195        };
196        let data_len = data.len();
197        data.get_mut(value_index)
198            .ok_or_else(|| MemoryError::UnallocatedSegment(Box::new((value_index, data_len))))
199    }
200
201    /// Inserts a value into a memory address
202    /// Will return an Error if the segment index given by the address corresponds to a non-allocated segment,
203    /// or if the inserted value is inconsistent with the current value at the memory cell
204    /// If the address isnt contiguous with previously inserted data, memory gaps will be represented by None values
205    pub fn insert<V>(&mut self, key: Relocatable, val: V) -> Result<(), MemoryError>
206    where
207        MaybeRelocatable: From<V>,
208    {
209        let val = MaybeRelocatable::from(val);
210        let segment = self.get_segment(key)?;
211        let (_, value_offset) = from_relocatable_to_indexes(key);
212
213        //Check if the element is inserted next to the last one on the segment
214        //Forgoing this check would allow data to be inserted in a different index
215        let (len, capacity) = (segment.len(), segment.capacity());
216        if len <= value_offset {
217            let new_len = value_offset
218                .checked_add(1)
219                .ok_or(MemoryError::VecCapacityExceeded)?;
220            segment
221                .try_reserve(new_len.saturating_sub(capacity))
222                .map_err(|_| MemoryError::VecCapacityExceeded)?;
223            segment.resize(new_len, MemoryCell::NONE);
224        }
225        // At this point there's *something* in there
226
227        match segment[value_offset].get_value() {
228            None => segment[value_offset] = MemoryCell::new(val),
229            Some(current_cell) => {
230                if current_cell != val {
231                    //Existing memory cannot be changed
232                    return Err(MemoryError::InconsistentMemory(Box::new((
233                        key,
234                        current_cell,
235                        val,
236                    ))));
237                }
238            }
239        };
240        self.validate_memory_cell(key)
241    }
242
243    pub(crate) fn delete_unaccessed(&mut self, addr: Relocatable) -> Result<(), MemoryError> {
244        let (_, offset) = from_relocatable_to_indexes(addr);
245        let segment = self.get_segment(addr)?;
246
247        // Make sure the offset exists.
248        if offset >= segment.len() {
249            return Err(MemoryError::UnsetUnallocatedCell(addr));
250        }
251
252        // Ensure the cell has not been accessed.
253        if segment[offset].is_accessed() {
254            return Err(MemoryError::UnsetAccessedCell(addr));
255        }
256
257        // Unset the cell.
258        segment[offset] = MemoryCell::NONE;
259        Ok(())
260    }
261
262    /// Retrieve a value from memory (either normal or temporary) and apply relocation rules
263    pub(crate) fn get<'a, 'b: 'a, K: 'a>(&'b self, key: &'a K) -> Option<Cow<'b, MaybeRelocatable>>
264    where
265        Relocatable: TryFrom<&'a K>,
266    {
267        let relocatable: Relocatable = key.try_into().ok()?;
268        let value = self
269            .get_segment_cells(relocatable.segment_index)?
270            .get(relocatable.offset)?
271            .get_value()?;
272        Some(Cow::Owned(self.relocate_value(&value).ok()?.into_owned()))
273    }
274
275    // Version of Memory.relocate_value() that doesn't require a self reference
276    #[cfg(not(feature = "extensive_hints"))]
277    fn relocate_address(
278        addr: Relocatable,
279        relocation_rules: &HashMap<usize, Relocatable>,
280    ) -> Result<MaybeRelocatable, MemoryError> {
281        if addr.segment_index < 0 {
282            // Adjust the segment index to begin at zero, as per the struct field's
283            // comment.
284            if let Some(x) = relocation_rules.get(&(-(addr.segment_index + 1) as usize)) {
285                return Ok((*x + addr.offset)?.into());
286            }
287        }
288        Ok(addr.into())
289    }
290
291    #[cfg(feature = "extensive_hints")]
292    fn relocate_address(
293        addr: Relocatable,
294        relocation_rules: &HashMap<usize, MaybeRelocatable>,
295    ) -> Result<MaybeRelocatable, MemoryError> {
296        if addr.segment_index < 0 {
297            // Adjust the segment index to begin at zero, as per the struct field's
298            // comment.
299            if let Some(x) = relocation_rules.get(&(-(addr.segment_index + 1) as usize)) {
300                return Ok(match x {
301                    MaybeRelocatable::RelocatableValue(r) => (*r + addr.offset)?.into(),
302                    MaybeRelocatable::Int(i) => i.into(),
303                });
304            }
305        }
306        Ok(addr.into())
307    }
308
309    #[cfg(not(feature = "extensive_hints"))]
310    fn flatten_relocation_rules(&mut self) -> Result<(), MemoryError> {
311        let keys: Vec<usize> = self.relocation_rules.keys().copied().collect();
312        let max_hops = self.relocation_rules.len().saturating_add(1);
313        for key in keys {
314            let mut dst = *self
315                .relocation_rules
316                .get(&key)
317                .expect("key taken from keys vec must exist");
318
319            let mut hops = 0;
320            while dst.segment_index < 0 {
321                let next_key = (-(dst.segment_index + 1)) as usize;
322                let next = *self
323                    .relocation_rules
324                    .get(&next_key)
325                    .ok_or(MemoryError::UnmappedTemporarySegment(dst.segment_index))?;
326                dst = (next + dst.offset).map_err(MemoryError::Math)?;
327                hops += 1;
328                if hops > max_hops {
329                    return Err(MemoryError::Relocation); // cycle guard
330                }
331            }
332            self.relocation_rules.insert(key, dst);
333        }
334        Ok(())
335    }
336
337    #[cfg(feature = "extensive_hints")]
338    fn flatten_relocation_rules(&mut self) -> Result<(), MemoryError> {
339        let keys: Vec<usize> = self.relocation_rules.keys().copied().collect();
340        let max_hops = self.relocation_rules.len().saturating_add(1);
341        for key in keys {
342            let mut dst = self
343                .relocation_rules
344                .get(&key)
345                .expect("key taken from keys vec must exist")
346                .clone();
347
348            let mut hops = 0;
349            loop {
350                match dst {
351                    MaybeRelocatable::RelocatableValue(relocatable)
352                        if relocatable.segment_index < 0 =>
353                    {
354                        let next_key = (-(relocatable.segment_index + 1)) as usize;
355                        let next = self
356                            .relocation_rules
357                            .get(&next_key)
358                            .ok_or(MemoryError::UnmappedTemporarySegment(
359                                relocatable.segment_index,
360                            ))?
361                            .clone();
362
363                        match next {
364                            MaybeRelocatable::RelocatableValue(next_relocatable) => {
365                                dst = MaybeRelocatable::RelocatableValue(
366                                    (next_relocatable + relocatable.offset)
367                                        .map_err(MemoryError::Math)?,
368                                );
369                            }
370                            MaybeRelocatable::Int(i) => {
371                                if relocatable.offset != 0 {
372                                    return Err(MemoryError::NonZeroOffset(relocatable.offset));
373                                }
374                                dst = MaybeRelocatable::Int(i);
375                            }
376                        }
377                    }
378                    _ => break,
379                }
380                hops += 1;
381                if hops > max_hops {
382                    return Err(MemoryError::Relocation);
383                }
384            }
385            self.relocation_rules.insert(key, dst);
386        }
387        Ok(())
388    }
389
390    /// Relocates the memory according to the relocation rules and clears `self.relocaction_rules`.
391    pub fn relocate_memory(&mut self) -> Result<(), MemoryError> {
392        if self.relocation_rules.is_empty() || self.temp_data.is_empty() {
393            return Ok(());
394        }
395
396        // flatten chains (temp->temp->...->real).
397        self.flatten_relocation_rules()?;
398
399        // Relocate temporary addresses in memory
400        for segment in self.data.iter_mut().chain(self.temp_data.iter_mut()) {
401            for cell in segment.iter_mut() {
402                let value = cell.get_value();
403                match value {
404                    Some(MaybeRelocatable::RelocatableValue(addr)) if addr.segment_index < 0 => {
405                        let mut new_cell = MemoryCell::new(Memory::relocate_address(
406                            addr,
407                            &self.relocation_rules,
408                        )?);
409                        if cell.is_accessed() {
410                            new_cell.mark_accessed();
411                        }
412                        *cell = new_cell;
413                    }
414                    _ => {}
415                }
416            }
417        }
418        // Move relocated temporary memory into the real memory
419        for index in (0..self.temp_data.len()).rev() {
420            if let Some(base_addr) = self.relocation_rules.get(&index) {
421                let data_segment = self.temp_data.remove(index);
422
423                #[cfg(feature = "extensive_hints")]
424                let base_addr = match base_addr {
425                    MaybeRelocatable::RelocatableValue(addr) => addr,
426                    MaybeRelocatable::Int(_) => {
427                        continue;
428                    }
429                };
430
431                // Insert the to-be relocated segment into the real memory
432                let mut addr = *base_addr;
433                if let Some(s) = self.data.get_mut(addr.segment_index as usize) {
434                    s.reserve_exact(data_segment.len())
435                }
436                for cell in data_segment {
437                    if let Some(v) = cell.get_value() {
438                        // Rely on Memory::insert to catch memory inconsistencies
439                        self.insert(addr, v)?;
440                        // If the cell is accessed, mark the relocated one as accessed too
441                        if cell.is_accessed() {
442                            self.mark_as_accessed(addr)
443                        }
444                    }
445                    addr = (addr + 1)?;
446                }
447            }
448        }
449        self.relocation_rules.clear();
450        Ok(())
451    }
452
453    /// Add a new relocation rule.
454    ///
455    /// When using feature "extensive_hints" the destination is allowed to be an Integer (via
456    /// MaybeRelocatable). Relocating memory to anything other than a `Relocatable` is generally
457    /// not useful, but it does make the implementation consistent with the pythonic version.
458    ///
459    /// Will return an error if any of the following conditions are not met:
460    ///   - Source address's segment must be negative (temporary).
461    ///   - Source address's offset must be zero.
462    ///   - There shouldn't already be relocation at the source segment.
463    #[cfg(not(feature = "extensive_hints"))]
464    pub(crate) fn add_relocation_rule(
465        &mut self,
466        src_ptr: Relocatable,
467        dst_ptr: Relocatable,
468    ) -> Result<(), MemoryError> {
469        if src_ptr.segment_index >= 0 {
470            return Err(MemoryError::AddressNotInTemporarySegment(
471                src_ptr.segment_index,
472            ));
473        }
474        if src_ptr.offset != 0 {
475            return Err(MemoryError::NonZeroOffset(src_ptr.offset));
476        }
477
478        // Adjust the segment index to begin at zero, as per the struct field's
479        // comment.
480        let segment_index = -(src_ptr.segment_index + 1) as usize;
481        if self.relocation_rules.contains_key(&segment_index) {
482            return Err(MemoryError::DuplicatedRelocation(src_ptr.segment_index));
483        }
484
485        self.relocation_rules.insert(segment_index, dst_ptr);
486        Ok(())
487    }
488    #[cfg(feature = "extensive_hints")]
489    pub(crate) fn add_relocation_rule(
490        &mut self,
491        src_ptr: Relocatable,
492        dst: MaybeRelocatable,
493    ) -> Result<(), MemoryError> {
494        if src_ptr.segment_index >= 0 {
495            return Err(MemoryError::AddressNotInTemporarySegment(
496                src_ptr.segment_index,
497            ));
498        }
499        if src_ptr.offset != 0 {
500            return Err(MemoryError::NonZeroOffset(src_ptr.offset));
501        }
502
503        // Adjust the segment index to begin at zero, as per the struct field's
504        // comment.
505        let segment_index = -(src_ptr.segment_index + 1) as usize;
506        if self.relocation_rules.contains_key(&segment_index) {
507            return Err(MemoryError::DuplicatedRelocation(src_ptr.segment_index));
508        }
509
510        self.relocation_rules.insert(segment_index, dst);
511        Ok(())
512    }
513
514    /// Gets the value from memory address as a Felt252 value.
515    /// Returns an Error if the value at the memory address is missing or not a Felt252.
516    pub fn get_integer(&'_ self, key: Relocatable) -> Result<Cow<'_, Felt252>, MemoryError> {
517        match self
518            .get(&key)
519            .ok_or_else(|| MemoryError::UnknownMemoryCell(Box::new(key)))?
520        {
521            Cow::Borrowed(MaybeRelocatable::Int(int)) => Ok(Cow::Borrowed(int)),
522            Cow::Owned(MaybeRelocatable::Int(int)) => Ok(Cow::Owned(int)),
523            _ => Err(MemoryError::ExpectedInteger(Box::new(key))),
524        }
525    }
526
527    /// Gets a u32 value from memory address.
528    /// Returns an Error if the value at the memory address is missing or not a u32.
529    pub fn get_u32(&self, key: Relocatable) -> Result<u32, MemoryError> {
530        let felt = self.get_integer(key)?.into_owned();
531        felt.to_u32()
532            .ok_or_else(|| MemoryError::Math(MathError::Felt252ToU32Conversion(Box::new(felt))))
533    }
534
535    /// Gets the value from memory address as a usize.
536    /// Returns an Error if the value at the memory address is missing not a Felt252, or can't be converted to usize.
537    pub fn get_usize(&self, key: Relocatable) -> Result<usize, MemoryError> {
538        let felt = self.get_integer(key)?.into_owned();
539        felt.to_usize()
540            .ok_or_else(|| MemoryError::Math(MathError::Felt252ToUsizeConversion(Box::new(felt))))
541    }
542
543    /// Gets the value from memory address as a Relocatable value.
544    /// Returns an Error if the value at the memory address is missing or not a Relocatable.
545    pub fn get_relocatable(&self, key: Relocatable) -> Result<Relocatable, MemoryError> {
546        match self
547            .get(&key)
548            .ok_or_else(|| MemoryError::UnknownMemoryCell(Box::new(key)))?
549        {
550            Cow::Borrowed(MaybeRelocatable::RelocatableValue(rel)) => Ok(*rel),
551            Cow::Owned(MaybeRelocatable::RelocatableValue(rel)) => Ok(rel),
552            _ => Err(MemoryError::ExpectedRelocatable(Box::new(key))),
553        }
554    }
555
556    /// Gets the value from memory address as a MaybeRelocatable value.
557    /// Returns an Error if the value at the memory address is missing or not a MaybeRelocatable.
558    pub fn get_maybe_relocatable(&self, key: Relocatable) -> Result<MaybeRelocatable, MemoryError> {
559        match self
560            .get(&key)
561            .ok_or_else(|| MemoryError::UnknownMemoryCell(Box::new(key)))?
562        {
563            // Note: the `Borrowed` variant will never occur.
564            Cow::Borrowed(maybe_rel) => Ok(maybe_rel.clone()),
565            Cow::Owned(maybe_rel) => Ok(maybe_rel),
566        }
567    }
568
569    /// Inserts a value into memory
570    /// Returns an error if the memory cell asignment is invalid
571    pub fn insert_value<T: Into<MaybeRelocatable>>(
572        &mut self,
573        key: Relocatable,
574        val: T,
575    ) -> Result<(), MemoryError> {
576        self.insert(key, &val.into())
577    }
578
579    pub fn add_validation_rule(&mut self, segment_index: usize, rule: ValidationRule) {
580        if segment_index >= self.validation_rules.len() {
581            // Fill gaps
582            self.validation_rules
583                .resize_with(segment_index + 1, || None);
584        }
585        self.validation_rules[segment_index] = Some(rule);
586    }
587
588    fn validate_memory_cell(&mut self, addr: Relocatable) -> Result<(), MemoryError> {
589        if let Some(Some(rule)) = addr
590            .segment_index
591            .to_usize()
592            .and_then(|x| self.validation_rules.get(x))
593        {
594            if !self.validated_addresses.contains(&addr) {
595                self.validated_addresses
596                    .extend(rule.0(self, addr)?.as_slice());
597            }
598        }
599        Ok(())
600    }
601
602    ///Applies validation_rules to the current memory
603    pub fn validate_existing_memory(&mut self) -> Result<(), MemoryError> {
604        for (index, rule) in self.validation_rules.iter().enumerate() {
605            if index >= self.data.len() {
606                continue;
607            }
608            let Some(rule) = rule else {
609                continue;
610            };
611            for offset in 0..self.data[index].len() {
612                let addr = Relocatable::from((index as isize, offset));
613                if !self.validated_addresses.contains(&addr) {
614                    self.validated_addresses
615                        .extend(rule.0(self, addr)?.as_slice());
616                }
617            }
618        }
619        Ok(())
620    }
621
622    fn get_segment_cells(&self, idx: isize) -> Option<&[MemoryCell]> {
623        if idx.is_negative() {
624            self.temp_data.get(-(idx + 1) as usize).map(Vec::as_slice)
625        } else {
626            self.data.get(idx as usize).map(Vec::as_slice)
627        }
628    }
629
630    /// Compares two ranges of values in memory of length `len`
631    /// Returns the ordering and the first relative position at which they differ
632    /// Special cases:
633    /// - `lhs` exists in memory but `rhs` doesn't -> (Ordering::Greater, 0)
634    /// - `rhs` exists in memory but `lhs` doesn't -> (Ordering::Less, 0)
635    /// - None of `lhs` or `rhs` exist in memory -> (Ordering::Equal, 0)
636    ///
637    /// Everything else behaves much like `memcmp` in C.
638    /// This is meant as an optimization for hints to avoid allocations.
639    pub(crate) fn memcmp(
640        &self,
641        lhs: Relocatable,
642        rhs: Relocatable,
643        len: usize,
644    ) -> (Ordering, usize) {
645        match (
646            self.get_segment_cells(lhs.segment_index),
647            self.get_segment_cells(rhs.segment_index),
648        ) {
649            (None, None) => {
650                return (Ordering::Equal, 0);
651            }
652            (Some(_), None) => {
653                return (Ordering::Greater, 0);
654            }
655            (None, Some(_)) => {
656                return (Ordering::Less, 0);
657            }
658            (Some(lhs_segment), Some(rhs_segment)) => {
659                let (lhs_start, rhs_start) = (lhs.offset, rhs.offset);
660                for i in 0..len {
661                    let (lhs, rhs) = (
662                        lhs_segment.get(lhs_start + i),
663                        rhs_segment.get(rhs_start + i),
664                    );
665                    let ord = lhs.cmp(&rhs);
666                    if ord == Ordering::Equal {
667                        continue;
668                    }
669                    return (ord, i);
670                }
671            }
672        };
673        (Ordering::Equal, len)
674    }
675
676    /// Compares two ranges of values in memory of length `len`
677    /// Returns the ordering and the first relative position at which they differ
678    /// Special cases:
679    /// - `lhs` exists in memory but `rhs` doesn't -> (Ordering::Greater, 0)
680    /// - `rhs` exists in memory but `lhs` doesn't -> (Ordering::Less, 0)
681    /// - None of `lhs` or `rhs` exist in memory -> (Ordering::Equal, 0)
682    ///   Everything else behaves much like `memcmp` in C.
683    ///   This is meant as an optimization for hints to avoid allocations.
684    pub(crate) fn mem_eq(&self, lhs: Relocatable, rhs: Relocatable, len: usize) -> bool {
685        if lhs == rhs {
686            return true;
687        }
688        match (
689            self.get_segment_cells(lhs.segment_index)
690                .and_then(|s| s.get(lhs.offset..)),
691            self.get_segment_cells(rhs.segment_index)
692                .and_then(|s| s.get(rhs.offset..)),
693        ) {
694            (Some(lhs), Some(rhs)) => {
695                let (lhs_len, rhs_len) = (lhs.len().min(len), rhs.len().min(len));
696                if lhs_len != rhs_len {
697                    return false;
698                }
699                lhs[..lhs_len] == rhs[..rhs_len]
700            }
701            (None, None) => true,
702            _ => false,
703        }
704    }
705
706    /// Gets a range of memory values from addr to addr + size
707    /// The outputed range may contain gaps if the original memory has them
708    pub fn get_range(
709        &'_ self,
710        addr: Relocatable,
711        size: usize,
712    ) -> Vec<Option<Cow<'_, MaybeRelocatable>>> {
713        let mut values = Vec::new();
714
715        for i in 0..size {
716            values.push((addr + i).ok().and_then(|x| self.get(&x)));
717        }
718
719        values
720    }
721
722    /// Gets a range of memory values from addr to addr + size
723    /// Fails if there if any of the values inside the range is missing (memory gap)
724    pub fn get_continuous_range(
725        &self,
726        addr: Relocatable,
727        size: usize,
728    ) -> Result<Vec<MaybeRelocatable>, MemoryError> {
729        let mut values = Vec::with_capacity(size);
730
731        for i in 0..size {
732            values.push(match self.get(&(addr + i)?) {
733                Some(elem) => elem.into_owned(),
734                None => return Err(MemoryError::GetRangeMemoryGap(Box::new((addr, size)))),
735            });
736        }
737
738        Ok(values)
739    }
740
741    /// Gets a range of Felt252 memory values from addr to addr + size
742    /// Fails if there if any of the values inside the range is missing (memory gap),
743    /// or is not a Felt252
744    pub fn get_integer_range(
745        &'_ self,
746        addr: Relocatable,
747        size: usize,
748    ) -> Result<Vec<Cow<'_, Felt252>>, MemoryError> {
749        let mut values = Vec::new();
750
751        for i in 0..size {
752            values.push(self.get_integer((addr + i)?)?);
753        }
754
755        Ok(values)
756    }
757
758    /// Gets a range of u32 memory values from addr to addr + size
759    /// Fails if any of the values inside the range is missing (memory gap) or is not a u32
760    pub fn get_u32_range(&self, addr: Relocatable, size: usize) -> Result<Vec<u32>, MemoryError> {
761        let mut values = Vec::new();
762
763        for i in 0..size {
764            values.push(self.get_u32((addr + i)?)?);
765        }
766
767        Ok(values)
768    }
769
770    fn get_cell(&self, addr: Relocatable) -> Option<&MemoryCell> {
771        let (i, j) = from_relocatable_to_indexes(addr);
772        let data = if addr.segment_index < 0 {
773            &self.temp_data
774        } else {
775            &self.data
776        };
777        data.get(i)?.get(j)
778    }
779
780    #[cfg(test)]
781    pub(crate) fn get_cell_for_testing(&self, addr: Relocatable) -> Option<&MemoryCell> {
782        self.get_cell(addr)
783    }
784
785    pub fn is_accessed(&self, addr: &Relocatable) -> Result<bool, MemoryError> {
786        Ok(self
787            .get_cell(*addr)
788            .ok_or(MemoryError::UnknownMemoryCell(Box::new(*addr)))?
789            .is_accessed())
790    }
791
792    pub fn mark_as_accessed(&mut self, addr: Relocatable) {
793        let (i, j) = from_relocatable_to_indexes(addr);
794        let data = if addr.segment_index < 0 {
795            &mut self.temp_data
796        } else {
797            &mut self.data
798        };
799        let cell = data.get_mut(i).and_then(|x| x.get_mut(j));
800        if let Some(cell) = cell {
801            cell.mark_accessed()
802        }
803    }
804
805    pub fn get_amount_of_accessed_addresses_for_segment(
806        &self,
807        segment_index: usize,
808    ) -> Option<usize> {
809        let segment = self.data.get(segment_index)?;
810        Some(
811            segment
812                .iter()
813                .filter(|x| x.is_some() && x.is_accessed())
814                .count(),
815        )
816    }
817
818    // Inserts a value into memory & inmediately marks it as accessed if insertion was succesful
819    // Used by ModBuiltinRunner, as it accesses memory outside of it's segment when operating
820    pub(crate) fn insert_as_accessed<V>(
821        &mut self,
822        key: Relocatable,
823        val: V,
824    ) -> Result<(), MemoryError>
825    where
826        MaybeRelocatable: From<V>,
827    {
828        self.insert(key, val)?;
829        self.mark_as_accessed(key);
830        Ok(())
831    }
832}
833
834impl From<&Memory> for CairoPieMemory {
835    fn from(mem: &Memory) -> CairoPieMemory {
836        let mut pie_memory = Vec::default();
837        for (i, segment) in mem.data.iter().enumerate() {
838            for (j, cell) in segment.iter().enumerate() {
839                if let Some(value) = cell.get_value() {
840                    pie_memory.push(((i, j), value))
841                }
842            }
843        }
844        CairoPieMemory(pie_memory)
845    }
846}
847
848impl fmt::Display for Memory {
849    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
850        for (i, segment) in self.temp_data.iter().enumerate() {
851            for (j, cell) in segment.iter().enumerate() {
852                if let Some(elem) = cell.get_value() {
853                    let temp_segment = i + 1;
854                    writeln!(f, "(-{temp_segment},{j}) : {elem}")?;
855                }
856            }
857        }
858        for (i, segment) in self.data.iter().enumerate() {
859            for (j, cell) in segment.iter().enumerate() {
860                if let Some(elem) = cell.get_value() {
861                    writeln!(f, "({i},{j}) : {elem}")?;
862                }
863            }
864        }
865        Ok(())
866    }
867}
868
869/// Applies `relocation_rules` to a value
870pub(crate) trait RelocateValue<'a, Input: 'a, Output: 'a> {
871    fn relocate_value(&self, value: Input) -> Result<Output, MemoryError>;
872}
873
874#[cfg(not(feature = "extensive_hints"))]
875impl RelocateValue<'_, Relocatable, Relocatable> for Memory {
876    fn relocate_value(&self, addr: Relocatable) -> Result<Relocatable, MemoryError> {
877        if addr.segment_index < 0 {
878            // Adjust the segment index to begin at zero, as per the struct field's
879            // comment.
880            if let Some(x) = self
881                .relocation_rules
882                .get(&(-(addr.segment_index + 1) as usize))
883            {
884                return (*x + addr.offset).map_err(MemoryError::Math);
885            }
886        }
887        Ok(addr)
888    }
889}
890#[cfg(feature = "extensive_hints")]
891impl RelocateValue<'_, Relocatable, MaybeRelocatable> for Memory {
892    fn relocate_value(&self, addr: Relocatable) -> Result<MaybeRelocatable, MemoryError> {
893        if addr.segment_index < 0 {
894            // Adjust the segment index to begin at zero, as per the struct field's
895            // comment.
896            if let Some(x) = self
897                .relocation_rules
898                .get(&(-(addr.segment_index + 1) as usize))
899            {
900                return Ok(match x {
901                    MaybeRelocatable::RelocatableValue(r) => {
902                        (*r + addr.offset).map_err(MemoryError::Math)?.into()
903                    }
904                    MaybeRelocatable::Int(i) => i.into(),
905                });
906            }
907        }
908        Ok(addr.into())
909    }
910}
911
912impl<'a> RelocateValue<'a, &'a Felt252, &'a Felt252> for Memory {
913    fn relocate_value(&self, value: &'a Felt252) -> Result<&'a Felt252, MemoryError> {
914        Ok(value)
915    }
916}
917
918impl<'a> RelocateValue<'a, &'a MaybeRelocatable, Cow<'a, MaybeRelocatable>> for Memory {
919    fn relocate_value(
920        &self,
921        value: &'a MaybeRelocatable,
922    ) -> Result<Cow<'a, MaybeRelocatable>, MemoryError> {
923        Ok(match value {
924            MaybeRelocatable::Int(_) => Cow::Borrowed(value),
925            MaybeRelocatable::RelocatableValue(addr) => {
926                #[cfg(not(feature = "extensive_hints"))]
927                let v = self.relocate_value(*addr)?.into();
928                #[cfg(feature = "extensive_hints")]
929                let v = self.relocate_value(*addr)?;
930
931                Cow::Owned(v)
932            }
933        })
934    }
935}
936
937impl Default for Memory {
938    fn default() -> Self {
939        Self::new()
940    }
941}
942
943#[cfg(test)]
944mod memory_tests {
945
946    use super::*;
947    use crate::{
948        felt_hex, relocatable,
949        utils::test_utils::*,
950        vm::{
951            runners::builtin_runner::{
952                RangeCheckBuiltinRunner, SignatureBuiltinRunner, RC_N_PARTS_STANDARD,
953            },
954            vm_memory::memory_segments::MemorySegmentManager,
955        },
956    };
957    use assert_matches::assert_matches;
958
959    use crate::vm::errors::memory_errors::MemoryError;
960
961    use crate::utils::test_utils::memory_from_memory;
962    use crate::utils::test_utils::memory_inner;
963
964    #[test]
965    fn insert_and_get_succesful() {
966        let key = Relocatable::from((0, 0));
967        let val = MaybeRelocatable::from(Felt252::from(5_u64));
968        let mut memory = Memory::new();
969        memory.data.push(Vec::new());
970        memory.insert(key, &val).unwrap();
971        assert_eq!(
972            memory.get(&key).unwrap().as_ref(),
973            &MaybeRelocatable::from(Felt252::from(5_u64))
974        );
975    }
976
977    #[test]
978    fn get_valuef_from_temp_segment() {
979        let mut memory = Memory::new();
980        memory.temp_data = vec![vec![
981            MemoryCell::NONE,
982            MemoryCell::NONE,
983            MemoryCell::new(mayberelocatable!(8)),
984        ]];
985        assert_eq!(
986            memory.get(&mayberelocatable!(-1, 2)).unwrap().as_ref(),
987            &mayberelocatable!(8),
988        );
989    }
990
991    #[test]
992    fn insert_value_in_temp_segment() {
993        let key = Relocatable::from((-1, 3));
994        let val = MaybeRelocatable::from(Felt252::from(8_u64));
995        let mut memory = Memory::new();
996        memory.temp_data.push(Vec::new());
997        memory.insert(key, &val).unwrap();
998        assert_eq!(
999            memory.temp_data[0][3],
1000            MemoryCell::new(MaybeRelocatable::from(Felt252::from(8_u64)))
1001        );
1002    }
1003
1004    #[test]
1005    fn insert_and_get_from_temp_segment_succesful() {
1006        let key = Relocatable::from((-1, 0));
1007        let val = MaybeRelocatable::from(Felt252::from(5_u64));
1008        let mut memory = Memory::new();
1009        memory.temp_data.push(Vec::new());
1010        memory.insert(key, &val).unwrap();
1011        assert_eq!(
1012            memory.get(&key).unwrap().as_ref(),
1013            &MaybeRelocatable::from(Felt252::from(5_u64)),
1014        );
1015    }
1016
1017    #[test]
1018    fn insert_and_get_from_temp_segment_failed() {
1019        let key = relocatable!(-1, 1);
1020        let mut memory = Memory::new();
1021        memory.temp_data = vec![vec![
1022            MemoryCell::NONE,
1023            MemoryCell::new(mayberelocatable!(8)),
1024        ]];
1025        assert_eq!(
1026            memory.insert(key, &mayberelocatable!(5)),
1027            Err(MemoryError::InconsistentMemory(Box::new((
1028                relocatable!(-1, 1),
1029                mayberelocatable!(8),
1030                mayberelocatable!(5)
1031            ))))
1032        );
1033    }
1034
1035    #[test]
1036    fn get_non_allocated_memory() {
1037        let key = Relocatable::from((0, 0));
1038        let memory = Memory::new();
1039        assert_eq!(memory.get(&key), None);
1040    }
1041
1042    #[test]
1043    fn get_non_existant_element() {
1044        let key = Relocatable::from((0, 0));
1045        let memory = Memory::new();
1046        assert_eq!(memory.get(&key), None);
1047    }
1048
1049    #[test]
1050    fn insert_non_allocated_memory() {
1051        let key = Relocatable::from((0, 0));
1052        let val = MaybeRelocatable::from(Felt252::from(5_u64));
1053        let mut memory = Memory::new();
1054        let error = memory.insert(key, &val);
1055        assert_eq!(
1056            error,
1057            Err(MemoryError::UnallocatedSegment(Box::new((0, 0))))
1058        );
1059    }
1060
1061    #[test]
1062    fn insert_inconsistent_memory() {
1063        let key = Relocatable::from((0, 0));
1064        let val_a = MaybeRelocatable::from(Felt252::from(5_u64));
1065        let val_b = MaybeRelocatable::from(Felt252::from(6_u64));
1066        let mut memory = Memory::new();
1067        memory.data.push(Vec::new());
1068        memory
1069            .insert(key, &val_a)
1070            .expect("Unexpected memory insert fail");
1071        let error = memory.insert(key, &val_b);
1072        assert_eq!(
1073            error,
1074            Err(MemoryError::InconsistentMemory(Box::new((
1075                key, val_a, val_b
1076            ))))
1077        );
1078    }
1079
1080    #[test]
1081    fn insert_non_contiguous_element() {
1082        let key_a = Relocatable::from((0, 0));
1083        let key_b = Relocatable::from((0, 2));
1084        let val = MaybeRelocatable::from(Felt252::from(5_u64));
1085        let mut memory = Memory::new();
1086        memory.data.push(Vec::new());
1087        memory.insert(key_a, &val).unwrap();
1088        memory.insert(key_b, &val).unwrap();
1089        assert_eq!(memory.get(&key_b).unwrap().as_ref(), &val);
1090    }
1091
1092    #[test]
1093    fn insert_non_contiguous_element_memory_gaps_none() {
1094        let key_a = Relocatable::from((0, 0));
1095        let key_b = Relocatable::from((0, 5));
1096        let val = MaybeRelocatable::from(Felt252::from(5_u64));
1097        let mut memory = Memory::new();
1098        memory.data.push(Vec::new());
1099        memory.insert(key_a, &val).unwrap();
1100        memory.insert(key_b, &val).unwrap();
1101        assert_eq!(memory.get(&key_b).unwrap().as_ref(), &val);
1102        assert_eq!(memory.get(&MaybeRelocatable::from((0, 1))), None);
1103        assert_eq!(memory.get(&MaybeRelocatable::from((0, 2))), None);
1104        assert_eq!(memory.get(&MaybeRelocatable::from((0, 3))), None);
1105        assert_eq!(memory.get(&MaybeRelocatable::from((0, 4))), None);
1106    }
1107
1108    #[test]
1109    fn validate_existing_memory_for_range_check_within_bounds() {
1110        let mut builtin = RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1111        let mut segments = MemorySegmentManager::new();
1112        builtin.initialize_segments(&mut segments);
1113        builtin.add_validation_rule(&mut segments.memory);
1114        for _ in 0..3 {
1115            segments.add();
1116        }
1117
1118        segments
1119            .memory
1120            .insert(
1121                Relocatable::from((0, 0)),
1122                &MaybeRelocatable::from(Felt252::from(45_u64)),
1123            )
1124            .unwrap();
1125        segments.memory.validate_existing_memory().unwrap();
1126        assert!(segments
1127            .memory
1128            .validated_addresses
1129            .contains(&Relocatable::from((0, 0))));
1130    }
1131
1132    #[test]
1133    fn validate_existing_memory_for_range_check_outside_bounds() {
1134        let mut builtin = RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1135        let mut segments = MemorySegmentManager::new();
1136        segments.add();
1137        builtin.initialize_segments(&mut segments);
1138        segments
1139            .memory
1140            .insert(
1141                Relocatable::from((1, 0)),
1142                &MaybeRelocatable::from(Felt252::from(-10)),
1143            )
1144            .unwrap();
1145        builtin.add_validation_rule(&mut segments.memory);
1146        let error = segments.memory.validate_existing_memory();
1147        assert_eq!(
1148            error,
1149            Err(MemoryError::RangeCheckNumOutOfBounds(Box::new((
1150                Felt252::from(-10),
1151                Felt252::TWO.pow(128_u128)
1152            ))))
1153        );
1154    }
1155
1156    #[test]
1157    fn validate_existing_memory_for_invalid_signature() {
1158        let mut builtin = SignatureBuiltinRunner::new(Some(512), true);
1159        let mut segments = MemorySegmentManager::new();
1160        builtin.initialize_segments(&mut segments);
1161        segments.memory = memory![
1162            (
1163                (0, 0),
1164                (
1165                    "874739451078007766457464989774322083649278607533249481151382481072868806602",
1166                    10
1167                )
1168            ),
1169            (
1170                (0, 1),
1171                (
1172                    "-1472574760335685482768423018116732869320670550222259018541069375211356613248",
1173                    10
1174                )
1175            )
1176        ];
1177        builtin.add_validation_rule(&mut segments.memory);
1178        let error = segments.memory.validate_existing_memory();
1179        assert_eq!(
1180            error,
1181            Err(MemoryError::SignatureNotFound(Box::new((0, 0).into())))
1182        );
1183    }
1184
1185    #[test]
1186    fn validate_existing_memory_for_valid_signature() {
1187        let mut builtin = SignatureBuiltinRunner::new(Some(512), true);
1188
1189        let signature_r =
1190            felt_hex!("0x411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20");
1191        let signature_s =
1192            felt_hex!("0x405c3191ab3883ef2b763af35bc5f5d15b3b4e99461d70e84c654a351a7c81b");
1193
1194        builtin
1195            .add_signature(Relocatable::from((1, 0)), &(signature_r, signature_s))
1196            .unwrap();
1197
1198        let mut segments = MemorySegmentManager::new();
1199
1200        segments.memory = memory![
1201            (
1202                (1, 0),
1203                (
1204                    "874739451078007766457464989774322083649278607533249481151382481072868806602",
1205                    10
1206                )
1207            ),
1208            ((1, 1), 2)
1209        ];
1210
1211        builtin.initialize_segments(&mut segments);
1212
1213        builtin.add_validation_rule(&mut segments.memory);
1214
1215        let result = segments.memory.validate_existing_memory();
1216
1217        assert_eq!(result, Ok(()))
1218    }
1219
1220    #[test]
1221    fn validate_existing_memory_for_range_check_relocatable_value() {
1222        let mut builtin = RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1223        let mut segments = MemorySegmentManager::new();
1224        builtin.initialize_segments(&mut segments);
1225        segments.memory = memory![((0, 0), (0, 4))];
1226        builtin.add_validation_rule(&mut segments.memory);
1227        let error = segments.memory.validate_existing_memory();
1228        assert_eq!(
1229            error,
1230            Err(MemoryError::RangeCheckFoundNonInt(Box::new(relocatable!(
1231                0, 0
1232            ))))
1233        );
1234    }
1235
1236    #[test]
1237    fn validate_existing_memory_for_range_check_out_of_bounds_diff_segment() {
1238        let mut builtin = RangeCheckBuiltinRunner::<RC_N_PARTS_STANDARD>::new(Some(8), true);
1239        let mut segments = MemorySegmentManager::new();
1240        segments.memory = Memory::new();
1241        segments.add();
1242        builtin.initialize_segments(&mut segments);
1243        segments
1244            .memory
1245            .insert(
1246                Relocatable::from((0, 0)),
1247                &MaybeRelocatable::from(Felt252::from(-45_i128)),
1248            )
1249            .unwrap();
1250        builtin.add_validation_rule(&mut segments.memory);
1251        assert_eq!(segments.memory.validate_existing_memory(), Ok(()));
1252    }
1253
1254    #[test]
1255    fn get_integer_valid() {
1256        let memory = memory![((0, 0), 10)];
1257        assert_eq!(
1258            memory
1259                .get_integer(Relocatable::from((0, 0)))
1260                .unwrap()
1261                .as_ref(),
1262            &Felt252::from(10)
1263        );
1264    }
1265
1266    #[test]
1267    fn get_integer_invalid_expected_integer() {
1268        let mut segments = MemorySegmentManager::new();
1269        segments.add();
1270        segments
1271            .memory
1272            .insert(Relocatable::from((0, 0)), &MaybeRelocatable::from((0, 10)))
1273            .unwrap();
1274        assert_matches!(
1275            segments.memory.get_integer(Relocatable::from((0, 0))),
1276            Err(MemoryError::ExpectedInteger(
1277                bx
1278            )) if *bx == Relocatable::from((0, 0))
1279        );
1280    }
1281
1282    #[test]
1283    fn get_u32_too_big() {
1284        let mut segments = MemorySegmentManager::new();
1285        segments.add();
1286        segments
1287            .memory
1288            .insert(Relocatable::from((0, 0)), &Felt252::from(1_u64 << 32))
1289            .unwrap();
1290        assert_matches!(
1291            segments.memory.get_u32(Relocatable::from((0, 0))),
1292            Err(MemoryError::Math(MathError::Felt252ToU32Conversion(
1293                bx
1294            ))) if *bx == Felt252::from(1_u64 << 32)
1295        );
1296    }
1297
1298    #[test]
1299    fn get_maybe_relocatable_valid_relocatable() {
1300        let memory = memory![((0, 0), (1, 0))];
1301        assert_eq!(
1302            memory
1303                .get_maybe_relocatable(Relocatable::from((0, 0)))
1304                .unwrap(),
1305            Relocatable::from((1, 0)).into()
1306        );
1307    }
1308
1309    #[test]
1310    fn get_maybe_relocatable_valid_integer() {
1311        let memory = memory![((0, 0), 10)];
1312        assert_eq!(
1313            memory
1314                .get_maybe_relocatable(Relocatable::from((0, 0)))
1315                .unwrap(),
1316            10.into()
1317        );
1318    }
1319
1320    #[test]
1321    fn default_memory() {
1322        let mem: Memory = Default::default();
1323        assert_eq!(mem.data.len(), 0);
1324    }
1325
1326    #[test]
1327    fn insert_and_get_temporary_succesful() {
1328        let mut memory = Memory::new();
1329        memory.temp_data.push(Vec::new());
1330
1331        let key = Relocatable::from((-1, 0));
1332        let val = MaybeRelocatable::from(Felt252::from(5));
1333        memory.insert(key, &val).unwrap();
1334
1335        assert_eq!(memory.get(&key).unwrap().as_ref(), &val);
1336    }
1337
1338    #[test]
1339    fn add_relocation_rule() {
1340        let mut memory = Memory::new();
1341
1342        assert_eq!(
1343            memory.add_relocation_rule((-1, 0).into(), (1, 2).into()),
1344            Ok(()),
1345        );
1346        assert_eq!(
1347            memory.add_relocation_rule((-2, 0).into(), (-1, 1).into()),
1348            Ok(()),
1349        );
1350        assert_eq!(
1351            memory.add_relocation_rule((5, 0).into(), (0, 0).into()),
1352            Err(MemoryError::AddressNotInTemporarySegment(5)),
1353        );
1354        assert_eq!(
1355            memory.add_relocation_rule((-3, 6).into(), (0, 0).into()),
1356            Err(MemoryError::NonZeroOffset(6)),
1357        );
1358        assert_eq!(
1359            memory.add_relocation_rule((-1, 0).into(), (0, 0).into()),
1360            Err(MemoryError::DuplicatedRelocation(-1)),
1361        );
1362    }
1363
1364    #[test]
1365    fn relocate_value_bigint() {
1366        let mut memory = Memory::new();
1367        memory
1368            .add_relocation_rule((-1, 0).into(), (2, 0).into())
1369            .unwrap();
1370        memory
1371            .add_relocation_rule((-2, 0).into(), (2, 2).into())
1372            .unwrap();
1373
1374        // Test when value is Some(BigInt):
1375        assert_eq!(
1376            memory
1377                .relocate_value(&MaybeRelocatable::Int(Felt252::from(0)))
1378                .unwrap(),
1379            Cow::Owned(MaybeRelocatable::Int(Felt252::from(0))),
1380        );
1381    }
1382
1383    #[test]
1384    fn relocate_value_mayberelocatable() {
1385        let mut memory = Memory::new();
1386        memory
1387            .add_relocation_rule((-1, 0).into(), (2, 0).into())
1388            .unwrap();
1389        memory
1390            .add_relocation_rule((-2, 0).into(), (2, 2).into())
1391            .unwrap();
1392
1393        // Test when value is Some(MaybeRelocatable) with segment_index >= 0:
1394        assert_eq!(
1395            memory
1396                .relocate_value(&MaybeRelocatable::RelocatableValue((0, 0).into()))
1397                .unwrap(),
1398            Cow::Owned(MaybeRelocatable::RelocatableValue((0, 0).into())),
1399        );
1400        assert_eq!(
1401            memory
1402                .relocate_value(&MaybeRelocatable::RelocatableValue((5, 0).into()))
1403                .unwrap(),
1404            Cow::Owned(MaybeRelocatable::RelocatableValue((5, 0).into())),
1405        );
1406    }
1407
1408    #[test]
1409    fn relocate_value_mayberelocatable_temporary_segment_no_rules() {
1410        let mut memory = Memory::new();
1411        memory
1412            .add_relocation_rule((-1, 0).into(), (2, 0).into())
1413            .unwrap();
1414        memory
1415            .add_relocation_rule((-2, 0).into(), (2, 2).into())
1416            .unwrap();
1417
1418        // Test when value is Some(MaybeRelocatable) with segment_index < 0 and
1419        // there are no applicable relocation rules:
1420        assert_eq!(
1421            memory
1422                .relocate_value(&MaybeRelocatable::RelocatableValue((-5, 0).into()))
1423                .unwrap(),
1424            Cow::Owned(MaybeRelocatable::RelocatableValue((-5, 0).into())),
1425        );
1426    }
1427
1428    #[test]
1429    fn relocate_value_mayberelocatable_temporary_segment_rules() {
1430        let mut memory = Memory::new();
1431        memory
1432            .add_relocation_rule((-1, 0).into(), (2, 0).into())
1433            .unwrap();
1434        memory
1435            .add_relocation_rule((-2, 0).into(), (2, 2).into())
1436            .unwrap();
1437
1438        // Test when value is Some(MaybeRelocatable) with segment_index < 0 and
1439        // there are applicable relocation rules:
1440        assert_eq!(
1441            memory
1442                .relocate_value(&MaybeRelocatable::RelocatableValue((-1, 0).into()))
1443                .unwrap(),
1444            Cow::Owned(MaybeRelocatable::RelocatableValue((2, 0).into())),
1445        );
1446        assert_eq!(
1447            memory
1448                .relocate_value(&MaybeRelocatable::RelocatableValue((-2, 0).into()))
1449                .unwrap(),
1450            Cow::Owned(MaybeRelocatable::RelocatableValue((2, 2).into())),
1451        );
1452        assert_eq!(
1453            memory
1454                .relocate_value(&MaybeRelocatable::RelocatableValue((-1, 5).into()))
1455                .unwrap(),
1456            Cow::Owned(MaybeRelocatable::RelocatableValue((2, 5).into())),
1457        );
1458        assert_eq!(
1459            memory
1460                .relocate_value(&MaybeRelocatable::RelocatableValue((-2, 5).into()))
1461                .unwrap(),
1462            Cow::Owned(MaybeRelocatable::RelocatableValue((2, 7).into())),
1463        );
1464    }
1465
1466    #[test]
1467    fn get_range_for_continuous_memory() {
1468        let memory = memory![((1, 0), 2), ((1, 1), 3), ((1, 2), 4)];
1469
1470        let value1 = MaybeRelocatable::from(Felt252::from(2));
1471        let value2 = MaybeRelocatable::from(Felt252::from(3));
1472        let value3 = MaybeRelocatable::from(Felt252::from(4));
1473
1474        let expected_vec = vec![
1475            Some(Cow::Borrowed(&value1)),
1476            Some(Cow::Borrowed(&value2)),
1477            Some(Cow::Borrowed(&value3)),
1478        ];
1479        assert_eq!(memory.get_range(Relocatable::from((1, 0)), 3), expected_vec);
1480    }
1481
1482    #[test]
1483    fn get_range_for_non_continuous_memory() {
1484        let memory = memory![((1, 0), 2), ((1, 1), 3), ((1, 3), 4)];
1485
1486        let value1 = MaybeRelocatable::from(Felt252::from(2));
1487        let value2 = MaybeRelocatable::from(Felt252::from(3));
1488        let value3 = MaybeRelocatable::from(Felt252::from(4));
1489
1490        let expected_vec = vec![
1491            Some(Cow::Borrowed(&value1)),
1492            Some(Cow::Borrowed(&value2)),
1493            None,
1494            Some(Cow::Borrowed(&value3)),
1495        ];
1496        assert_eq!(memory.get_range(Relocatable::from((1, 0)), 4), expected_vec);
1497    }
1498
1499    #[test]
1500    fn get_continuous_range_for_continuous_memory() {
1501        let memory = memory![((1, 0), 2), ((1, 1), 3), ((1, 2), 4)];
1502
1503        let value1 = MaybeRelocatable::from(Felt252::from(2));
1504        let value2 = MaybeRelocatable::from(Felt252::from(3));
1505        let value3 = MaybeRelocatable::from(Felt252::from(4));
1506
1507        let expected_vec = vec![value1, value2, value3];
1508        assert_eq!(
1509            memory.get_continuous_range(Relocatable::from((1, 0)), 3),
1510            Ok(expected_vec)
1511        );
1512    }
1513
1514    #[test]
1515    fn get_continuous_range_for_non_continuous_memory() {
1516        let memory = memory![((1, 0), 2), ((1, 1), 3), ((1, 3), 4)];
1517
1518        assert_eq!(
1519            memory.get_continuous_range(Relocatable::from((1, 0)), 3),
1520            Err(MemoryError::GetRangeMemoryGap(Box::new(((1, 0).into(), 3))))
1521        );
1522    }
1523
1524    #[test]
1525    fn get_u32_range_ok() {
1526        let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967295), ((0, 3), 3)];
1527        let expected_vector = vec![1, 4294967295];
1528        assert_eq!(memory.get_u32_range((0, 1).into(), 2), Ok(expected_vector));
1529    }
1530
1531    #[test]
1532    fn get_u32_range_relocatable() {
1533        let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), (0, 0)), ((0, 3), 3)];
1534        assert_matches!(memory.get_u32_range((0, 1).into(), 2), Err(MemoryError::ExpectedInteger(bx)) if *bx == (0, 2).into());
1535    }
1536
1537    #[test]
1538    fn get_u32_range_over_32_bits() {
1539        let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 2), 4294967296), ((0, 3), 3)];
1540        assert_matches!(memory.get_u32_range((0, 1).into(), 2), Err(MemoryError::Math(MathError::Felt252ToU32Conversion(bx))) if *bx == Felt252::from(4294967296_u64));
1541    }
1542
1543    #[test]
1544    fn get_u32_range_memory_gap() {
1545        let memory = memory![((0, 0), 0), ((0, 1), 1), ((0, 3), 3)];
1546        assert_matches!(memory.get_u32_range((0, 1).into(), 3), Err(MemoryError::UnknownMemoryCell(bx)) if *bx == (0, 2).into());
1547    }
1548
1549    /// Test that relocate_memory() works when there are no relocation rules.
1550    #[test]
1551    fn relocate_memory_empty_relocation_rules() {
1552        let mut memory = memory![((0, 0), 1), ((0, 1), 2), ((0, 2), 3)];
1553
1554        assert_eq!(memory.relocate_memory(), Ok(()));
1555        check_memory!(memory, ((0, 0), 1), ((0, 1), 2), ((0, 2), 3));
1556    }
1557
1558    #[test]
1559    fn relocate_memory_new_segment_with_gap() {
1560        let mut memory = memory![
1561            ((0, 0), 1),
1562            ((0, 1), (-1, 0)),
1563            ((0, 2), 3),
1564            ((1, 0), (-1, 1)),
1565            ((1, 1), 5),
1566            ((1, 2), (-1, 2)),
1567            ((-1, 0), 7),
1568            ((-1, 1), 8),
1569            ((-1, 2), 9)
1570        ];
1571        memory
1572            .add_relocation_rule((-1, 0).into(), (2, 1).into())
1573            .unwrap();
1574        memory.data.push(vec![]);
1575
1576        assert_eq!(memory.relocate_memory(), Ok(()));
1577        check_memory!(
1578            memory,
1579            ((0, 0), 1),
1580            ((0, 1), (2, 1)),
1581            ((0, 2), 3),
1582            ((1, 0), (2, 2)),
1583            ((1, 1), 5),
1584            ((1, 2), (2, 3)),
1585            ((2, 1), 7),
1586            ((2, 2), 8),
1587            ((2, 3), 9)
1588        );
1589        assert!(memory.temp_data.is_empty());
1590    }
1591
1592    #[test]
1593    fn relocate_memory_new_segment() {
1594        let mut memory = memory![
1595            ((0, 0), 1),
1596            ((0, 1), (-1, 0)),
1597            ((0, 2), 3),
1598            ((1, 0), (-1, 1)),
1599            ((1, 1), 5),
1600            ((1, 2), (-1, 2)),
1601            ((-1, 0), 7),
1602            ((-1, 1), 8),
1603            ((-1, 2), 9)
1604        ];
1605        memory
1606            .add_relocation_rule((-1, 0).into(), (2, 0).into())
1607            .unwrap();
1608        memory.data.push(vec![]);
1609
1610        assert_eq!(memory.relocate_memory(), Ok(()));
1611
1612        check_memory!(
1613            memory,
1614            ((0, 0), 1),
1615            ((0, 1), (2, 0)),
1616            ((0, 2), 3),
1617            ((1, 0), (2, 1)),
1618            ((1, 1), 5),
1619            ((1, 2), (2, 2)),
1620            ((2, 0), 7),
1621            ((2, 1), 8),
1622            ((2, 2), 9)
1623        );
1624        assert!(memory.temp_data.is_empty());
1625    }
1626
1627    #[test]
1628    fn relocate_memory_new_segment_unallocated() {
1629        let mut memory = memory![
1630            ((0, 0), 1),
1631            ((0, 1), (-1, 0)),
1632            ((0, 2), 3),
1633            ((1, 0), (-1, 1)),
1634            ((1, 1), 5),
1635            ((1, 2), (-1, 2)),
1636            ((-1, 0), 7),
1637            ((-1, 1), 8),
1638            ((-1, 2), 9)
1639        ];
1640        memory
1641            .add_relocation_rule((-1, 0).into(), (2, 0).into())
1642            .unwrap();
1643
1644        assert_eq!(
1645            memory.relocate_memory(),
1646            Err(MemoryError::UnallocatedSegment(Box::new((2, 2))))
1647        );
1648    }
1649
1650    #[test]
1651    fn relocate_memory_into_existing_segment() {
1652        let mut memory = memory![
1653            ((0, 0), 1),
1654            ((0, 1), (-1, 0)),
1655            ((0, 2), 3),
1656            ((1, 0), (-1, 1)),
1657            ((1, 1), 5),
1658            ((1, 2), (-1, 2)),
1659            ((-1, 0), 7),
1660            ((-1, 1), 8),
1661            ((-1, 2), 9)
1662        ];
1663        memory
1664            .add_relocation_rule((-1, 0).into(), (1, 3).into())
1665            .unwrap();
1666
1667        assert_eq!(memory.relocate_memory(), Ok(()));
1668
1669        check_memory!(
1670            memory,
1671            ((0, 0), 1),
1672            ((0, 1), (1, 3)),
1673            ((0, 2), 3),
1674            ((1, 0), (1, 4)),
1675            ((1, 1), 5),
1676            ((1, 2), (1, 5)),
1677            ((1, 3), 7),
1678            ((1, 4), 8),
1679            ((1, 5), 9)
1680        );
1681        assert!(memory.temp_data.is_empty());
1682    }
1683
1684    #[test]
1685    fn relocate_memory_into_existing_segment_inconsistent_memory() {
1686        let mut memory = memory![
1687            ((0, 0), 1),
1688            ((0, 1), (-1, 0)),
1689            ((0, 2), 3),
1690            ((1, 0), (-1, 1)),
1691            ((1, 1), 5),
1692            ((1, 2), (-1, 2)),
1693            ((-1, 0), 7),
1694            ((-1, 1), 8),
1695            ((-1, 2), 9)
1696        ];
1697        memory
1698            .add_relocation_rule((-1, 0).into(), (1, 0).into())
1699            .unwrap();
1700
1701        assert_eq!(
1702            memory.relocate_memory(),
1703            Err(MemoryError::InconsistentMemory(Box::new((
1704                (1, 0).into(),
1705                (1, 1).into(),
1706                7.into(),
1707            ))))
1708        );
1709    }
1710
1711    #[test]
1712    fn relocate_memory_new_segment_2_temporary_segments_one_relocated() {
1713        let mut memory = memory![
1714            ((0, 0), 1),
1715            ((0, 1), (-1, 0)),
1716            ((0, 2), 3),
1717            ((1, 0), (-1, 1)),
1718            ((1, 1), 5),
1719            ((1, 2), (-1, 2)),
1720            ((-1, 0), 7),
1721            ((-1, 1), 8),
1722            ((-1, 2), 9),
1723            ((-2, 0), 10),
1724            ((-2, 1), 11)
1725        ];
1726        memory
1727            .add_relocation_rule((-1, 0).into(), (2, 0).into())
1728            .unwrap();
1729        memory.data.push(vec![]);
1730
1731        assert_eq!(memory.relocate_memory(), Ok(()));
1732        check_memory!(
1733            memory,
1734            ((0, 0), 1),
1735            ((0, 1), (2, 0)),
1736            ((0, 2), 3),
1737            ((1, 0), (2, 1)),
1738            ((1, 1), 5),
1739            ((1, 2), (2, 2)),
1740            ((2, 0), 7),
1741            ((2, 1), 8),
1742            ((2, 2), 9),
1743            ((-1, 0), 10),
1744            ((-1, 1), 11)
1745        );
1746    }
1747
1748    #[test]
1749    fn relocate_memory_new_segment_2_temporary_segments_relocated() {
1750        let mut memory = memory![
1751            ((0, 0), 1),
1752            ((0, 1), (-1, 0)),
1753            ((0, 2), 3),
1754            ((1, 0), (-1, 1)),
1755            ((1, 1), 5),
1756            ((1, 2), (-1, 2)),
1757            ((-1, 0), 7),
1758            ((-1, 1), 8),
1759            ((-1, 2), 9),
1760            ((-2, 0), 10),
1761            ((-2, 1), 11)
1762        ];
1763        memory.data.push(vec![]);
1764        memory
1765            .add_relocation_rule((-1, 0).into(), (2, 0).into())
1766            .unwrap();
1767        memory.data.push(vec![]);
1768        memory
1769            .add_relocation_rule((-2, 0).into(), (3, 0).into())
1770            .unwrap();
1771
1772        assert_eq!(memory.relocate_memory(), Ok(()));
1773
1774        check_memory!(
1775            memory,
1776            ((0, 0), 1),
1777            ((0, 1), (2, 0)),
1778            ((0, 2), 3),
1779            ((1, 0), (2, 1)),
1780            ((1, 1), 5),
1781            ((1, 2), (2, 2)),
1782            ((2, 0), 7),
1783            ((2, 1), 8),
1784            ((2, 2), 9),
1785            ((3, 0), 10),
1786            ((3, 1), 11)
1787        );
1788        assert!(memory.temp_data.is_empty());
1789    }
1790
1791    #[test]
1792    fn test_memory_display() {
1793        let memory = memory![
1794            ((0, 0), 1),
1795            ((0, 1), (-1, 0)),
1796            ((0, 2), 3),
1797            ((1, 0), (-1, 1)),
1798            ((1, 1), 5),
1799            ((1, 2), (-1, 2)),
1800            ((-1, 0), (-1, 0)),
1801            ((-1, 1), 8),
1802            ((-1, 2), 9)
1803        ];
1804
1805        assert_eq!(
1806            format!("{}", memory),
1807            "(-1,0) : -1:0\n(-1,1) : 8\n(-1,2) : 9\n(0,0) : 1\n(0,1) : -1:0\n(0,2) : 3\n(1,0) : -1:1\n(1,1) : 5\n(1,2) : -1:2\n");
1808    }
1809
1810    #[test]
1811    fn relocate_memory_into_existing_segment_temporary_values_in_temporary_memory() {
1812        let mut memory = memory![
1813            ((0, 0), 1),
1814            ((0, 1), (-1, 0)),
1815            ((0, 2), 3),
1816            ((1, 0), (-1, 1)),
1817            ((1, 1), 5),
1818            ((1, 2), (-1, 2)),
1819            ((-1, 0), (-1, 0)),
1820            ((-1, 1), 8),
1821            ((-1, 2), 9)
1822        ];
1823        memory
1824            .add_relocation_rule((-1, 0).into(), (1, 3).into())
1825            .unwrap();
1826
1827        assert_eq!(memory.relocate_memory(), Ok(()));
1828        check_memory!(
1829            memory,
1830            ((0, 0), 1),
1831            ((0, 1), (1, 3)),
1832            ((0, 2), 3),
1833            ((1, 0), (1, 4)),
1834            ((1, 1), 5),
1835            ((1, 2), (1, 5)),
1836            ((1, 3), (1, 3)),
1837            ((1, 4), 8),
1838            ((1, 5), 9)
1839        );
1840        assert!(memory.temp_data.is_empty());
1841    }
1842
1843    #[test]
1844    fn relocate_address_with_rules() {
1845        let mut memory = Memory::new();
1846        memory
1847            .add_relocation_rule((-1, 0).into(), (2, 0).into())
1848            .unwrap();
1849        memory
1850            .add_relocation_rule((-2, 0).into(), (2, 2).into())
1851            .unwrap();
1852
1853        assert_eq!(
1854            Memory::relocate_address((-1, 0).into(), &memory.relocation_rules).unwrap(),
1855            MaybeRelocatable::RelocatableValue((2, 0).into()),
1856        );
1857        assert_eq!(
1858            Memory::relocate_address((-2, 1).into(), &memory.relocation_rules).unwrap(),
1859            MaybeRelocatable::RelocatableValue((2, 3).into()),
1860        );
1861    }
1862
1863    #[test]
1864    fn relocate_address_no_rules() {
1865        let memory = Memory::new();
1866        assert_eq!(
1867            Memory::relocate_address((-1, 0).into(), &memory.relocation_rules).unwrap(),
1868            MaybeRelocatable::RelocatableValue((-1, 0).into()),
1869        );
1870        assert_eq!(
1871            Memory::relocate_address((-2, 1).into(), &memory.relocation_rules).unwrap(),
1872            MaybeRelocatable::RelocatableValue((-2, 1).into()),
1873        );
1874    }
1875
1876    #[test]
1877    fn relocate_address_real_addr() {
1878        let memory = Memory::new();
1879        assert_eq!(
1880            Memory::relocate_address((1, 0).into(), &memory.relocation_rules).unwrap(),
1881            MaybeRelocatable::RelocatableValue((1, 0).into()),
1882        );
1883        assert_eq!(
1884            Memory::relocate_address((1, 1).into(), &memory.relocation_rules).unwrap(),
1885            MaybeRelocatable::RelocatableValue((1, 1).into()),
1886        );
1887    }
1888
1889    #[test]
1890    #[cfg(feature = "extensive_hints")]
1891    fn relocate_address_to_integer() {
1892        let mut memory = Memory::new();
1893        memory
1894            .add_relocation_rule((-1, 0).into(), 0.into())
1895            .unwrap();
1896        memory
1897            .add_relocation_rule((-2, 0).into(), 42.into())
1898            .unwrap();
1899
1900        assert_eq!(
1901            Memory::relocate_address((-1, 0).into(), &memory.relocation_rules).unwrap(),
1902            MaybeRelocatable::Int(0.into()),
1903        );
1904        assert_eq!(
1905            Memory::relocate_address((-2, 0).into(), &memory.relocation_rules).unwrap(),
1906            MaybeRelocatable::Int(42.into()),
1907        );
1908    }
1909
1910    #[test]
1911    #[cfg(feature = "extensive_hints")]
1912    fn relocate_address_integer_no_duplicates() {
1913        let mut memory = Memory::new();
1914        memory
1915            .add_relocation_rule((-1, 0).into(), 1.into())
1916            .unwrap();
1917        assert_eq!(
1918            memory.add_relocation_rule((-1, 0).into(), 42.into()),
1919            Err(MemoryError::DuplicatedRelocation(-1))
1920        );
1921        assert_eq!(
1922            memory.add_relocation_rule((-1, 0).into(), (2, 0).into()),
1923            Err(MemoryError::DuplicatedRelocation(-1))
1924        );
1925
1926        assert_eq!(
1927            Memory::relocate_address((-1, 0).into(), &memory.relocation_rules).unwrap(),
1928            MaybeRelocatable::Int(1.into()),
1929        );
1930
1931        memory
1932            .add_relocation_rule((-2, 0).into(), (3, 0).into())
1933            .unwrap();
1934        assert_eq!(
1935            memory.add_relocation_rule((-2, 0).into(), 1.into()),
1936            Err(MemoryError::DuplicatedRelocation(-2))
1937        );
1938
1939        assert_eq!(
1940            Memory::relocate_address((-2, 0).into(), &memory.relocation_rules).unwrap(),
1941            MaybeRelocatable::RelocatableValue((3, 0).into()),
1942        );
1943    }
1944
1945    #[test]
1946    fn mark_address_as_accessed() {
1947        let mut memory = memory![((0, 0), 0)];
1948        assert!(!memory.data[0][0].is_accessed());
1949        memory.mark_as_accessed(relocatable!(0, 0));
1950        assert!(memory.data[0][0].is_accessed());
1951    }
1952
1953    #[test]
1954    fn get_amount_of_accessed_addresses_for_segment_valid() {
1955        let mut memory = memory![((0, 0), 0)];
1956        assert_eq!(
1957            memory.get_amount_of_accessed_addresses_for_segment(0),
1958            Some(0)
1959        );
1960        memory.mark_as_accessed(relocatable!(0, 0));
1961        assert_eq!(
1962            memory.get_amount_of_accessed_addresses_for_segment(0),
1963            Some(1)
1964        );
1965    }
1966
1967    #[test]
1968    fn get_amount_of_accessed_addresses_for_segment_invalid_segment() {
1969        let memory = memory![((0, 0), 0)];
1970        assert_eq!(memory.get_amount_of_accessed_addresses_for_segment(1), None);
1971    }
1972
1973    #[test]
1974    fn memory_cell_new_is_not_accessed() {
1975        let cell = MemoryCell::new(mayberelocatable!(1));
1976        assert!(!cell.is_accessed())
1977    }
1978
1979    #[test]
1980    fn memory_cell_mark_accessed() {
1981        let mut cell = MemoryCell::new(mayberelocatable!(1));
1982        cell.mark_accessed();
1983        assert!(cell.is_accessed())
1984    }
1985
1986    #[test]
1987    fn memory_cell_get_value() {
1988        let cell = MemoryCell::new(mayberelocatable!(1));
1989        assert_eq!(cell.get_value(), Some(mayberelocatable!(1)));
1990    }
1991
1992    use core::cmp::Ordering::*;
1993
1994    fn check_memcmp(
1995        lhs: (isize, usize),
1996        rhs: (isize, usize),
1997        len: usize,
1998        ord: Ordering,
1999        pos: usize,
2000    ) {
2001        let mem = memory![
2002            ((-2, 0), 1),
2003            ((-2, 1), (1, 1)),
2004            ((-2, 3), 0),
2005            ((-2, 4), 0),
2006            ((-1, 0), 1),
2007            ((-1, 1), (1, 1)),
2008            ((-1, 3), 0),
2009            ((-1, 4), 3),
2010            ((0, 0), 1),
2011            ((0, 1), (1, 1)),
2012            ((0, 3), 0),
2013            ((0, 4), 0),
2014            ((1, 0), 1),
2015            ((1, 1), (1, 1)),
2016            ((1, 3), 0),
2017            ((1, 4), 3)
2018        ];
2019        assert_eq!((ord, pos), mem.memcmp(lhs.into(), rhs.into(), len));
2020    }
2021
2022    #[test]
2023    fn insert_alloc_fails_gracefully() {
2024        let mut mem = memory![((0, 0), 1)];
2025        let err = mem.insert((0, usize::MAX >> 1).into(), Felt252::ONE);
2026        assert_eq!(err, Err(MemoryError::VecCapacityExceeded));
2027    }
2028
2029    #[test]
2030    fn insert_overflow_fails_gracefully() {
2031        let mut mem = memory![((0, 0), 1)];
2032        let err = mem.insert((0, usize::MAX).into(), Felt252::ONE);
2033        assert_eq!(err, Err(MemoryError::VecCapacityExceeded));
2034    }
2035
2036    #[test]
2037    fn memcmp() {
2038        check_memcmp((0, 0), (0, 0), 3, Equal, 3);
2039        check_memcmp((0, 0), (1, 0), 3, Equal, 3);
2040        check_memcmp((0, 0), (1, 0), 5, Less, 4);
2041        check_memcmp((1, 0), (0, 0), 5, Greater, 4);
2042        check_memcmp((2, 2), (2, 5), 8, Equal, 0);
2043        check_memcmp((0, 0), (2, 5), 8, Greater, 0);
2044        check_memcmp((2, 5), (0, 0), 8, Less, 0);
2045        check_memcmp((-2, 0), (-2, 0), 3, Equal, 3);
2046        check_memcmp((-2, 0), (-1, 0), 3, Equal, 3);
2047        check_memcmp((-2, 0), (-1, 0), 5, Less, 4);
2048        check_memcmp((-1, 0), (-2, 0), 5, Greater, 4);
2049        check_memcmp((-3, 2), (-3, 5), 8, Equal, 0);
2050        check_memcmp((-2, 0), (-3, 5), 8, Greater, 0);
2051        check_memcmp((-3, 5), (-2, 0), 8, Less, 0);
2052    }
2053
2054    #[test]
2055    fn cairo_pie_memory_from_memory() {
2056        let memory = memory![((8, 9), 3), ((1, 2), 5), ((7, 6), (1, 2))];
2057
2058        assert_eq!(
2059            CairoPieMemory::from(&memory),
2060            CairoPieMemory(vec![
2061                ((1, 2), MaybeRelocatable::from(5)),
2062                ((7, 6), MaybeRelocatable::from((1, 2))),
2063                ((8, 9), MaybeRelocatable::from(3))
2064            ])
2065        )
2066    }
2067
2068    #[test]
2069    #[cfg(not(feature = "extensive_hints"))]
2070    fn flatten_relocation_rules_chain_happy() {
2071        let mut mem = Memory::new();
2072        // temp segments just to keep indices sensible (not strictly required here)
2073        mem.temp_data = vec![vec![], vec![]];
2074
2075        //  key 0 -> (-2, 3) ; key 1 -> (10, 4)
2076        //  after flatten: key 0 -> (10, 7)
2077        mem.relocation_rules.insert(0, Relocatable::from((-2, 3)));
2078        mem.relocation_rules.insert(1, Relocatable::from((10, 4)));
2079        // sanity: an unrelated rule stays as-is
2080        mem.relocation_rules.insert(2, Relocatable::from((7, 1)));
2081
2082        assert_eq!(mem.flatten_relocation_rules(), Ok(()));
2083        assert_eq!(
2084            *mem.relocation_rules.get(&0).unwrap(),
2085            Relocatable::from((10, 7))
2086        );
2087        assert_eq!(
2088            *mem.relocation_rules.get(&1).unwrap(),
2089            Relocatable::from((10, 4))
2090        );
2091        assert_eq!(
2092            *mem.relocation_rules.get(&2).unwrap(),
2093            Relocatable::from((7, 1))
2094        );
2095    }
2096
2097    #[test]
2098    #[cfg(not(feature = "extensive_hints"))]
2099    fn flatten_relocation_rules_cycle_err() {
2100        let mut mem = Memory::new();
2101        mem.temp_data = vec![vec![]];
2102
2103        // Self-loop: key 0 -> (-1, 0)  (i.e., points back to itself)
2104        mem.relocation_rules.insert(0, Relocatable::from((-1, 0)));
2105
2106        assert_eq!(mem.flatten_relocation_rules(), Err(MemoryError::Relocation));
2107    }
2108
2109    #[test]
2110    #[cfg(feature = "extensive_hints")]
2111    fn flatten_relocation_rules_chain_happy_extensive_reloc_and_int() {
2112        let mut mem = Memory::new();
2113        mem.temp_data = vec![vec![], vec![], vec![], vec![], vec![]];
2114
2115        // ---- Chain A (ends at relocatable) ----
2116        // key 0 -> (-2, 3)  (=> key 1)
2117        // key 1 -> (10, 4)  (real)
2118        // Expect: key 0 -> (10, 7)
2119        mem.relocation_rules.insert(
2120            0,
2121            MaybeRelocatable::RelocatableValue(Relocatable::from((-2, 3))),
2122        );
2123        mem.relocation_rules.insert(
2124            1,
2125            MaybeRelocatable::RelocatableValue(Relocatable::from((10, 4))),
2126        );
2127
2128        // ---- Chain B (ends at int) ----
2129        // key 2 -> (-4, 0)  (=> key 3)
2130        // key 3 -> (-5, 0)  (=> key 4)
2131        // key 4 -> 99       (final Int)
2132        // Expect: key 2 -> 99  (offset is zero along the way)
2133        mem.relocation_rules.insert(
2134            2,
2135            MaybeRelocatable::RelocatableValue(Relocatable::from((-4, 0))),
2136        );
2137        mem.relocation_rules.insert(
2138            3,
2139            MaybeRelocatable::RelocatableValue(Relocatable::from((-5, 0))),
2140        );
2141        mem.relocation_rules
2142            .insert(4, MaybeRelocatable::Int(Felt252::from(99)));
2143
2144        assert_eq!(mem.flatten_relocation_rules(), Ok(()));
2145
2146        assert_eq!(
2147            mem.relocation_rules.get(&0),
2148            Some(&MaybeRelocatable::RelocatableValue(Relocatable::from((
2149                10, 7
2150            ))))
2151        );
2152        assert_eq!(
2153            mem.relocation_rules.get(&1),
2154            Some(&MaybeRelocatable::RelocatableValue(Relocatable::from((
2155                10, 4
2156            ))))
2157        );
2158        assert_eq!(
2159            mem.relocation_rules.get(&2),
2160            Some(&MaybeRelocatable::Int(Felt252::from(99)))
2161        );
2162    }
2163
2164    #[test]
2165    #[cfg(feature = "extensive_hints")]
2166    fn flatten_relocation_rules_int_with_non_zero_offset_err() {
2167        let mut mem = Memory::new();
2168        // temp_data length only matters for error messages; keep it >= biggest temp key + 1
2169        mem.temp_data = vec![vec![], vec![], vec![]];
2170
2171        // key 0 -> (-2, 5)  (points to key 1, offset 5)
2172        // key 1 -> (-3, 0)  (points to key 2, offset 2)
2173        // key 2 -> 7        (final Int)
2174        mem.relocation_rules.insert(
2175            0,
2176            MaybeRelocatable::RelocatableValue(Relocatable::from((-2, 5))),
2177        );
2178        mem.relocation_rules.insert(
2179            1,
2180            MaybeRelocatable::RelocatableValue(Relocatable::from((-3, 0))),
2181        );
2182        mem.relocation_rules
2183            .insert(2, MaybeRelocatable::Int(Felt252::from(7)));
2184
2185        assert_eq!(
2186            mem.flatten_relocation_rules(),
2187            Err(MemoryError::NonZeroOffset(5))
2188        );
2189    }
2190
2191    #[test]
2192    #[cfg(feature = "extensive_hints")]
2193    fn flatten_relocation_rules_cycle_err_extensive() {
2194        let mut mem = Memory::new();
2195        mem.temp_data = vec![vec![], vec![]];
2196
2197        // 2-cycle:
2198        //   key 0 -> (-1, 0)  (points to key 0)
2199        //   key 1 -> (-2, 0)  (points to key 1)
2200        mem.relocation_rules.insert(
2201            0,
2202            MaybeRelocatable::RelocatableValue(Relocatable::from((-1, 0))),
2203        );
2204        mem.relocation_rules.insert(
2205            1,
2206            MaybeRelocatable::RelocatableValue(Relocatable::from((-2, 0))),
2207        );
2208
2209        assert_eq!(mem.flatten_relocation_rules(), Err(MemoryError::Relocation));
2210    }
2211
2212    #[test]
2213    #[cfg(not(feature = "extensive_hints"))]
2214    fn flatten_relocation_rules_missing_next_err() {
2215        let mut mem = Memory::new();
2216        mem.temp_data = vec![vec![], vec![], vec![]];
2217
2218        // key 0 -> (-4, 1)  => next_key = -( -4 + 1 ) = 3
2219        // No rule for key 3, so we expect UnmappedTemporarySegment(-4).
2220        mem.relocation_rules.insert(0, Relocatable::from((-4, 1)));
2221
2222        assert_eq!(
2223            mem.flatten_relocation_rules(),
2224            Err(MemoryError::UnmappedTemporarySegment(-4))
2225        );
2226    }
2227
2228    #[test]
2229    #[cfg(feature = "extensive_hints")]
2230    fn flatten_relocation_rules_missing_next_err_extensive() {
2231        let mut mem = Memory::new();
2232        mem.temp_data = vec![vec![], vec![], vec![]];
2233
2234        // key 0 -> (-4, 0)  => next_key = 3
2235        // No rule for key 3, so we expect UnmappedTemporarySegment(-4).
2236        mem.relocation_rules.insert(
2237            0,
2238            MaybeRelocatable::RelocatableValue(Relocatable::from((-4, 0))),
2239        );
2240
2241        assert_eq!(
2242            mem.flatten_relocation_rules(),
2243            Err(MemoryError::UnmappedTemporarySegment(-4))
2244        );
2245    }
2246
2247    #[test]
2248    #[cfg(not(feature = "extensive_hints"))]
2249    fn relocate_memory_temp_chain_multi_hop() {
2250        let mut memory = Memory::new();
2251
2252        // temp segments:
2253        //  -1: [100, 200]
2254        //  -2: [7, 8, 9]
2255        memory.temp_data = vec![
2256            vec![
2257                MemoryCell::new(mayberelocatable!(100)),
2258                MemoryCell::new(mayberelocatable!(200)),
2259            ],
2260            vec![
2261                MemoryCell::new(mayberelocatable!(7)),
2262                MemoryCell::new(mayberelocatable!(8)),
2263                MemoryCell::new(mayberelocatable!(9)),
2264            ],
2265        ];
2266
2267        // Rules:
2268        //   key 0 (-1) -> (-2, 3)
2269        //   key 1 (-2) -> (5, 10)
2270        // Chain: -1 -> -2-> (5,10)  => -1 relocates to (5,13)
2271        memory
2272            .relocation_rules
2273            .insert(0, Relocatable::from((-2, 3)));
2274        memory
2275            .relocation_rules
2276            .insert(1, Relocatable::from((5, 10)));
2277
2278        // Real memory references that point into temp segments
2279        // Expect after relocation:
2280        //   (0,0): (-1,0) -> (5,13)
2281        //   (0,1): (-1,1) -> (5,14)
2282        //   (0,2): (-2,0) -> (5,10)
2283        memory.data.push(vec![
2284            MemoryCell::new(mayberelocatable!(-1, 0)),
2285            MemoryCell::new(mayberelocatable!(-1, 1)),
2286            MemoryCell::new(mayberelocatable!(-2, 0)),
2287        ]);
2288
2289        // Allocate destination segment 5
2290        while memory.data.len() <= 5 {
2291            memory.data.push(Vec::new());
2292        }
2293
2294        assert_eq!(memory.relocate_memory(), Ok(()));
2295
2296        // References updated
2297        check_memory!(
2298            memory,
2299            ((0, 0), (5, 13)),
2300            ((0, 1), (5, 14)),
2301            ((0, 2), (5, 10)),
2302            ((5, 10), 7),
2303            ((5, 11), 8),
2304            ((5, 12), 9),
2305            ((5, 13), 100),
2306            ((5, 14), 200)
2307        );
2308        assert!(memory.temp_data.is_empty());
2309    }
2310
2311    #[test]
2312    #[cfg(feature = "extensive_hints")]
2313    fn relocate_memory_temp_chain_to_int_multi_hop() {
2314        let mut memory = Memory::new();
2315
2316        // temp segments:
2317        //  -1: [123]
2318        //  -2: [456]
2319        memory.temp_data = vec![
2320            vec![MemoryCell::new(mayberelocatable!(123))],
2321            vec![MemoryCell::new(mayberelocatable!(456))],
2322        ];
2323
2324        // Rules:
2325        //   key 0 (-1) -> (-2, 0)
2326        //   key 1 (-2) -> 99 (Int)
2327        // Chain: -1 -> -2 -> 99  (offsets are zero, so collapse to Int)
2328        memory.relocation_rules.insert(
2329            0,
2330            MaybeRelocatable::RelocatableValue(Relocatable::from((-2, 0))),
2331        );
2332        memory
2333            .relocation_rules
2334            .insert(1, MaybeRelocatable::Int(Felt252::from(99)));
2335
2336        // Real memory has a reference into temp
2337        // Expect after relocation: (0,0) becomes Int(99)
2338        memory
2339            .data
2340            .push(vec![MemoryCell::new(mayberelocatable!(-1, 0))]);
2341
2342        assert_eq!(memory.relocate_memory(), Ok(()));
2343
2344        // Reference collapsed to Int
2345        assert_eq!(
2346            memory.data[0][0].get_value(),
2347            Some(MaybeRelocatable::Int(Felt252::from(99)))
2348        );
2349
2350        // The temp segments whose rules end at Int are not moved
2351        assert!(memory.temp_data.is_empty());
2352    }
2353
2354    #[test]
2355    fn add_validation_rule_out_of_order_no_shift_and_correct_validation() {
2356        let mut memory = Memory::new();
2357        memory.data.resize(4, Vec::new());
2358
2359        memory
2360            .insert_value(Relocatable::from((3, 0)), Felt252::from(3))
2361            .unwrap();
2362        memory
2363            .insert_value(Relocatable::from((1, 0)), Felt252::from(1))
2364            .unwrap();
2365
2366        let rule_seg3 = ValidationRule(Box::new(
2367            |memory: &Memory, addr: Relocatable| -> Result<Vec<Relocatable>, MemoryError> {
2368                memory.get_integer(addr)?;
2369                Ok(vec![addr])
2370            },
2371        ));
2372        let rule_seg1 = ValidationRule(Box::new(
2373            |memory: &Memory, addr: Relocatable| -> Result<Vec<Relocatable>, MemoryError> {
2374                memory.get_integer(addr)?;
2375                Ok(vec![addr])
2376            },
2377        ));
2378
2379        memory.add_validation_rule(3, rule_seg3);
2380        memory.add_validation_rule(1, rule_seg1);
2381
2382        assert!(memory.validation_rules[3].is_some());
2383        assert!(memory.validation_rules[1].is_some());
2384
2385        assert_eq!(memory.validate_existing_memory(), Ok(()));
2386        assert!(memory
2387            .validated_addresses
2388            .contains(&Relocatable::from((3, 0))));
2389        assert!(memory
2390            .validated_addresses
2391            .contains(&Relocatable::from((1, 0))));
2392    }
2393}