cairo_vm/vm/vm_memory/
memory_segments.rs

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