1use crate::vm::errors::memory_errors::MemoryError;
2use crate::{
3 types::relocatable::{MaybeRelocatable, Relocatable},
4 vm::vm_memory::memory_segments::MemorySegmentManager,
5};
6
7#[cfg(not(feature = "std"))]
8use alloc::vec::Vec;
9use num_integer::div_ceil;
10
11pub(crate) const ARENA_BUILTIN_SIZE: u32 = 3;
12const INITIAL_SEGMENT_SIZE: usize = ARENA_BUILTIN_SIZE as usize;
14
15#[derive(Debug, Clone)]
16pub struct SegmentArenaBuiltinRunner {
17 base: Relocatable,
18 pub(crate) included: bool,
19 pub(crate) stop_ptr: Option<usize>,
20}
21
22impl SegmentArenaBuiltinRunner {
23 pub(crate) fn new(included: bool) -> Self {
24 SegmentArenaBuiltinRunner {
25 base: Relocatable::from((0, 0)),
26 included,
27 stop_ptr: None,
28 }
29 }
30
31 pub fn initialize_segments(&mut self, segments: &mut MemorySegmentManager) {
32 let info = &[
33 MaybeRelocatable::from(segments.add()),
34 MaybeRelocatable::from(0),
35 MaybeRelocatable::from(0),
36 ];
37 let segment_start = gen_arg(segments, info);
38 self.base = (segment_start + INITIAL_SEGMENT_SIZE).unwrap();
40 }
41
42 pub fn get_used_cells(&self, segments: &MemorySegmentManager) -> Result<usize, MemoryError> {
43 let used = segments
44 .get_segment_used_size(self.base.segment_index as usize)
45 .ok_or(MemoryError::MissingSegmentUsedSizes)?;
46 if used < INITIAL_SEGMENT_SIZE {
47 return Err(MemoryError::InvalidUsedSizeSegmentArena);
48 }
49 Ok(used - INITIAL_SEGMENT_SIZE)
50 }
51
52 pub fn initial_stack(&self) -> Vec<MaybeRelocatable> {
53 if self.included {
54 vec![MaybeRelocatable::from(self.base)]
55 } else {
56 vec![]
57 }
58 }
59
60 pub fn get_used_instances(
61 &self,
62 segments: &MemorySegmentManager,
63 ) -> Result<usize, MemoryError> {
64 Ok(div_ceil(
65 self.get_used_cells(segments)?,
66 ARENA_BUILTIN_SIZE as usize,
67 ))
68 }
69
70 pub fn base(&self) -> usize {
71 self.base.segment_index as usize
72 }
73}
74
75fn gen_arg(segments: &mut MemorySegmentManager, data: &[MaybeRelocatable; 3]) -> Relocatable {
77 let base = segments.add();
78 for (num, value) in data.iter().enumerate() {
79 segments
81 .memory
82 .insert((base + num).unwrap(), value)
83 .unwrap();
84 }
85 base
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use crate::types::builtin_name::BuiltinName;
92 use crate::vm::errors::runner_errors::RunnerError;
93 use crate::{relocatable, utils::test_utils::*, vm::runners::builtin_runner::BuiltinRunner};
94 #[cfg(not(feature = "std"))]
95 use alloc::boxed::Box;
96 #[cfg(target_arch = "wasm32")]
97 use wasm_bindgen_test::*;
98
99 #[test]
100 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
101 fn gen_arg_test() {
102 let mut segments = MemorySegmentManager::new();
103 let data = &[
104 MaybeRelocatable::from(segments.add()),
105 MaybeRelocatable::from(0),
106 MaybeRelocatable::from(0),
107 ];
108 let base = gen_arg(&mut segments, data);
109 assert_eq!(base, (1, 0).into());
110 check_memory!(segments.memory, ((1, 0), (0, 0)), ((1, 1), 0), ((1, 2), 0));
111 }
112
113 #[test]
114 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
115 fn get_used_instances() {
116 let builtin = SegmentArenaBuiltinRunner::new(true);
117
118 let mut vm = vm!();
119 vm.segments.segment_used_sizes = Some(vec![3]);
120
121 assert_eq!(builtin.get_used_instances(&vm.segments), Ok(0));
122 }
123
124 #[test]
125 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
126 fn get_used_instances_enum() {
127 let builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(true).into();
128
129 let mut vm = vm!();
130 vm.segments.segment_used_sizes = Some(vec![3]);
131
132 assert_eq!(builtin.get_used_instances(&vm.segments), Ok(0));
133 }
134
135 #[test]
136 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
137 fn final_stack_error_stop_pointer() {
138 let mut builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(true).into();
139
140 let mut vm = vm!();
141
142 vm.segments = segments![
143 ((0, 0), (0, 0)),
144 ((0, 1), (0, 1)),
145 ((2, 0), (0, 0)),
146 ((2, 1), (0, 0))
147 ];
148
149 vm.segments.segment_used_sizes = Some(vec![6]);
150
151 let pointer = Relocatable::from((2, 2));
152 assert_eq!(
159 builtin.final_stack(&vm.segments, pointer),
160 Err(RunnerError::InvalidStopPointer(Box::new((
161 BuiltinName::segment_arena,
162 relocatable!(0, 6),
163 relocatable!(0, 0)
164 ))))
165 );
166 }
167
168 #[test]
169 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
170 fn final_stack_valid() {
171 let mut builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(false).into();
172
173 let mut vm = vm!();
174
175 vm.segments = segments![
176 ((0, 0), (0, 0)),
177 ((0, 1), (0, 1)),
178 ((2, 0), (0, 0)),
179 ((2, 1), (1, 0))
180 ];
181
182 vm.segments.segment_used_sizes = Some(vec![0]);
183
184 let pointer = Relocatable::from((2, 2));
185
186 assert_eq!(
187 builtin.final_stack(&vm.segments, pointer).unwrap(),
188 Relocatable::from((2, 2))
189 );
190 }
191
192 #[test]
193 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
194 fn final_stack_valid_from_enum() {
195 let mut builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(false).into();
196
197 let mut vm = vm!();
198
199 vm.segments = segments![
200 ((0, 0), (0, 0)),
201 ((0, 1), (0, 1)),
202 ((2, 0), (0, 0)),
203 ((2, 1), (1, 0))
204 ];
205
206 vm.segments.segment_used_sizes = Some(vec![0]);
207
208 let pointer = Relocatable::from((2, 2));
209
210 assert_eq!(
211 builtin.final_stack(&vm.segments, pointer).unwrap(),
212 Relocatable::from((2, 2))
213 );
214 }
215
216 #[test]
217 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
218 fn final_stack_error_non_relocatable() {
219 let mut builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(true).into();
220
221 let mut vm = vm!();
222
223 vm.segments = segments![
224 ((0, 0), (0, 0)),
225 ((0, 1), (0, 1)),
226 ((2, 0), (0, 0)),
227 ((2, 1), 2)
228 ];
229
230 vm.segments.segment_used_sizes = Some(vec![0]);
231
232 let pointer = Relocatable::from((2, 2));
233
234 assert_eq!(
235 builtin.final_stack(&vm.segments, pointer),
236 Err(RunnerError::NoStopPointer(Box::new(
237 BuiltinName::segment_arena
238 )))
239 );
240 }
241
242 #[test]
243 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
244 fn get_used_cells_and_allocated_size_test() {
245 let builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(true).into();
246
247 let mut vm = vm!();
248
249 vm.segments.segment_used_sizes = Some(vec![3]);
250
251 assert_eq!(
252 builtin.get_used_cells_and_allocated_size(&vm),
253 Ok((0_usize, 0))
254 );
255 }
256
257 #[test]
258 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
259 fn initialize_segments_for_output() {
260 let mut builtin = SegmentArenaBuiltinRunner::new(true);
261 let mut segments = MemorySegmentManager::new();
262 builtin.initialize_segments(&mut segments);
263 assert_eq!(builtin.base, (1, 3).into());
264 }
265
266 #[test]
267 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
268 fn get_initial_stack_for_output_with_base() {
269 let mut builtin = SegmentArenaBuiltinRunner::new(true);
270 builtin.base = relocatable!(1, 0);
271 let initial_stack = builtin.initial_stack();
272 assert_eq!(
273 initial_stack[0].clone(),
274 MaybeRelocatable::RelocatableValue((builtin.base() as isize, 0).into())
275 );
276 assert_eq!(initial_stack.len(), 1);
277 }
278
279 #[test]
280 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
281 fn get_used_cells_missing_segment_used_sizes() {
282 let builtin = BuiltinRunner::SegmentArena(SegmentArenaBuiltinRunner::new(true));
283 let vm = vm!();
284
285 assert_eq!(
286 builtin.get_used_cells(&vm.segments),
287 Err(MemoryError::MissingSegmentUsedSizes)
288 );
289 }
290
291 #[test]
292 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
293 fn get_used_cells_empty() {
294 let builtin = BuiltinRunner::SegmentArena(SegmentArenaBuiltinRunner::new(true));
295 let mut vm = vm!();
296
297 vm.segments.segment_used_sizes = Some(vec![0]);
298 assert_eq!(
299 builtin.get_used_cells(&vm.segments),
300 Err(MemoryError::InvalidUsedSizeSegmentArena)
301 );
302 }
303
304 #[test]
305 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
306 fn get_used_cells() {
307 let builtin = BuiltinRunner::SegmentArena(SegmentArenaBuiltinRunner::new(true));
308 let mut vm = vm!();
309
310 vm.segments.segment_used_sizes = Some(vec![4]);
311 assert_eq!(builtin.get_used_cells(&vm.segments), Ok(1));
312 }
313
314 #[test]
315 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
316 fn test_get_used_instances_missing_segments() {
317 let builtin = BuiltinRunner::SegmentArena(SegmentArenaBuiltinRunner::new(true));
318 let memory_segment_manager = MemorySegmentManager::new();
319
320 assert_eq!(
321 builtin.get_used_instances(&memory_segment_manager),
322 Err(MemoryError::MissingSegmentUsedSizes)
323 );
324 }
325
326 #[test]
327 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
328 fn test_get_used_instances_valid() {
329 let builtin = BuiltinRunner::SegmentArena(SegmentArenaBuiltinRunner::new(true));
330 let mut memory_segment_manager = MemorySegmentManager::new();
331 memory_segment_manager.segment_used_sizes = Some(vec![6]);
332 assert_eq!(builtin.get_used_instances(&memory_segment_manager), Ok(1));
334 }
335
336 #[test]
337 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
338 fn test_deduce_memory_cell_output_builtin() {
339 let builtin = BuiltinRunner::SegmentArena(SegmentArenaBuiltinRunner::new(true));
340 let mut vm = vm!();
341
342 vm.segments = segments![
343 ((0, 0), (0, 0)),
344 ((0, 1), (0, 1)),
345 ((2, 0), (0, 0)),
346 ((2, 1), 2)
347 ];
348
349 let pointer = Relocatable::from((2, 2));
350
351 assert_eq!(
352 builtin.deduce_memory_cell(pointer, &vm.segments.memory),
353 Ok(None)
354 );
355 }
356
357 #[test]
358 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
359 fn initial_stackincluded_test() {
360 let ec_op_builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(true).into();
361 assert_eq!(ec_op_builtin.initial_stack(), vec![mayberelocatable!(0, 0)])
362 }
363
364 #[test]
365 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
366 fn initial_stack_notincluded_test() {
367 let ec_op_builtin = SegmentArenaBuiltinRunner::new(false);
368 assert_eq!(ec_op_builtin.initial_stack(), Vec::new())
369 }
370
371 #[test]
372 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
373 fn test_add_validation_rule_enum() {
374 let builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(true).into();
375 let mut vm = vm!();
376
377 vm.segments = segments![
378 ((0, 0), (0, 0)),
379 ((0, 1), (0, 1)),
380 ((2, 0), (0, 0)),
381 ((2, 1), 2)
382 ];
383
384 vm.segments.segment_used_sizes = Some(vec![0]);
385 builtin.add_validation_rule(&mut vm.segments.memory);
386 }
387
388 #[test]
389 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
390 fn cells_per_instance_enum() {
391 let builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(true).into();
392 assert_eq!(builtin.cells_per_instance(), ARENA_BUILTIN_SIZE)
393 }
394
395 #[test]
396 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
397 fn n_input_cells_enum() {
398 let builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(true).into();
399 assert_eq!(builtin.n_input_cells(), ARENA_BUILTIN_SIZE)
400 }
401
402 #[test]
403 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
404 fn instances_per_component_enum() {
405 let builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(true).into();
406 assert_eq!(builtin.instances_per_component(), 1)
407 }
408
409 #[test]
410 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
411 fn get_air_private_input() {
412 let builtin: BuiltinRunner = SegmentArenaBuiltinRunner::new(true).into();
413
414 let segments = segments![((0, 0), 0), ((0, 1), 1), ((0, 2), 2), ((0, 3), 3)];
415 assert!(builtin.air_private_input(&segments).is_empty());
416 }
417}