Skip to main content

cairo_vm/vm/vm_memory/
memory_segments.rs

1use core::cmp::max;
2use core::fmt;
3use std::collections::HashSet;
4
5use crate::vm::runners::cairo_pie::CairoPieMemory;
6use crate::Felt252;
7use num_traits::Zero;
8
9use crate::vm::runners::cairo_runner::CairoArg;
10use std::{any::Any, collections::HashMap};
11
12use crate::{
13    types::relocatable::{MaybeRelocatable, Relocatable},
14    vm::{
15        errors::memory_errors::MemoryError, errors::vm_errors::VirtualMachineError,
16        vm_memory::memory::Memory,
17    },
18};
19
20use super::memory::MemoryCell;
21
22pub struct MemorySegmentManager {
23    pub segment_sizes: HashMap<usize, usize>,
24    pub segment_used_sizes: Option<Vec<usize>>,
25    pub memory: Memory,
26    // A map from segment index to a list of pairs (offset, page_id) that constitute the
27    // public memory. Note that the offset is absolute (not based on the page_id).
28    pub public_memory_offsets: HashMap<usize, Vec<(usize, usize)>>,
29    // Segment index of the zero segment index, a memory segment filled with zeroes, used exclusively by builtin runners
30    // This segment will never have index 0 so we use 0 to represent uninitialized value
31    zero_segment_index: usize,
32    // Segment size of the zero segment index
33    zero_segment_size: usize,
34}
35
36impl MemorySegmentManager {
37    /// Number of segments in the real memory
38    pub fn num_segments(&self) -> usize {
39        self.memory.data.len()
40    }
41
42    /// Number of segments in the temporary memory
43    pub fn num_temp_segments(&self) -> usize {
44        self.memory.temp_data.len()
45    }
46
47    ///Adds a new segment and returns its starting location as a Relocatable value. Its segment index will always be positive.
48    pub fn add(&mut self) -> Relocatable {
49        self.memory.data.push(Vec::new());
50        Relocatable {
51            segment_index: (self.memory.data.len() - 1) as isize,
52            offset: 0,
53        }
54    }
55
56    /// Adds a new temporary segment and returns its starting location as a Relocatable value. Its segment index will always be negative.
57    pub fn add_temporary_segment(&mut self) -> Relocatable {
58        self.memory.temp_data.push(Vec::new());
59        Relocatable {
60            // We dont substract 1 as we need to take into account the index shift (temporary memory begins from -1 instead of 0)
61            segment_index: -((self.memory.temp_data.len()) as isize),
62            offset: 0,
63        }
64    }
65
66    ///Writes data into the memory from address ptr and returns the first address after the data.
67    pub fn load_data(
68        &mut self,
69        ptr: Relocatable,
70        data: &[MaybeRelocatable],
71    ) -> Result<Relocatable, MemoryError> {
72        // Starting from the end ensures any necessary resize
73        // is performed once with enough room for everything
74        for (num, value) in data.iter().enumerate().rev() {
75            self.memory.insert((ptr + num)?, value)?;
76        }
77        (ptr + data.len()).map_err(MemoryError::Math)
78    }
79
80    pub fn new() -> MemorySegmentManager {
81        MemorySegmentManager {
82            segment_sizes: HashMap::new(),
83            segment_used_sizes: None,
84            public_memory_offsets: HashMap::new(),
85            memory: Memory::new(),
86            zero_segment_index: 0,
87            zero_segment_size: 0,
88        }
89    }
90
91    /// Calculates the size of each memory segment.
92    pub fn compute_effective_sizes(&mut self) -> &Vec<usize> {
93        self.segment_used_sizes
94            .get_or_insert_with(|| self.memory.data.iter().map(Vec::len).collect())
95    }
96
97    ///Returns the number of used segments if they have been computed.
98    ///Returns None otherwise.
99    pub fn get_segment_used_size(&self, index: usize) -> Option<usize> {
100        self.segment_used_sizes.as_ref()?.get(index).copied()
101    }
102
103    pub fn get_segment_size(&self, index: usize) -> Option<usize> {
104        self.segment_sizes
105            .get(&index)
106            .cloned()
107            .or_else(|| self.get_segment_used_size(index))
108    }
109
110    ///Returns a vector containing the first relocated address of each memory segment
111    pub fn relocate_segments(&self) -> Result<Vec<usize>, MemoryError> {
112        let first_addr = 1;
113        let mut relocation_table = vec![first_addr];
114        match &self.segment_used_sizes {
115            Some(segment_used_sizes) => {
116                for (i, _size) in segment_used_sizes.iter().enumerate() {
117                    let segment_size = self
118                        .get_segment_size(i)
119                        .ok_or(MemoryError::MissingSegmentUsedSizes)?;
120
121                    relocation_table.push(relocation_table[i] + segment_size);
122                }
123            }
124            None => return Err(MemoryError::MissingSegmentUsedSizes),
125        }
126        //The last value corresponds to the total amount of elements across all segments, which isnt needed for relocation.
127        relocation_table.pop();
128        Ok(relocation_table)
129    }
130
131    pub fn gen_arg(&mut self, arg: &dyn Any) -> Result<MaybeRelocatable, MemoryError> {
132        if let Some(value) = arg.downcast_ref::<MaybeRelocatable>() {
133            Ok(value.clone())
134        } else if let Some(value) = arg.downcast_ref::<Vec<MaybeRelocatable>>() {
135            let base = self.add();
136            self.write_arg(base, value)?;
137            Ok(base.into())
138        } else if let Some(value) = arg.downcast_ref::<Vec<Relocatable>>() {
139            let base = self.add();
140            self.write_arg(base, value)?;
141            Ok(base.into())
142        } else {
143            Err(MemoryError::GenArgInvalidType)
144        }
145    }
146
147    pub fn gen_cairo_arg(
148        &mut self,
149        arg: &CairoArg,
150    ) -> Result<MaybeRelocatable, VirtualMachineError> {
151        match arg {
152            CairoArg::Single(value) => Ok(value.clone()),
153            CairoArg::Array(values) => {
154                let base = self.add();
155                self.load_data(base, values)?;
156                Ok(base.into())
157            }
158            CairoArg::Composed(cairo_args) => {
159                let args = cairo_args
160                    .iter()
161                    .map(|cairo_arg| self.gen_cairo_arg(cairo_arg))
162                    .collect::<Result<Vec<MaybeRelocatable>, VirtualMachineError>>()?;
163                let base = self.add();
164                self.load_data(base, &args)?;
165                Ok(base.into())
166            }
167        }
168    }
169
170    pub fn write_arg(
171        &mut self,
172        ptr: Relocatable,
173        arg: &dyn Any,
174    ) -> Result<MaybeRelocatable, MemoryError> {
175        if let Some(vector) = arg.downcast_ref::<Vec<MaybeRelocatable>>() {
176            self.load_data(ptr, vector).map(Into::into)
177        } else if let Some(vector) = arg.downcast_ref::<Vec<Relocatable>>() {
178            let data: &Vec<MaybeRelocatable> = &vector.iter().map(|value| value.into()).collect();
179            self.load_data(ptr, data).map(Into::into)
180        } else {
181            Err(MemoryError::WriteArg)
182        }
183    }
184
185    pub fn is_valid_memory_value(&self, value: &MaybeRelocatable) -> Result<bool, MemoryError> {
186        match &self.segment_used_sizes {
187            Some(segment_used_sizes) => match value {
188                MaybeRelocatable::Int(_) => Ok(true),
189                MaybeRelocatable::RelocatableValue(relocatable) => {
190                    let segment_index: usize =
191                        relocatable.segment_index.try_into().map_err(|_| {
192                            MemoryError::AddressInTemporarySegment(relocatable.segment_index)
193                        })?;
194
195                    Ok(segment_index < segment_used_sizes.len())
196                }
197            },
198            None => Err(MemoryError::MissingSegmentUsedSizes),
199        }
200    }
201
202    pub fn is_accessed(&self, addr: &Relocatable) -> Result<bool, MemoryError> {
203        self.memory.is_accessed(addr)
204    }
205
206    /// Counts the memory holes (aka unaccessed memory cells) in memory
207    /// # Parameters
208    /// - `builtin_segment_indexes`: Set representing the segments indexes of the builtins initialized in the VM, except for the output builtin.
209    pub fn get_memory_holes(
210        &self,
211        builtin_segment_indexes: HashSet<usize>,
212    ) -> Result<usize, MemoryError> {
213        let data = &self.memory.data;
214        let mut memory_holes = 0;
215        for i in 0..data.len() {
216            // Instead of marking all of the builtin segment's address as accessed, we just skip them when counting memory holes
217            // Output builtin is extempt from this behaviour
218            if builtin_segment_indexes.contains(&i) {
219                continue;
220            }
221            let accessed_amount =
222                // Instead of marking the values in the zero segment until zero_segment_size as accessed we use zero_segment_size as accessed_amount
223                if self.has_zero_segment() && i == self.zero_segment_index {
224                    self.zero_segment_size
225                } else {
226                    match self.memory.get_amount_of_accessed_addresses_for_segment(i) {
227                        Some(accessed_amount) if accessed_amount > 0 => accessed_amount,
228                        _ => continue,
229                    }
230                };
231            let segment_size = self
232                .get_segment_size(i)
233                .ok_or(MemoryError::MissingSegmentUsedSizes)?;
234            if accessed_amount > segment_size {
235                return Err(MemoryError::SegmentHasMoreAccessedAddressesThanSize(
236                    Box::new((i, accessed_amount, segment_size)),
237                ));
238            }
239            memory_holes += segment_size - accessed_amount;
240        }
241        Ok(memory_holes)
242    }
243
244    /// Returns a list of addresses of memory cells that constitute the public memory.
245    /// segment_offsets is the result of self.relocate_segments()
246    pub fn get_public_memory_addresses(
247        &self,
248        segment_offsets: &[usize],
249    ) -> Result<Vec<(usize, usize)>, MemoryError> {
250        let mut addresses = Vec::with_capacity(self.num_segments());
251        let empty_vec = vec![];
252        for segment_index in 0..self.num_segments() {
253            let offsets = &self
254                .public_memory_offsets
255                .get(&segment_index)
256                .unwrap_or(&empty_vec);
257            let segment_start = segment_offsets
258                .get(segment_index)
259                .ok_or(MemoryError::MalformedPublicMemory)?;
260            for (offset, page_id) in offsets.iter() {
261                addresses.push((segment_start + offset, *page_id));
262            }
263        }
264        Ok(addresses)
265    }
266
267    // Writes the following information for the given segment:
268    // * size - The size of the segment (to be used in relocate_segments).
269    // * public_memory - A list of offsets for memory cells that will be considered as public
270    // memory.
271    pub fn finalize(
272        &mut self,
273        size: Option<usize>,
274        segment_index: usize,
275        public_memory: Option<&Vec<(usize, usize)>>,
276    ) {
277        if let Some(size) = size {
278            self.segment_sizes.insert(segment_index, size);
279        }
280        self.public_memory_offsets
281            .insert(segment_index, public_memory.cloned().unwrap_or_default());
282    }
283
284    pub fn has_zero_segment(&self) -> bool {
285        !self.zero_segment_index.is_zero()
286    }
287
288    // Creates the zero segment if it wasn't previously created
289    // Fills the segment with the value 0 until size is reached
290    // Returns the index of the zero segment
291    pub(crate) fn add_zero_segment(&mut self, size: usize) -> usize {
292        if !self.has_zero_segment() {
293            self.zero_segment_index = self.add().segment_index as usize;
294        }
295
296        // Fil zero segment with zero values until size is reached
297        for _ in 0..(size.saturating_sub(self.zero_segment_size)) {
298            // As zero_segment_index is only accessible to the segment manager
299            // we can asume that it is always valid and index direcly into it
300            self.memory.data[self.zero_segment_index].push(MemoryCell::new(Felt252::ZERO.into()))
301        }
302        self.zero_segment_size = max(self.zero_segment_size, size);
303        self.zero_segment_index
304    }
305
306    // Finalizes the zero segment and clears it's tracking data from the manager
307    pub(crate) fn finalize_zero_segment(&mut self) {
308        if self.has_zero_segment() {
309            self.finalize(Some(self.zero_segment_size), self.zero_segment_index, None);
310            self.zero_segment_index = 0;
311            self.zero_segment_size = 0;
312        }
313    }
314
315    pub(crate) fn load_pie_memory(
316        &mut self,
317        pie_memory: &CairoPieMemory,
318        n_extra_segments: usize,
319    ) -> Result<(), MemoryError> {
320        // Create extra segments
321        for _ in 0..n_extra_segments {
322            self.add();
323        }
324        // Load previous execution memory
325        for ((si, so), val) in pie_memory.0.iter() {
326            self.memory.insert((*si as isize, *so).into(), val)?;
327        }
328        Ok(())
329    }
330}
331
332impl Default for MemorySegmentManager {
333    fn default() -> Self {
334        Self::new()
335    }
336}
337
338impl fmt::Display for MemorySegmentManager {
339    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
340        writeln!(f, "Memory:\n{}", self.memory)?;
341        if let Some(used_sizes) = &self.segment_used_sizes {
342            writeln!(f, "Segment Info:")?;
343            for (index, used_size) in used_sizes.iter().enumerate() {
344                writeln!(
345                    f,
346                    "Segment Number: {}, Used Size: {}, Size {}",
347                    index,
348                    used_size,
349                    self.segment_sizes
350                        .get(&index)
351                        .map(|n| n.to_string())
352                        .unwrap_or(String::from("None"))
353                )?;
354            }
355        }
356        Ok(())
357    }
358}
359
360#[cfg(test)]
361mod tests {
362    use super::*;
363    use crate::Felt252;
364    use crate::{relocatable, utils::test_utils::*, vm::vm_memory::memory::MemoryCell};
365    use assert_matches::assert_matches;
366
367    #[test]
368    fn add_segment_no_size() {
369        let mut segments = MemorySegmentManager::new();
370        let base = segments.add();
371        assert_eq!(base, relocatable!(0, 0));
372        assert_eq!(segments.num_segments(), 1);
373    }
374
375    #[test]
376    fn add_segment_no_size_test_two_segments() {
377        let mut segments = MemorySegmentManager::new();
378        let mut _base = segments.add();
379        _base = segments.add();
380        assert_eq!(
381            _base,
382            Relocatable {
383                segment_index: 1,
384                offset: 0
385            }
386        );
387        assert_eq!(segments.num_segments(), 2);
388    }
389
390    #[test]
391    fn add_one_temporary_segment() {
392        let mut segments = MemorySegmentManager::new();
393        let base = segments.add_temporary_segment();
394        assert_eq!(base, relocatable!(-1, 0));
395        assert_eq!(segments.num_temp_segments(), 1);
396    }
397
398    #[test]
399    fn add_two_temporary_segments() {
400        let mut segments = MemorySegmentManager::new();
401        segments.add_temporary_segment();
402        let base = segments.add_temporary_segment();
403        assert_eq!(
404            base,
405            Relocatable {
406                segment_index: -2,
407                offset: 0
408            }
409        );
410        assert_eq!(segments.num_temp_segments(), 2);
411    }
412
413    #[test]
414    fn load_data_empty() {
415        let data = Vec::new();
416        let ptr = Relocatable::from((0, 3));
417        let mut segments = MemorySegmentManager::new();
418        let current_ptr = segments.load_data(ptr, &data).unwrap();
419        assert_eq!(current_ptr, Relocatable::from((0, 3)));
420    }
421
422    #[test]
423    fn load_data_one_element() {
424        let data = vec![MaybeRelocatable::from(Felt252::from(4))];
425        let ptr = Relocatable::from((0, 0));
426        let mut segments = MemorySegmentManager::new();
427        segments.add();
428        let current_ptr = segments.load_data(ptr, &data).unwrap();
429        assert_eq!(current_ptr, Relocatable::from((0, 1)));
430        assert_eq!(
431            segments.memory.get(&ptr).unwrap().as_ref(),
432            &MaybeRelocatable::from(Felt252::from(4))
433        );
434    }
435
436    #[test]
437    fn load_data_three_elements() {
438        let data = vec![
439            MaybeRelocatable::from(Felt252::from(4)),
440            MaybeRelocatable::from(Felt252::from(5)),
441            MaybeRelocatable::from(Felt252::from(6)),
442        ];
443        let ptr = Relocatable::from((0, 0));
444        let mut segments = MemorySegmentManager::new();
445        segments.add();
446        let current_ptr = segments.load_data(ptr, &data).unwrap();
447        assert_eq!(current_ptr, Relocatable::from((0, 3)));
448
449        assert_eq!(
450            segments.memory.get(&ptr).unwrap().as_ref(),
451            &MaybeRelocatable::from(Felt252::from(4))
452        );
453        assert_eq!(
454            segments
455                .memory
456                .get(&MaybeRelocatable::from((0, 1)))
457                .unwrap()
458                .as_ref(),
459            &MaybeRelocatable::from(Felt252::from(5))
460        );
461        assert_eq!(
462            segments
463                .memory
464                .get(&MaybeRelocatable::from((0, 2)))
465                .unwrap()
466                .as_ref(),
467            &MaybeRelocatable::from(Felt252::from(6))
468        );
469    }
470    #[test]
471    fn compute_effective_sizes_for_one_segment_memory() {
472        let mut segments = segments![((0, 0), 1), ((0, 1), 1), ((0, 2), 1)];
473        segments.compute_effective_sizes();
474        assert_eq!(Some(vec![3]), segments.segment_used_sizes);
475    }
476
477    #[test]
478    fn compute_effective_sizes_for_one_segment_memory_with_gap() {
479        let mut segments = MemorySegmentManager::new();
480        segments.add();
481        segments
482            .memory
483            .insert(
484                Relocatable::from((0, 6)),
485                &MaybeRelocatable::from(Felt252::from(1)),
486            )
487            .unwrap();
488        segments.compute_effective_sizes();
489        assert_eq!(Some(vec![7]), segments.segment_used_sizes);
490    }
491
492    #[test]
493    fn compute_effective_sizes_for_one_segment_memory_with_gaps() {
494        let mut segments = segments![((0, 3), 1), ((0, 4), 1), ((0, 7), 1), ((0, 9), 1)];
495        segments.compute_effective_sizes();
496        assert_eq!(Some(vec![10]), segments.segment_used_sizes);
497    }
498
499    #[test]
500    fn compute_effective_sizes_for_three_segment_memory() {
501        let mut segments = segments![
502            ((0, 0), 1),
503            ((0, 1), 1),
504            ((0, 2), 1),
505            ((1, 0), 1),
506            ((1, 1), 1),
507            ((1, 2), 1),
508            ((2, 0), 1),
509            ((2, 1), 1),
510            ((2, 2), 1)
511        ];
512        segments.compute_effective_sizes();
513        assert_eq!(Some(vec![3, 3, 3]), segments.segment_used_sizes);
514    }
515
516    #[test]
517    fn compute_effective_sizes_for_three_segment_memory_with_gaps() {
518        let mut segments = segments![
519            ((0, 2), 1),
520            ((0, 5), 1),
521            ((0, 7), 1),
522            ((1, 1), 1),
523            ((2, 2), 1),
524            ((2, 4), 1),
525            ((2, 7), 1)
526        ];
527        segments.compute_effective_sizes();
528        assert_eq!(Some(vec![8, 2, 8]), segments.segment_used_sizes);
529    }
530
531    #[test]
532    fn get_segment_used_size_after_computing_used() {
533        let mut segments = segments![
534            ((0, 2), 1),
535            ((0, 5), 1),
536            ((0, 7), 1),
537            ((1, 1), 1),
538            ((2, 2), 1),
539            ((2, 4), 1),
540            ((2, 7), 1)
541        ];
542        segments.compute_effective_sizes();
543        assert_eq!(Some(8), segments.get_segment_used_size(2));
544    }
545
546    #[test]
547    fn get_segment_used_size_before_computing_used() {
548        let segments = MemorySegmentManager::new();
549        assert_eq!(None, segments.get_segment_used_size(2));
550    }
551
552    #[test]
553    fn relocate_segments_one_segment() {
554        let mut segments = MemorySegmentManager::new();
555        segments.segment_used_sizes = Some(vec![3]);
556        assert_eq!(
557            segments
558                .relocate_segments()
559                .expect("Couldn't relocate after compute effective sizes"),
560            vec![1]
561        )
562    }
563
564    #[test]
565    fn relocate_segments_five_segment() {
566        let mut segments = MemorySegmentManager::new();
567        segments.segment_used_sizes = Some(vec![3, 3, 56, 78, 8]);
568        assert_eq!(
569            segments
570                .relocate_segments()
571                .expect("Couldn't relocate after compute effective sizes"),
572            vec![1, 4, 7, 63, 141]
573        )
574    }
575
576    #[test]
577    fn write_arg_relocatable() {
578        let data = vec![
579            Relocatable::from((0, 1)),
580            Relocatable::from((0, 2)),
581            Relocatable::from((0, 3)),
582        ];
583        let ptr = Relocatable::from((1, 0));
584        let mut segments = MemorySegmentManager::new();
585        for _ in 0..2 {
586            segments.add();
587        }
588
589        let exec = segments.write_arg(ptr, &data);
590
591        assert_eq!(exec, Ok(MaybeRelocatable::from((1, 3))));
592        assert_eq!(
593            segments.memory.data[1],
594            vec![
595                MemoryCell::new(MaybeRelocatable::from((0, 1))),
596                MemoryCell::new(MaybeRelocatable::from((0, 2))),
597                MemoryCell::new(MaybeRelocatable::from((0, 3))),
598            ]
599        );
600    }
601
602    #[test]
603    fn write_arg_invalid_type() {
604        let data = vec!["Invalid Type 1", "Invalid Type 2"];
605        let ptr = Relocatable::from((1, 0));
606        let mut segments = MemorySegmentManager::new();
607        for _ in 0..2 {
608            segments.add();
609        }
610
611        let exec = segments.write_arg(ptr, &data);
612
613        assert_eq!(exec, Err(MemoryError::WriteArg));
614        assert!(segments.memory.data[1].is_empty())
615    }
616
617    #[test]
618    fn segment_default() {
619        let segment_mng_new = MemorySegmentManager::new();
620        let segment_mng_def: MemorySegmentManager = Default::default();
621        assert_eq!(
622            segment_mng_new.num_segments(),
623            segment_mng_def.num_segments()
624        );
625        assert_eq!(
626            segment_mng_new.segment_used_sizes,
627            segment_mng_def.segment_used_sizes
628        );
629    }
630
631    #[test]
632    fn is_valid_memory_value_missing_effective_sizes() {
633        let segment_manager = MemorySegmentManager::new();
634
635        assert_eq!(
636            segment_manager.is_valid_memory_value(&mayberelocatable!(0)),
637            Err(MemoryError::MissingSegmentUsedSizes),
638        );
639    }
640
641    #[test]
642    fn is_valid_memory_value_temporary_segment() {
643        let mut segment_manager = MemorySegmentManager::new();
644
645        segment_manager.segment_used_sizes = Some(vec![10]);
646        assert_eq!(
647            segment_manager.is_valid_memory_value(&mayberelocatable!(-1, 0)),
648            Err(MemoryError::AddressInTemporarySegment(-1)),
649        );
650    }
651
652    #[test]
653    fn is_valid_memory_value_invalid_segment() {
654        let mut segment_manager = MemorySegmentManager::new();
655
656        segment_manager.segment_used_sizes = Some(vec![10]);
657        assert_eq!(
658            segment_manager.is_valid_memory_value(&mayberelocatable!(1, 0)),
659            Ok(false),
660        );
661    }
662
663    #[test]
664    fn is_valid_memory_value() {
665        let mut segment_manager = MemorySegmentManager::new();
666
667        segment_manager.segment_used_sizes = Some(vec![10]);
668        assert_eq!(
669            segment_manager.is_valid_memory_value(&mayberelocatable!(0, 5)),
670            Ok(true),
671        );
672    }
673
674    #[test]
675    fn is_valid_memory_value_felt() {
676        let mut segment_manager = MemorySegmentManager::new();
677
678        segment_manager.segment_used_sizes = Some(vec![10]);
679        assert_eq!(
680            segment_manager.is_valid_memory_value(&mayberelocatable!(1)),
681            Ok(true),
682        );
683    }
684
685    #[test]
686    fn get_memory_holes_missing_segment_used_sizes() {
687        let mut memory_segment_manager = MemorySegmentManager::new();
688        memory_segment_manager.memory = memory![((0, 0), 0)];
689        memory_segment_manager
690            .memory
691            .mark_as_accessed((0, 0).into());
692        assert_eq!(
693            memory_segment_manager.get_memory_holes(HashSet::new()),
694            Err(MemoryError::MissingSegmentUsedSizes),
695        );
696    }
697
698    #[test]
699    fn get_memory_holes_out_of_address_offset_bigger_than_size() {
700        let mut memory_segment_manager = MemorySegmentManager::new();
701        memory_segment_manager.segment_used_sizes = Some(vec![2]);
702        memory_segment_manager.memory = memory![((0, 0), 1), ((0, 1), 1), ((0, 2), 2)];
703        for i in 0..3 {
704            memory_segment_manager
705                .memory
706                .mark_as_accessed((0, i).into());
707        }
708        assert_eq!(
709            memory_segment_manager.get_memory_holes(HashSet::new()),
710            Err(MemoryError::SegmentHasMoreAccessedAddressesThanSize(
711                Box::new((0, 3, 2))
712            )),
713        );
714    }
715
716    #[test]
717    fn get_memory_holes_empty() {
718        let mut memory_segment_manager = MemorySegmentManager::new();
719        memory_segment_manager.segment_used_sizes = Some(Vec::new());
720        assert_eq!(
721            memory_segment_manager.get_memory_holes(HashSet::new()),
722            Ok(0),
723        );
724    }
725
726    #[test]
727    fn get_memory_holes_empty2() {
728        let mut memory_segment_manager = MemorySegmentManager::new();
729        memory_segment_manager.segment_used_sizes = Some(vec![4]);
730        assert_eq!(
731            memory_segment_manager.get_memory_holes(HashSet::new()),
732            Ok(0),
733        );
734    }
735
736    #[test]
737    fn get_memory_holes() {
738        let mut memory_segment_manager = MemorySegmentManager::new();
739        memory_segment_manager.segment_used_sizes = Some(vec![10]);
740        memory_segment_manager.memory = memory![
741            ((0, 0), 0),
742            ((0, 1), 0),
743            ((0, 2), 0),
744            ((0, 3), 0),
745            ((0, 6), 0),
746            ((0, 7), 0),
747            ((0, 8), 0),
748            ((0, 9), 0)
749        ];
750        for i in [0, 1, 2, 3, 6, 7, 8, 9] {
751            memory_segment_manager
752                .memory
753                .mark_as_accessed((0, i).into());
754        }
755        assert_eq!(
756            memory_segment_manager.get_memory_holes(HashSet::new()),
757            Ok(2),
758        );
759    }
760
761    #[test]
762    fn get_memory_holes2() {
763        let mut memory_segment_manager = MemorySegmentManager::new();
764
765        memory_segment_manager.segment_sizes = HashMap::from([(0, 15)]);
766        memory_segment_manager.memory = memory![
767            ((0, 0), 0),
768            ((0, 1), 0),
769            ((0, 2), 0),
770            ((0, 3), 0),
771            ((0, 6), 0),
772            ((0, 7), 0),
773            ((0, 8), 0),
774            ((0, 9), 0)
775        ];
776        memory_segment_manager.segment_used_sizes = Some(vec![10]);
777        for i in [0, 1, 2, 3, 6, 7, 8, 9] {
778            memory_segment_manager
779                .memory
780                .mark_as_accessed((0, i).into());
781        }
782        assert_eq!(
783            memory_segment_manager.get_memory_holes(HashSet::new()),
784            Ok(7),
785        );
786    }
787
788    #[test]
789    fn get_memory_size_missing_segment() {
790        let memory_segment_manager = MemorySegmentManager::new();
791
792        assert_eq!(memory_segment_manager.get_segment_size(0), None);
793    }
794
795    #[test]
796    fn get_memory_size_used() {
797        let mut memory_segment_manager = MemorySegmentManager::new();
798        memory_segment_manager.segment_used_sizes = Some(vec![5]);
799
800        assert_eq!(memory_segment_manager.get_segment_size(0), Some(5));
801    }
802
803    #[test]
804    fn get_memory_size() {
805        let mut memory_segment_manager = MemorySegmentManager::new();
806        memory_segment_manager.segment_sizes = HashMap::from([(0, 5)]);
807
808        assert_eq!(memory_segment_manager.get_segment_size(0), Some(5));
809    }
810
811    #[test]
812    fn get_memory_size2() {
813        let mut memory_segment_manager = MemorySegmentManager::new();
814        memory_segment_manager.segment_sizes = HashMap::from([(0, 5)]);
815        memory_segment_manager.segment_used_sizes = Some(vec![3]);
816
817        assert_eq!(memory_segment_manager.get_segment_size(0), Some(5));
818    }
819
820    /// Test that the call to .gen_arg() with a relocatable just passes the
821    /// value through.
822    #[test]
823    fn gen_arg_relocatable() {
824        let mut memory_segment_manager = MemorySegmentManager::new();
825
826        assert_matches!(
827            memory_segment_manager.gen_arg(&mayberelocatable!(0, 0)),
828            Ok(x) if x == mayberelocatable!(0, 0)
829        );
830    }
831
832    /// Test that the call to .gen_arg() with a bigint and no prime number just
833    /// passes the value through.
834    #[test]
835    fn gen_arg_bigint() {
836        let mut memory_segment_manager = MemorySegmentManager::new();
837
838        assert_matches!(
839            memory_segment_manager.gen_arg(&mayberelocatable!(1234)),
840            Ok(x) if x == mayberelocatable!(1234)
841        );
842    }
843
844    /// Test that the call to .gen_arg() with a Vec<MaybeRelocatable> writes its
845    /// contents into a new segment and returns a pointer to it.
846    #[test]
847    fn gen_arg_vec() {
848        let mut memory_segment_manager = MemorySegmentManager::new();
849
850        assert_matches!(
851            memory_segment_manager.gen_arg(
852                &vec![
853                    mayberelocatable!(0),
854                    mayberelocatable!(1),
855                    mayberelocatable!(2),
856                    mayberelocatable!(3),
857                    mayberelocatable!(0, 0),
858                    mayberelocatable!(0, 1),
859                    mayberelocatable!(0, 2),
860                    mayberelocatable!(0, 3),
861                ],
862            ),
863            Ok(x) if x == mayberelocatable!(0, 0)
864        );
865    }
866
867    /// Test that the call to .gen_arg() with a Vec<MaybeRelocatable::Relocatable>
868    /// writes its contents into a new segment and returns a pointer to it.
869    #[test]
870    fn gen_arg_vec_mayberelocatables() {
871        let mut memory_segment_manager = MemorySegmentManager::new();
872
873        assert_matches!(
874            memory_segment_manager.gen_arg(
875                &vec![
876                    MaybeRelocatable::from((0, 0)),
877                    MaybeRelocatable::from((0, 1)),
878                    MaybeRelocatable::from((0, 2)),
879                    MaybeRelocatable::from((0, 3)),
880                ],
881            ),
882            Ok(x) if x == mayberelocatable!(0, 0)
883        );
884        assert_eq!(
885            memory_segment_manager.memory.data[0],
886            vec![
887                MemoryCell::new(MaybeRelocatable::from((0, 0))),
888                MemoryCell::new(MaybeRelocatable::from((0, 1))),
889                MemoryCell::new(MaybeRelocatable::from((0, 2))),
890                MemoryCell::new(MaybeRelocatable::from((0, 3))),
891            ],
892        );
893    }
894
895    /// Test that call to .gen_arg() with a Vec<Relocatable> writes its
896    /// contents into a new segment and returns a pointer to it.
897    #[test]
898    fn gen_arg_vec_relocatables() {
899        let mut memory_segment_manager = MemorySegmentManager::new();
900
901        assert_matches!(
902            memory_segment_manager.gen_arg(
903                &vec![
904                    Relocatable::from((0, 0)),
905                    Relocatable::from((0, 1)),
906                    Relocatable::from((0, 2)),
907                    Relocatable::from((0, 3)),
908                ],
909            ),
910            Ok(x) if x == mayberelocatable!(0, 0)
911        );
912        assert_eq!(
913            memory_segment_manager.memory.data[0],
914            vec![
915                MemoryCell::new(MaybeRelocatable::from((0, 0))),
916                MemoryCell::new(MaybeRelocatable::from((0, 1))),
917                MemoryCell::new(MaybeRelocatable::from((0, 2))),
918                MemoryCell::new(MaybeRelocatable::from((0, 3))),
919            ],
920        );
921    }
922
923    /// Test that the call to .gen_arg() with any other argument returns a not
924    /// implemented error.
925    #[test]
926    fn gen_arg_invalid_type() {
927        let mut memory_segment_manager = MemorySegmentManager::new();
928
929        assert_matches!(
930            memory_segment_manager.gen_arg(&""),
931            Err(MemoryError::GenArgInvalidType)
932        );
933    }
934
935    #[test]
936    fn finalize_no_size_nor_memory() {
937        let mut segments = MemorySegmentManager::new();
938        segments.finalize(None, 0, None);
939        assert!(segments.memory.data.is_empty());
940        assert!(segments.memory.temp_data.is_empty());
941        assert_eq!(segments.public_memory_offsets, HashMap::from([(0, vec![])]));
942        assert_eq!(segments.num_segments(), 0);
943        assert_eq!(segments.num_temp_segments(), 0);
944    }
945
946    #[test]
947    fn finalize_no_memory() {
948        let mut segments = MemorySegmentManager::new();
949        segments.finalize(Some(42), 0, None);
950        assert_eq!(segments.public_memory_offsets, HashMap::from([(0, vec![])]));
951        assert_eq!(segments.segment_sizes, HashMap::from([(0, 42)]));
952    }
953
954    #[test]
955    fn finalize_no_size() {
956        let mut segments = MemorySegmentManager::new();
957        segments.finalize(None, 0, Some(&vec![(1_usize, 2_usize)]));
958        assert_eq!(
959            segments.public_memory_offsets,
960            HashMap::from([(0_usize, vec![(1_usize, 2_usize)])])
961        );
962        assert!(segments.segment_sizes.is_empty());
963    }
964
965    #[test]
966    fn finalize_all_args() {
967        let mut segments = MemorySegmentManager::new();
968        segments.finalize(Some(42), 0, Some(&vec![(1_usize, 2_usize)]));
969        assert_eq!(
970            segments.public_memory_offsets,
971            HashMap::from([(0_usize, vec![(1_usize, 2_usize)])])
972        );
973        assert_eq!(segments.segment_sizes, HashMap::from([(0, 42)]));
974    }
975
976    #[test]
977    fn gen_cairo_arg_single() {
978        let mut memory_segment_manager = MemorySegmentManager::new();
979
980        assert_matches!(
981            memory_segment_manager.gen_cairo_arg(&mayberelocatable!(1234).into()),
982            Ok(x) if x == mayberelocatable!(1234)
983        );
984    }
985
986    #[test]
987    fn gen_cairo_arg_array() {
988        let mut memory_segment_manager = MemorySegmentManager::new();
989
990        assert_matches!(
991            memory_segment_manager.gen_cairo_arg(
992                &vec![
993                    mayberelocatable!(0),
994                    mayberelocatable!(1),
995                    mayberelocatable!(2),
996                    mayberelocatable!(3),
997                    mayberelocatable!(0, 0),
998                    mayberelocatable!(0, 1),
999                    mayberelocatable!(0, 2),
1000                    mayberelocatable!(0, 3),
1001                ]
1002                .into(),
1003            ),
1004            Ok(x) if x == mayberelocatable!(0, 0)
1005        );
1006    }
1007
1008    #[test]
1009    fn gen_cairo_arg_composed() {
1010        let mut memory_segment_manager = MemorySegmentManager::new();
1011        let cairo_args = CairoArg::Composed(vec![
1012            CairoArg::Array(vec![
1013                mayberelocatable!(0),
1014                mayberelocatable!(1),
1015                mayberelocatable!(2),
1016            ]),
1017            CairoArg::Single(mayberelocatable!(1234)),
1018            CairoArg::Single(mayberelocatable!(5678)),
1019            CairoArg::Array(vec![
1020                mayberelocatable!(3),
1021                mayberelocatable!(4),
1022                mayberelocatable!(5),
1023            ]),
1024        ]);
1025
1026        assert_matches!(
1027            memory_segment_manager.gen_cairo_arg(&cairo_args),
1028            Ok(x) if x == mayberelocatable!(2, 0)
1029        );
1030    }
1031
1032    #[test]
1033    fn test_add_zero_segment() {
1034        // Create MemorySegmentManager with program and execution segments
1035        let mut memory_segment_manager = MemorySegmentManager::new();
1036        memory_segment_manager.add();
1037        memory_segment_manager.add();
1038
1039        // Add zero segment
1040        memory_segment_manager.add_zero_segment(3);
1041        assert_eq!(memory_segment_manager.zero_segment_index, 2);
1042        assert_eq!(memory_segment_manager.zero_segment_size, 3);
1043        assert_eq!(
1044            &memory_segment_manager.memory.data[2],
1045            &Vec::from([
1046                MemoryCell::new(MaybeRelocatable::from(0)),
1047                MemoryCell::new(MaybeRelocatable::from(0)),
1048                MemoryCell::new(MaybeRelocatable::from(0))
1049            ])
1050        );
1051
1052        // Resize zero segment
1053        memory_segment_manager.add_zero_segment(5);
1054        assert_eq!(memory_segment_manager.zero_segment_index, 2);
1055        assert_eq!(memory_segment_manager.zero_segment_size, 5);
1056
1057        assert_eq!(
1058            &memory_segment_manager.memory.data[2],
1059            &Vec::from([
1060                MemoryCell::new(MaybeRelocatable::from(0)),
1061                MemoryCell::new(MaybeRelocatable::from(0)),
1062                MemoryCell::new(MaybeRelocatable::from(0)),
1063                MemoryCell::new(MaybeRelocatable::from(0)),
1064                MemoryCell::new(MaybeRelocatable::from(0))
1065            ])
1066        );
1067    }
1068}