|
1 | 1 | use crate::{ |
2 | 2 | relocatable::{PyMaybeRelocatable, PyRelocatable}, |
| 3 | + utils::to_py_error, |
3 | 4 | vm_core::PyVM, |
4 | 5 | }; |
5 | 6 | use cairo_rs::{ |
6 | 7 | types::relocatable::{MaybeRelocatable, Relocatable}, |
7 | 8 | vm::vm_core::VirtualMachine, |
8 | 9 | }; |
| 10 | +use num_bigint::BigInt; |
9 | 11 | use pyo3::{ |
10 | 12 | exceptions::{PyTypeError, PyValueError}, |
11 | 13 | prelude::*, |
12 | 14 | }; |
13 | | -use std::{cell::RefCell, rc::Rc}; |
| 15 | +use std::{borrow::Cow, cell::RefCell, rc::Rc}; |
14 | 16 |
|
15 | 17 | const MEMORY_GET_ERROR_MSG: &str = "Failed to get value from Cairo memory"; |
16 | 18 | const MEMORY_SET_ERROR_MSG: &str = "Failed to set value to Cairo memory"; |
@@ -69,6 +71,18 @@ impl PyMemory { |
69 | 71 | .collect::<Vec<PyMaybeRelocatable>>() |
70 | 72 | .to_object(py)) |
71 | 73 | } |
| 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 | + } |
72 | 86 | } |
73 | 87 |
|
74 | 88 | #[cfg(test)] |
@@ -282,4 +296,104 @@ assert memory[ap] == fp |
282 | 296 | assert_eq!(range.unwrap_err(), expected_error); |
283 | 297 | }); |
284 | 298 | } |
| 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 | + } |
285 | 399 | } |
0 commit comments