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 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    pub fn is_accessed(&self, addr: &Relocatable) -> Result<bool, MemoryError> {
204        self.memory.is_accessed(addr)
205    }
206
207    /// Counts the memory holes (aka unaccessed memory cells) in memory
208    /// # Parameters
209    /// - `builtin_segment_indexes`: Set representing the segments indexes of the builtins initialized in the VM, except for the output builtin.
210    pub fn get_memory_holes(
211        &self,
212        builtin_segment_indexes: HashSet<usize>,
213    ) -> Result<usize, MemoryError> {
214        let data = &self.memory.data;
215        let mut memory_holes = 0;
216        for i in 0..data.len() {
217            // Instead of marking all of the builtin segment's address as accessed, we just skip them when counting memory holes
218            // Output builtin is extempt from this behaviour
219            if builtin_segment_indexes.contains(&i) {
220                continue;
221            }
222            let accessed_amount =
223                // Instead of marking the values in the zero segment until zero_segment_size as accessed we use zero_segment_size as accessed_amount
224                if self.has_zero_segment() && i == self.zero_segment_index {
225                    self.zero_segment_size
226                } else {
227                    match self.memory.get_amount_of_accessed_addresses_for_segment(i) {
228                        Some(accessed_amount) if accessed_amount > 0 => accessed_amount,
229                        _ => continue,
230                    }
231                };
232            let segment_size = self
233                .get_segment_size(i)
234                .ok_or(MemoryError::MissingSegmentUsedSizes)?;
235            if accessed_amount > segment_size {
236                return Err(MemoryError::SegmentHasMoreAccessedAddressesThanSize(
237                    Box::new((i, accessed_amount, segment_size)),
238                ));
239            }
240            memory_holes += segment_size - accessed_amount;
241        }
242        Ok(memory_holes)
243    }
244
245    /// Returns a list of addresses of memory cells that constitute the public memory.
246    /// segment_offsets is the result of self.relocate_segments()
247    pub fn get_public_memory_addresses(
248        &self,
249        segment_offsets: &[usize],
250    ) -> Result<Vec<(usize, usize)>, MemoryError> {
251        let mut addresses = Vec::with_capacity(self.num_segments());
252        let empty_vec = vec![];
253        for segment_index in 0..self.num_segments() {
254            let offsets = &self
255                .public_memory_offsets
256                .get(&segment_index)
257                .unwrap_or(&empty_vec);
258            let segment_start = segment_offsets
259                .get(segment_index)
260                .ok_or(MemoryError::MalformedPublicMemory)?;
261            for (offset, page_id) in offsets.iter() {
262                addresses.push((segment_start + offset, *page_id));
263            }
264        }
265        Ok(addresses)
266    }
267
268    // Writes the following information for the given segment:
269    // * size - The size of the segment (to be used in relocate_segments).
270    // * public_memory - A list of offsets for memory cells that will be considered as public
271    // memory.
272    pub fn finalize(
273        &mut self,
274        size: Option<usize>,
275        segment_index: usize,
276        public_memory: Option<&Vec<(usize, usize)>>,
277    ) {
278        if let Some(size) = size {
279            self.segment_sizes.insert(segment_index, size);
280        }
281        self.public_memory_offsets
282            .insert(segment_index, public_memory.cloned().unwrap_or_default());
283    }
284
285    pub fn has_zero_segment(&self) -> bool {
286        !self.zero_segment_index.is_zero()
287    }
288
289    // Creates the zero segment if it wasn't previously created
290    // Fills the segment with the value 0 until size is reached
291    // Returns the index of the zero segment
292    pub(crate) fn add_zero_segment(&mut self, size: usize) -> usize {
293        if !self.has_zero_segment() {
294            self.zero_segment_index = self.add().segment_index as usize;
295        }
296
297        // Fil zero segment with zero values until size is reached
298        for _ in 0..(size.saturating_sub(self.zero_segment_size)) {
299            // As zero_segment_index is only accessible to the segment manager
300            // we can asume that it is always valid and index direcly into it
301            self.memory.data[self.zero_segment_index].push(MemoryCell::new(Felt252::ZERO.into()))
302        }
303        self.zero_segment_size = max(self.zero_segment_size, size);
304        self.zero_segment_index
305    }
306
307    // Finalizes the zero segment and clears it's tracking data from the manager
308    pub(crate) fn finalize_zero_segment(&mut self) {
309        if self.has_zero_segment() {
310            self.finalize(Some(self.zero_segment_size), self.zero_segment_index, None);
311            self.zero_segment_index = 0;
312            self.zero_segment_size = 0;
313        }
314    }
315
316    pub(crate) fn load_pie_memory(
317        &mut self,
318        pie_memory: &CairoPieMemory,
319        n_extra_segments: usize,
320    ) -> Result<(), MemoryError> {
321        // Create extra segments
322        for _ in 0..n_extra_segments {
323            self.add();
324        }
325        // Load previous execution memory
326        for ((si, so), val) in pie_memory.0.iter() {
327            self.memory.insert((*si as isize, *so).into(), val)?;
328        }
329        Ok(())
330    }
331}
332
333impl Default for MemorySegmentManager {
334    fn default() -> Self {
335        Self::new()
336    }
337}
338
339impl fmt::Display for MemorySegmentManager {
340    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
341        writeln!(f, "Memory:\n{}", self.memory)?;
342        if let Some(used_sizes) = &self.segment_used_sizes {
343            writeln!(f, "Segment Info:")?;
344            for (index, used_size) in used_sizes.iter().enumerate() {
345                writeln!(
346                    f,
347                    "Segment Number: {}, Used Size: {}, Size {}",
348                    index,
349                    used_size,
350                    self.segment_sizes
351                        .get(&index)
352                        .map(|n| n.to_string())
353                        .unwrap_or(String::from("None"))
354                )?;
355            }
356        }
357        Ok(())
358    }
359}
360
361#[cfg(test)]
362mod tests {
363    use super::*;
364    use crate::Felt252;
365    use crate::{relocatable, utils::test_utils::*, vm::vm_memory::memory::MemoryCell};
366    use assert_matches::assert_matches;
367
368    #[cfg(target_arch = "wasm32")]
369    use wasm_bindgen_test::*;
370
371    #[test]
372    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
373    fn add_segment_no_size() {
374        let mut segments = MemorySegmentManager::new();
375        let base = segments.add();
376        assert_eq!(base, relocatable!(0, 0));
377        assert_eq!(segments.num_segments(), 1);
378    }
379
380    #[test]
381    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
382    fn add_segment_no_size_test_two_segments() {
383        let mut segments = MemorySegmentManager::new();
384        let mut _base = segments.add();
385        _base = segments.add();
386        assert_eq!(
387            _base,
388            Relocatable {
389                segment_index: 1,
390                offset: 0
391            }
392        );
393        assert_eq!(segments.num_segments(), 2);
394    }
395
396    #[test]
397    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
398    fn add_one_temporary_segment() {
399        let mut segments = MemorySegmentManager::new();
400        let base = segments.add_temporary_segment();
401        assert_eq!(base, relocatable!(-1, 0));
402        assert_eq!(segments.num_temp_segments(), 1);
403    }
404
405    #[test]
406    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
407    fn add_two_temporary_segments() {
408        let mut segments = MemorySegmentManager::new();
409        segments.add_temporary_segment();
410        let base = segments.add_temporary_segment();
411        assert_eq!(
412            base,
413            Relocatable {
414                segment_index: -2,
415                offset: 0
416            }
417        );
418        assert_eq!(segments.num_temp_segments(), 2);
419    }
420
421    #[test]
422    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
423    fn load_data_empty() {
424        let data = Vec::new();
425        let ptr = Relocatable::from((0, 3));
426        let mut segments = MemorySegmentManager::new();
427        let current_ptr = segments.load_data(ptr, &data).unwrap();
428        assert_eq!(current_ptr, Relocatable::from((0, 3)));
429    }
430
431    #[test]
432    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
433    fn load_data_one_element() {
434        let data = vec![MaybeRelocatable::from(Felt252::from(4))];
435        let ptr = Relocatable::from((0, 0));
436        let mut segments = MemorySegmentManager::new();
437        segments.add();
438        let current_ptr = segments.load_data(ptr, &data).unwrap();
439        assert_eq!(current_ptr, Relocatable::from((0, 1)));
440        assert_eq!(
441            segments.memory.get(&ptr).unwrap().as_ref(),
442            &MaybeRelocatable::from(Felt252::from(4))
443        );
444    }
445
446    #[test]
447    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
448    fn load_data_three_elements() {
449        let data = vec![
450            MaybeRelocatable::from(Felt252::from(4)),
451            MaybeRelocatable::from(Felt252::from(5)),
452            MaybeRelocatable::from(Felt252::from(6)),
453        ];
454        let ptr = Relocatable::from((0, 0));
455        let mut segments = MemorySegmentManager::new();
456        segments.add();
457        let current_ptr = segments.load_data(ptr, &data).unwrap();
458        assert_eq!(current_ptr, Relocatable::from((0, 3)));
459
460        assert_eq!(
461            segments.memory.get(&ptr).unwrap().as_ref(),
462            &MaybeRelocatable::from(Felt252::from(4))
463        );
464        assert_eq!(
465            segments
466                .memory
467                .get(&MaybeRelocatable::from((0, 1)))
468                .unwrap()
469                .as_ref(),
470            &MaybeRelocatable::from(Felt252::from(5))
471        );
472        assert_eq!(
473            segments
474                .memory
475                .get(&MaybeRelocatable::from((0, 2)))
476                .unwrap()
477                .as_ref(),
478            &MaybeRelocatable::from(Felt252::from(6))
479        );
480    }
481    #[test]
482    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
483    fn compute_effective_sizes_for_one_segment_memory() {
484        let mut segments = segments![((0, 0), 1), ((0, 1), 1), ((0, 2), 1)];
485        segments.compute_effective_sizes();
486        assert_eq!(Some(vec![3]), segments.segment_used_sizes);
487    }
488
489    #[test]
490    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
491    fn compute_effective_sizes_for_one_segment_memory_with_gap() {
492        let mut segments = MemorySegmentManager::new();
493        segments.add();
494        segments
495            .memory
496            .insert(
497                Relocatable::from((0, 6)),
498                &MaybeRelocatable::from(Felt252::from(1)),
499            )
500            .unwrap();
501        segments.compute_effective_sizes();
502        assert_eq!(Some(vec![7]), segments.segment_used_sizes);
503    }
504
505    #[test]
506    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
507    fn compute_effective_sizes_for_one_segment_memory_with_gaps() {
508        let mut segments = segments![((0, 3), 1), ((0, 4), 1), ((0, 7), 1), ((0, 9), 1)];
509        segments.compute_effective_sizes();
510        assert_eq!(Some(vec![10]), segments.segment_used_sizes);
511    }
512
513    #[test]
514    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
515    fn compute_effective_sizes_for_three_segment_memory() {
516        let mut segments = segments![
517            ((0, 0), 1),
518            ((0, 1), 1),
519            ((0, 2), 1),
520            ((1, 0), 1),
521            ((1, 1), 1),
522            ((1, 2), 1),
523            ((2, 0), 1),
524            ((2, 1), 1),
525            ((2, 2), 1)
526        ];
527        segments.compute_effective_sizes();
528        assert_eq!(Some(vec![3, 3, 3]), segments.segment_used_sizes);
529    }
530
531    #[test]
532    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
533    fn compute_effective_sizes_for_three_segment_memory_with_gaps() {
534        let mut segments = segments![
535            ((0, 2), 1),
536            ((0, 5), 1),
537            ((0, 7), 1),
538            ((1, 1), 1),
539            ((2, 2), 1),
540            ((2, 4), 1),
541            ((2, 7), 1)
542        ];
543        segments.compute_effective_sizes();
544        assert_eq!(Some(vec![8, 2, 8]), segments.segment_used_sizes);
545    }
546
547    #[test]
548    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
549    fn get_segment_used_size_after_computing_used() {
550        let mut segments = segments![
551            ((0, 2), 1),
552            ((0, 5), 1),
553            ((0, 7), 1),
554            ((1, 1), 1),
555            ((2, 2), 1),
556            ((2, 4), 1),
557            ((2, 7), 1)
558        ];
559        segments.compute_effective_sizes();
560        assert_eq!(Some(8), segments.get_segment_used_size(2));
561    }
562
563    #[test]
564    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
565    fn get_segment_used_size_before_computing_used() {
566        let segments = MemorySegmentManager::new();
567        assert_eq!(None, segments.get_segment_used_size(2));
568    }
569
570    #[test]
571    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
572    fn relocate_segments_one_segment() {
573        let mut segments = MemorySegmentManager::new();
574        segments.segment_used_sizes = Some(vec![3]);
575        assert_eq!(
576            segments
577                .relocate_segments()
578                .expect("Couldn't relocate after compute effective sizes"),
579            vec![1]
580        )
581    }
582
583    #[test]
584    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
585    fn relocate_segments_five_segment() {
586        let mut segments = MemorySegmentManager::new();
587        segments.segment_used_sizes = Some(vec![3, 3, 56, 78, 8]);
588        assert_eq!(
589            segments
590                .relocate_segments()
591                .expect("Couldn't relocate after compute effective sizes"),
592            vec![1, 4, 7, 63, 141]
593        )
594    }
595
596    #[test]
597    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
598    fn write_arg_relocatable() {
599        let data = vec![
600            Relocatable::from((0, 1)),
601            Relocatable::from((0, 2)),
602            Relocatable::from((0, 3)),
603        ];
604        let ptr = Relocatable::from((1, 0));
605        let mut segments = MemorySegmentManager::new();
606        for _ in 0..2 {
607            segments.add();
608        }
609
610        let exec = segments.write_arg(ptr, &data);
611
612        assert_eq!(exec, Ok(MaybeRelocatable::from((1, 3))));
613        assert_eq!(
614            segments.memory.data[1],
615            vec![
616                MemoryCell::new(MaybeRelocatable::from((0, 1))),
617                MemoryCell::new(MaybeRelocatable::from((0, 2))),
618                MemoryCell::new(MaybeRelocatable::from((0, 3))),
619            ]
620        );
621    }
622
623    #[test]
624    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
625    fn segment_default() {
626        let segment_mng_new = MemorySegmentManager::new();
627        let segment_mng_def: MemorySegmentManager = Default::default();
628        assert_eq!(
629            segment_mng_new.num_segments(),
630            segment_mng_def.num_segments()
631        );
632        assert_eq!(
633            segment_mng_new.segment_used_sizes,
634            segment_mng_def.segment_used_sizes
635        );
636    }
637
638    #[test]
639    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
640    fn is_valid_memory_value_missing_effective_sizes() {
641        let segment_manager = MemorySegmentManager::new();
642
643        assert_eq!(
644            segment_manager.is_valid_memory_value(&mayberelocatable!(0)),
645            Err(MemoryError::MissingSegmentUsedSizes),
646        );
647    }
648
649    #[test]
650    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
651    fn is_valid_memory_value_temporary_segment() {
652        let mut segment_manager = MemorySegmentManager::new();
653
654        segment_manager.segment_used_sizes = Some(vec![10]);
655        assert_eq!(
656            segment_manager.is_valid_memory_value(&mayberelocatable!(-1, 0)),
657            Err(MemoryError::AddressInTemporarySegment(-1)),
658        );
659    }
660
661    #[test]
662    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
663    fn is_valid_memory_value_invalid_segment() {
664        let mut segment_manager = MemorySegmentManager::new();
665
666        segment_manager.segment_used_sizes = Some(vec![10]);
667        assert_eq!(
668            segment_manager.is_valid_memory_value(&mayberelocatable!(1, 0)),
669            Ok(false),
670        );
671    }
672
673    #[test]
674    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
675    fn is_valid_memory_value() {
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!(0, 5)),
681            Ok(true),
682        );
683    }
684
685    #[test]
686    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
687    fn get_memory_holes_missing_segment_used_sizes() {
688        let mut memory_segment_manager = MemorySegmentManager::new();
689        memory_segment_manager.memory = memory![((0, 0), 0)];
690        memory_segment_manager
691            .memory
692            .mark_as_accessed((0, 0).into());
693        assert_eq!(
694            memory_segment_manager.get_memory_holes(HashSet::new()),
695            Err(MemoryError::MissingSegmentUsedSizes),
696        );
697    }
698
699    #[test]
700    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
701    fn get_memory_holes_out_of_address_offset_bigger_than_size() {
702        let mut memory_segment_manager = MemorySegmentManager::new();
703        memory_segment_manager.segment_used_sizes = Some(vec![2]);
704        memory_segment_manager.memory = memory![((0, 0), 1), ((0, 1), 1), ((0, 2), 2)];
705        for i in 0..3 {
706            memory_segment_manager
707                .memory
708                .mark_as_accessed((0, i).into());
709        }
710        assert_eq!(
711            memory_segment_manager.get_memory_holes(HashSet::new()),
712            Err(MemoryError::SegmentHasMoreAccessedAddressesThanSize(
713                Box::new((0, 3, 2))
714            )),
715        );
716    }
717
718    #[test]
719    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
720    fn get_memory_holes_empty() {
721        let mut memory_segment_manager = MemorySegmentManager::new();
722        memory_segment_manager.segment_used_sizes = Some(Vec::new());
723        assert_eq!(
724            memory_segment_manager.get_memory_holes(HashSet::new()),
725            Ok(0),
726        );
727    }
728
729    #[test]
730    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
731    fn get_memory_holes_empty2() {
732        let mut memory_segment_manager = MemorySegmentManager::new();
733        memory_segment_manager.segment_used_sizes = Some(vec![4]);
734        assert_eq!(
735            memory_segment_manager.get_memory_holes(HashSet::new()),
736            Ok(0),
737        );
738    }
739
740    #[test]
741    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
742    fn get_memory_holes() {
743        let mut memory_segment_manager = MemorySegmentManager::new();
744        memory_segment_manager.segment_used_sizes = Some(vec![10]);
745        memory_segment_manager.memory = memory![
746            ((0, 0), 0),
747            ((0, 1), 0),
748            ((0, 2), 0),
749            ((0, 3), 0),
750            ((0, 6), 0),
751            ((0, 7), 0),
752            ((0, 8), 0),
753            ((0, 9), 0)
754        ];
755        for i in [0, 1, 2, 3, 6, 7, 8, 9] {
756            memory_segment_manager
757                .memory
758                .mark_as_accessed((0, i).into());
759        }
760        assert_eq!(
761            memory_segment_manager.get_memory_holes(HashSet::new()),
762            Ok(2),
763        );
764    }
765
766    #[test]
767    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
768    fn get_memory_holes2() {
769        let mut memory_segment_manager = MemorySegmentManager::new();
770
771        memory_segment_manager.segment_sizes = HashMap::from([(0, 15)]);
772        memory_segment_manager.memory = memory![
773            ((0, 0), 0),
774            ((0, 1), 0),
775            ((0, 2), 0),
776            ((0, 3), 0),
777            ((0, 6), 0),
778            ((0, 7), 0),
779            ((0, 8), 0),
780            ((0, 9), 0)
781        ];
782        memory_segment_manager.segment_used_sizes = Some(vec![10]);
783        for i in [0, 1, 2, 3, 6, 7, 8, 9] {
784            memory_segment_manager
785                .memory
786                .mark_as_accessed((0, i).into());
787        }
788        assert_eq!(
789            memory_segment_manager.get_memory_holes(HashSet::new()),
790            Ok(7),
791        );
792    }
793
794    #[test]
795    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
796    fn get_memory_size_missing_segment() {
797        let memory_segment_manager = MemorySegmentManager::new();
798
799        assert_eq!(memory_segment_manager.get_segment_size(0), None);
800    }
801
802    #[test]
803    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
804    fn get_memory_size_used() {
805        let mut memory_segment_manager = MemorySegmentManager::new();
806        memory_segment_manager.segment_used_sizes = Some(vec![5]);
807
808        assert_eq!(memory_segment_manager.get_segment_size(0), Some(5));
809    }
810
811    #[test]
812    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
813    fn get_memory_size() {
814        let mut memory_segment_manager = MemorySegmentManager::new();
815        memory_segment_manager.segment_sizes = HashMap::from([(0, 5)]);
816
817        assert_eq!(memory_segment_manager.get_segment_size(0), Some(5));
818    }
819
820    #[test]
821    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
822    fn get_memory_size2() {
823        let mut memory_segment_manager = MemorySegmentManager::new();
824        memory_segment_manager.segment_sizes = HashMap::from([(0, 5)]);
825        memory_segment_manager.segment_used_sizes = Some(vec![3]);
826
827        assert_eq!(memory_segment_manager.get_segment_size(0), Some(5));
828    }
829
830    /// Test that the call to .gen_arg() with a relocatable just passes the
831    /// value through.
832    #[test]
833    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
834    fn gen_arg_relocatable() {
835        let mut memory_segment_manager = MemorySegmentManager::new();
836
837        assert_matches!(
838            memory_segment_manager.gen_arg(&mayberelocatable!(0, 0)),
839            Ok(x) if x == mayberelocatable!(0, 0)
840        );
841    }
842
843    /// Test that the call to .gen_arg() with a bigint and no prime number just
844    /// passes the value through.
845    #[test]
846    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
847    fn gen_arg_bigint() {
848        let mut memory_segment_manager = MemorySegmentManager::new();
849
850        assert_matches!(
851            memory_segment_manager.gen_arg(&mayberelocatable!(1234)),
852            Ok(x) if x == mayberelocatable!(1234)
853        );
854    }
855
856    /// Test that the call to .gen_arg() with a Vec<MaybeRelocatable> writes its
857    /// contents into a new segment and returns a pointer to it.
858    #[test]
859    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
860    fn gen_arg_vec() {
861        let mut memory_segment_manager = MemorySegmentManager::new();
862
863        assert_matches!(
864            memory_segment_manager.gen_arg(
865                &vec![
866                    mayberelocatable!(0),
867                    mayberelocatable!(1),
868                    mayberelocatable!(2),
869                    mayberelocatable!(3),
870                    mayberelocatable!(0, 0),
871                    mayberelocatable!(0, 1),
872                    mayberelocatable!(0, 2),
873                    mayberelocatable!(0, 3),
874                ],
875            ),
876            Ok(x) if x == mayberelocatable!(0, 0)
877        );
878    }
879
880    /// Test that the call to .gen_arg() with a Vec<Relocatable> writes its
881    /// contents into a new segment and returns a pointer to it.
882    #[test]
883    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
884    fn gen_arg_vec_relocatable() {
885        let mut memory_segment_manager = MemorySegmentManager::new();
886
887        assert_matches!(
888            memory_segment_manager.gen_arg(
889                &vec![
890                    MaybeRelocatable::from((0, 0)),
891                    MaybeRelocatable::from((0, 1)),
892                    MaybeRelocatable::from((0, 2)),
893                    MaybeRelocatable::from((0, 3)),
894                ],
895            ),
896            Ok(x) if x == mayberelocatable!(0, 0)
897        );
898    }
899
900    /// Test that the call to .gen_arg() with any other argument returns a not
901    /// implemented error.
902    #[test]
903    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
904    fn gen_arg_invalid_type() {
905        let mut memory_segment_manager = MemorySegmentManager::new();
906
907        assert_matches!(
908            memory_segment_manager.gen_arg(&""),
909            Err(MemoryError::GenArgInvalidType)
910        );
911    }
912
913    #[test]
914    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
915    fn finalize_no_size_nor_memory() {
916        let mut segments = MemorySegmentManager::new();
917        segments.finalize(None, 0, None);
918        assert!(segments.memory.data.is_empty());
919        assert!(segments.memory.temp_data.is_empty());
920        assert_eq!(segments.public_memory_offsets, HashMap::from([(0, vec![])]));
921        assert_eq!(segments.num_segments(), 0);
922        assert_eq!(segments.num_temp_segments(), 0);
923    }
924
925    #[test]
926    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
927    fn finalize_no_memory() {
928        let mut segments = MemorySegmentManager::new();
929        segments.finalize(Some(42), 0, None);
930        assert_eq!(segments.public_memory_offsets, HashMap::from([(0, vec![])]));
931        assert_eq!(segments.segment_sizes, HashMap::from([(0, 42)]));
932    }
933
934    #[test]
935    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
936    fn finalize_no_size() {
937        let mut segments = MemorySegmentManager::new();
938        segments.finalize(None, 0, Some(&vec![(1_usize, 2_usize)]));
939        assert_eq!(
940            segments.public_memory_offsets,
941            HashMap::from([(0_usize, vec![(1_usize, 2_usize)])])
942        );
943        assert!(segments.segment_sizes.is_empty());
944    }
945
946    #[test]
947    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
948    fn finalize_all_args() {
949        let mut segments = MemorySegmentManager::new();
950        segments.finalize(Some(42), 0, Some(&vec![(1_usize, 2_usize)]));
951        assert_eq!(
952            segments.public_memory_offsets,
953            HashMap::from([(0_usize, vec![(1_usize, 2_usize)])])
954        );
955        assert_eq!(segments.segment_sizes, HashMap::from([(0, 42)]));
956    }
957
958    #[test]
959    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
960    fn gen_cairo_arg_single() {
961        let mut memory_segment_manager = MemorySegmentManager::new();
962
963        assert_matches!(
964            memory_segment_manager.gen_cairo_arg(&mayberelocatable!(1234).into()),
965            Ok(x) if x == mayberelocatable!(1234)
966        );
967    }
968
969    #[test]
970    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
971    fn gen_cairo_arg_array() {
972        let mut memory_segment_manager = MemorySegmentManager::new();
973
974        assert_matches!(
975            memory_segment_manager.gen_cairo_arg(
976                &vec![
977                    mayberelocatable!(0),
978                    mayberelocatable!(1),
979                    mayberelocatable!(2),
980                    mayberelocatable!(3),
981                    mayberelocatable!(0, 0),
982                    mayberelocatable!(0, 1),
983                    mayberelocatable!(0, 2),
984                    mayberelocatable!(0, 3),
985                ]
986                .into(),
987            ),
988            Ok(x) if x == mayberelocatable!(0, 0)
989        );
990    }
991
992    #[test]
993    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
994    fn gen_cairo_arg_composed() {
995        let mut memory_segment_manager = MemorySegmentManager::new();
996        let cairo_args = CairoArg::Composed(vec![
997            CairoArg::Array(vec![
998                mayberelocatable!(0),
999                mayberelocatable!(1),
1000                mayberelocatable!(2),
1001            ]),
1002            CairoArg::Single(mayberelocatable!(1234)),
1003            CairoArg::Single(mayberelocatable!(5678)),
1004            CairoArg::Array(vec![
1005                mayberelocatable!(3),
1006                mayberelocatable!(4),
1007                mayberelocatable!(5),
1008            ]),
1009        ]);
1010
1011        assert_matches!(
1012            memory_segment_manager.gen_cairo_arg(&cairo_args),
1013            Ok(x) if x == mayberelocatable!(2, 0)
1014        );
1015    }
1016
1017    #[test]
1018    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1019    fn test_add_zero_segment() {
1020        // Create MemorySegmentManager with program and execution segments
1021        let mut memory_segment_manager = MemorySegmentManager::new();
1022        memory_segment_manager.add();
1023        memory_segment_manager.add();
1024
1025        // Add zero segment
1026        memory_segment_manager.add_zero_segment(3);
1027        assert_eq!(memory_segment_manager.zero_segment_index, 2);
1028        assert_eq!(memory_segment_manager.zero_segment_size, 3);
1029        assert_eq!(
1030            &memory_segment_manager.memory.data[2],
1031            &Vec::from([
1032                MemoryCell::new(MaybeRelocatable::from(0)),
1033                MemoryCell::new(MaybeRelocatable::from(0)),
1034                MemoryCell::new(MaybeRelocatable::from(0))
1035            ])
1036        );
1037
1038        // Resize zero segment
1039        memory_segment_manager.add_zero_segment(5);
1040        assert_eq!(memory_segment_manager.zero_segment_index, 2);
1041        assert_eq!(memory_segment_manager.zero_segment_size, 5);
1042
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                MemoryCell::new(MaybeRelocatable::from(0)),
1050                MemoryCell::new(MaybeRelocatable::from(0))
1051            ])
1052        );
1053    }
1054}