Skip to content

Commit 29704a5

Browse files
authored
Implement PyMemory::get_range_as_ints(). (#147)
1 parent de9cb2b commit 29704a5

File tree

1 file changed

+115
-1
lines changed

1 file changed

+115
-1
lines changed

src/memory.rs

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
use crate::{
22
relocatable::{PyMaybeRelocatable, PyRelocatable},
3+
utils::to_py_error,
34
vm_core::PyVM,
45
};
56
use cairo_rs::{
67
types::relocatable::{MaybeRelocatable, Relocatable},
78
vm::vm_core::VirtualMachine,
89
};
10+
use num_bigint::BigInt;
911
use pyo3::{
1012
exceptions::{PyTypeError, PyValueError},
1113
prelude::*,
1214
};
13-
use std::{cell::RefCell, rc::Rc};
15+
use std::{borrow::Cow, cell::RefCell, rc::Rc};
1416

1517
const MEMORY_GET_ERROR_MSG: &str = "Failed to get value from Cairo memory";
1618
const MEMORY_SET_ERROR_MSG: &str = "Failed to set value to Cairo memory";
@@ -69,6 +71,18 @@ impl PyMemory {
6971
.collect::<Vec<PyMaybeRelocatable>>()
7072
.to_object(py))
7173
}
74+
75+
/// Return a continuous section of memory as a vector of integers.
76+
pub fn get_range_as_ints(&self, addr: PyRelocatable, size: usize) -> PyResult<Vec<BigInt>> {
77+
Ok(self
78+
.vm
79+
.borrow()
80+
.get_integer_range(&Relocatable::from(&addr), size)
81+
.map_err(to_py_error)?
82+
.into_iter()
83+
.map(Cow::into_owned)
84+
.collect())
85+
}
7286
}
7387

7488
#[cfg(test)]
@@ -282,4 +296,104 @@ assert memory[ap] == fp
282296
assert_eq!(range.unwrap_err(), expected_error);
283297
});
284298
}
299+
300+
// Test that get_range_as_ints() works as intended.
301+
#[test]
302+
fn get_range_as_ints() {
303+
let vm = PyVM::new(
304+
BigInt::new(Sign::Plus, vec![1, 0, 0, 0, 0, 0, 17, 134217728]),
305+
false,
306+
);
307+
let memory = PyMemory::new(&vm);
308+
309+
let addr = {
310+
let mut vm = vm.vm.borrow_mut();
311+
let addr = vm.add_memory_segment();
312+
313+
vm.load_data(
314+
&MaybeRelocatable::from(&addr),
315+
vec![
316+
bigint!(1).into(),
317+
bigint!(2).into(),
318+
bigint!(3).into(),
319+
bigint!(4).into(),
320+
],
321+
)
322+
.expect("memory insertion failed");
323+
324+
addr
325+
};
326+
327+
assert_eq!(
328+
memory
329+
.get_range_as_ints(addr.into(), 4)
330+
.expect("get_range_as_ints() failed"),
331+
vec![bigint!(1), bigint!(2), bigint!(3), bigint!(4)],
332+
);
333+
}
334+
335+
// Test that get_range_as_ints() fails when not all values are integers.
336+
#[test]
337+
fn get_range_as_ints_mixed() {
338+
let vm = PyVM::new(
339+
BigInt::new(Sign::Plus, vec![1, 0, 0, 0, 0, 0, 17, 134217728]),
340+
false,
341+
);
342+
let memory = PyMemory::new(&vm);
343+
344+
let addr = {
345+
let mut vm = vm.vm.borrow_mut();
346+
let addr = vm.add_memory_segment();
347+
348+
vm.load_data(
349+
&MaybeRelocatable::from(&addr),
350+
vec![
351+
bigint!(1).into(),
352+
bigint!(2).into(),
353+
MaybeRelocatable::RelocatableValue((1, 2).into()),
354+
bigint!(4).into(),
355+
],
356+
)
357+
.expect("memory insertion failed");
358+
359+
addr
360+
};
361+
362+
memory
363+
.get_range_as_ints(addr.into(), 4)
364+
.expect_err("get_range_as_ints() succeeded (should have failed)");
365+
}
366+
367+
// Test that get_range_as_ints() fails when the requested range is larger than the available
368+
// segments.
369+
#[test]
370+
fn get_range_as_ints_incomplete() {
371+
let vm = PyVM::new(
372+
BigInt::new(Sign::Plus, vec![1, 0, 0, 0, 0, 0, 17, 134217728]),
373+
false,
374+
);
375+
let memory = PyMemory::new(&vm);
376+
377+
let addr = {
378+
let mut vm = vm.vm.borrow_mut();
379+
let addr = vm.add_memory_segment();
380+
381+
vm.load_data(
382+
&MaybeRelocatable::from(&addr),
383+
vec![
384+
bigint!(1).into(),
385+
bigint!(2).into(),
386+
bigint!(3).into(),
387+
bigint!(4).into(),
388+
],
389+
)
390+
.expect("memory insertion failed");
391+
392+
addr
393+
};
394+
395+
memory
396+
.get_range_as_ints(addr.into(), 8)
397+
.expect_err("get_range_as_ints() succeeded (should have failed)");
398+
}
285399
}

0 commit comments

Comments
 (0)