1use std::{
2 fmt::{self, Display},
3 ops::{Add, AddAssign, Sub},
4};
5
6use crate::Felt252;
7use crate::{
8 relocatable, types::errors::math_errors::MathError, vm::errors::memory_errors::MemoryError,
9};
10use num_traits::ToPrimitive;
11use serde::{Deserialize, Serialize};
12
13#[cfg(feature = "test_utils")]
14use arbitrary::Arbitrary;
15
16#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
17#[derive(
18 Eq, Ord, Hash, PartialEq, PartialOrd, Clone, Copy, Debug, Serialize, Deserialize, Default,
19)]
20pub struct Relocatable {
21 pub segment_index: isize,
22 pub offset: usize,
23}
24
25#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
26#[derive(Eq, Ord, Hash, PartialEq, PartialOrd, Clone, Serialize, Deserialize)]
27pub enum MaybeRelocatable {
28 RelocatableValue(Relocatable),
29 Int(Felt252),
30}
31
32impl fmt::Debug for MaybeRelocatable {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 match self {
36 MaybeRelocatable::RelocatableValue(v) => {
37 f.debug_tuple("RelocatableValue").field(&v).finish()
38 }
39 MaybeRelocatable::Int(v) => {
40 f.debug_tuple("Int").field(&format_args!("{}", &v)).finish()
41 }
42 }
43 }
44}
45
46impl From<(isize, usize)> for Relocatable {
47 fn from(index_offset: (isize, usize)) -> Self {
48 Relocatable {
49 segment_index: index_offset.0,
50 offset: index_offset.1,
51 }
52 }
53}
54
55impl From<(isize, usize)> for MaybeRelocatable {
56 fn from(index_offset: (isize, usize)) -> Self {
57 MaybeRelocatable::RelocatableValue(Relocatable::from(index_offset))
58 }
59}
60
61impl From<usize> for MaybeRelocatable {
62 fn from(num: usize) -> Self {
63 MaybeRelocatable::Int(Felt252::from(num))
64 }
65}
66
67impl From<Felt252> for MaybeRelocatable {
68 fn from(num: Felt252) -> Self {
69 MaybeRelocatable::Int(num)
70 }
71}
72
73impl From<&Relocatable> for MaybeRelocatable {
74 fn from(rel: &Relocatable) -> Self {
75 MaybeRelocatable::RelocatableValue(*rel)
76 }
77}
78
79impl From<&Relocatable> for Relocatable {
80 fn from(other: &Relocatable) -> Self {
81 *other
82 }
83}
84
85impl From<&Felt252> for MaybeRelocatable {
86 fn from(val: &Felt252) -> Self {
87 MaybeRelocatable::Int(*val)
88 }
89}
90
91impl From<Relocatable> for MaybeRelocatable {
92 fn from(rel: Relocatable) -> Self {
93 MaybeRelocatable::RelocatableValue(rel)
94 }
95}
96
97impl Display for MaybeRelocatable {
98 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99 match self {
100 MaybeRelocatable::RelocatableValue(rel) => rel.fmt(f),
101 MaybeRelocatable::Int(num) => write!(f, "{num}"),
102 }
103 }
104}
105
106impl Display for Relocatable {
107 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108 write!(f, "{}:{}", self.segment_index, self.offset)
109 }
110}
111
112impl Add<usize> for Relocatable {
113 type Output = Result<Relocatable, MathError>;
114 fn add(self, other: usize) -> Result<Self, MathError> {
115 self.offset
116 .checked_add(other)
117 .map(|x| Relocatable::from((self.segment_index, x)))
118 .ok_or_else(|| MathError::RelocatableAddUsizeOffsetExceeded(Box::new((self, other))))
119 }
120}
121
122impl AddAssign<usize> for Relocatable {
124 fn add_assign(&mut self, rhs: usize) {
125 self.offset += rhs
126 }
127}
128
129impl Add<u32> for Relocatable {
130 type Output = Result<Relocatable, MathError>;
131 fn add(self, other: u32) -> Result<Self, MathError> {
132 self + other as usize
133 }
134}
135
136impl Add<i32> for Relocatable {
137 type Output = Result<Relocatable, MathError>;
138 fn add(self, other: i32) -> Result<Self, MathError> {
139 if other >= 0 {
140 self + other as usize
141 } else {
142 self - other.unsigned_abs() as usize
143 }
144 }
145}
146impl Add<&Felt252> for Relocatable {
147 type Output = Result<Relocatable, MathError>;
148 fn add(self, other: &Felt252) -> Result<Relocatable, MathError> {
149 let new_offset = (self.offset as u64 + other)
150 .and_then(|x| x.to_usize())
151 .ok_or_else(|| {
152 MathError::RelocatableAddFelt252OffsetExceeded(Box::new((self, *other)))
153 })?;
154 Ok((self.segment_index, new_offset).into())
155 }
156}
157
158impl Add<&MaybeRelocatable> for Relocatable {
161 type Output = Result<Relocatable, MathError>;
162 fn add(self, other: &MaybeRelocatable) -> Result<Relocatable, MathError> {
163 let num_ref = match other {
164 MaybeRelocatable::RelocatableValue(rel) => {
165 return Err(MathError::RelocatableAdd(Box::new((self, *rel))))
166 }
167 MaybeRelocatable::Int(num) => num,
168 };
169 self + num_ref
170 }
171}
172
173impl Sub<usize> for Relocatable {
174 type Output = Result<Relocatable, MathError>;
175 fn sub(self, other: usize) -> Result<Self, MathError> {
176 if self.offset < other {
177 return Err(MathError::RelocatableSubUsizeNegOffset(Box::new((
178 self, other,
179 ))));
180 }
181 let new_offset = self.offset - other;
182 Ok(relocatable!(self.segment_index, new_offset))
183 }
184}
185
186impl Sub<Relocatable> for Relocatable {
187 type Output = Result<usize, MathError>;
188 fn sub(self, other: Self) -> Result<usize, MathError> {
189 if self.segment_index != other.segment_index {
190 return Err(MathError::RelocatableSubDiffIndex(Box::new((self, other))));
191 }
192 if self.offset < other.offset {
193 return Err(MathError::RelocatableSubUsizeNegOffset(Box::new((
194 self,
195 other.offset,
196 ))));
197 }
198 let result = self.offset - other.offset;
199 Ok(result)
200 }
201}
202
203impl TryInto<Relocatable> for MaybeRelocatable {
204 type Error = MemoryError;
205 fn try_into(self) -> Result<Relocatable, MemoryError> {
206 match self {
207 MaybeRelocatable::RelocatableValue(rel) => Ok(rel),
208 _ => Err(MemoryError::AddressNotRelocatable),
209 }
210 }
211}
212
213impl From<&MaybeRelocatable> for MaybeRelocatable {
214 fn from(other: &MaybeRelocatable) -> Self {
215 other.clone()
216 }
217}
218
219impl TryFrom<&MaybeRelocatable> for Relocatable {
220 type Error = MathError;
221 fn try_from(other: &MaybeRelocatable) -> Result<Self, MathError> {
222 match other {
223 MaybeRelocatable::RelocatableValue(rel) => Ok(*rel),
224 MaybeRelocatable::Int(num) => Err(MathError::Felt252ToRelocatable(Box::new(*num))),
225 }
226 }
227}
228
229impl MaybeRelocatable {
230 pub fn add_int(&self, other: &Felt252) -> Result<MaybeRelocatable, MathError> {
232 match *self {
233 MaybeRelocatable::Int(ref value) => Ok(MaybeRelocatable::Int(value + other)),
234 MaybeRelocatable::RelocatableValue(rel) => {
235 Ok(MaybeRelocatable::RelocatableValue((rel + other)?))
236 }
237 }
238 }
239
240 pub fn add_usize(&self, other: usize) -> Result<MaybeRelocatable, MathError> {
242 Ok(match *self {
243 MaybeRelocatable::Int(ref value) => MaybeRelocatable::Int(value + other as u64),
244 MaybeRelocatable::RelocatableValue(rel) => (rel + other)?.into(),
245 })
246 }
247
248 pub fn add(&self, other: &MaybeRelocatable) -> Result<MaybeRelocatable, MathError> {
251 match (self, other) {
252 (MaybeRelocatable::Int(num_a_ref), MaybeRelocatable::Int(num_b)) => {
253 Ok(MaybeRelocatable::Int(num_a_ref + num_b))
254 }
255 (
256 &MaybeRelocatable::RelocatableValue(rel_a),
257 &MaybeRelocatable::RelocatableValue(rel_b),
258 ) => Err(MathError::RelocatableAdd(Box::new((rel_a, rel_b)))),
259 (&MaybeRelocatable::RelocatableValue(rel), &MaybeRelocatable::Int(ref num_ref))
260 | (&MaybeRelocatable::Int(ref num_ref), &MaybeRelocatable::RelocatableValue(rel)) => {
261 Ok((rel + num_ref)?.into())
262 }
263 }
264 }
265
266 pub fn sub_usize(&self, other: usize) -> Result<MaybeRelocatable, MathError> {
268 Ok(match *self {
269 MaybeRelocatable::Int(ref value) => MaybeRelocatable::Int(value - other as u64),
270 MaybeRelocatable::RelocatableValue(rel) => (rel - other)?.into(),
271 })
272 }
273
274 pub fn sub(&self, other: &MaybeRelocatable) -> Result<MaybeRelocatable, MathError> {
278 match (self, other) {
279 (MaybeRelocatable::Int(num_a), MaybeRelocatable::Int(num_b)) => {
280 Ok(MaybeRelocatable::Int(num_a - num_b))
281 }
282 (
283 MaybeRelocatable::RelocatableValue(rel_a),
284 MaybeRelocatable::RelocatableValue(rel_b),
285 ) => {
286 if rel_a.segment_index == rel_b.segment_index {
287 return Ok(MaybeRelocatable::from(Felt252::from(
288 rel_a.offset as i128 - rel_b.offset as i128,
289 )));
290 }
291 Err(MathError::RelocatableSubDiffIndex(Box::new((
292 *rel_a, *rel_b,
293 ))))
294 }
295 (MaybeRelocatable::RelocatableValue(rel_a), MaybeRelocatable::Int(ref num_b)) => {
296 Ok(MaybeRelocatable::from((
297 rel_a.segment_index,
298 (rel_a.offset as u64 - num_b)
299 .and_then(|x| x.to_usize())
300 .ok_or_else(|| {
301 MathError::RelocatableSubFelt252NegOffset(Box::new((*rel_a, *num_b)))
302 })?,
303 )))
304 }
305 (MaybeRelocatable::Int(int), MaybeRelocatable::RelocatableValue(rel)) => {
306 Err(MathError::SubRelocatableFromInt(Box::new((*int, *rel))))
307 }
308 }
309 }
310
311 pub fn divmod(
314 &self,
315 other: &MaybeRelocatable,
316 ) -> Result<(MaybeRelocatable, MaybeRelocatable), MathError> {
317 match (self, other) {
318 (MaybeRelocatable::Int(val), MaybeRelocatable::Int(div)) => Ok((
319 MaybeRelocatable::from(
320 val.field_div(&div.try_into().map_err(|_| MathError::DividedByZero)?),
321 ),
322 MaybeRelocatable::from(Felt252::ZERO),
324 )),
325 _ => Err(MathError::DivModWrongType(Box::new((
326 self.clone(),
327 other.clone(),
328 )))),
329 }
330 }
331
332 pub fn get_int_ref(&self) -> Option<&Felt252> {
335 match self {
336 MaybeRelocatable::Int(num) => Some(num),
337 MaybeRelocatable::RelocatableValue(_) => None,
338 }
339 }
340
341 pub fn get_int(&self) -> Option<Felt252> {
343 match self {
344 MaybeRelocatable::Int(num) => Some(*num),
345 MaybeRelocatable::RelocatableValue(_) => None,
346 }
347 }
348
349 pub fn get_relocatable(&self) -> Option<Relocatable> {
351 match self {
352 MaybeRelocatable::RelocatableValue(rel) => Some(*rel),
353 MaybeRelocatable::Int(_) => None,
354 }
355 }
356}
357
358pub fn relocate_value(
362 value: MaybeRelocatable,
363 relocation_table: &[usize],
364) -> Result<Felt252, MemoryError> {
365 match value {
366 MaybeRelocatable::Int(num) => Ok(num),
367 MaybeRelocatable::RelocatableValue(relocatable) => Ok(Felt252::from(relocate_address(
368 relocatable,
369 relocation_table,
370 )?)),
371 }
372}
373
374pub fn relocate_address(
376 relocatable: Relocatable,
377 relocation_table: &[usize],
378) -> Result<usize, MemoryError> {
379 let (segment_index, offset) = if relocatable.segment_index >= 0 {
380 (relocatable.segment_index as usize, relocatable.offset)
381 } else {
382 return Err(MemoryError::TemporarySegmentInRelocation(
383 relocatable.segment_index,
384 ));
385 };
386
387 if relocation_table.len() <= segment_index {
388 return Err(MemoryError::Relocation);
389 }
390
391 Ok(relocation_table[segment_index] + offset)
392}
393
394#[cfg(test)]
395mod tests {
396 use super::*;
397 use crate::{felt_hex, felt_str};
398 use crate::{relocatable, utils::test_utils::mayberelocatable};
399
400 use proptest::prelude::*;
401
402 proptest! {
403 #[test]
404 fn add_relocatable_felt(offset in any::<u64>(), ref bigint in any::<[u8; 32]>()) {
405 let big = &Felt252::from_bytes_be(bigint);
406 let rel = Relocatable::from((0, offset as usize));
407
408 let sum = (big + offset).to_usize()
409 .map(|offset| (0, offset).into());
410 prop_assert_eq!((rel + big).ok(), sum);
411 }
412
413 #[test]
414 fn add_relocatable_felt_extremes(offset in any::<u64>()) {
415 let big_zero = &Felt252::ZERO;
416 let big_max = &Felt252::MAX;
417 let big_min = &(big_zero + (i64::MIN as u64));
418 let rel = Relocatable::from((0, offset as usize));
419
420 let sum_max = (big_max + offset).to_usize()
421 .map(|offset| (0, offset).into());
422 prop_assert_eq!((rel + big_max).ok(), sum_max);
423 let sum_min = (big_min + offset).to_usize()
424 .map(|offset| (0, offset).into());
425 prop_assert_eq!((rel + big_min).ok(), sum_min);
426 let sum_zero = (big_zero + offset).to_usize()
427 .map(|offset| (0, offset).into());
428 prop_assert_eq!((rel + big_zero).ok(), sum_zero);
429 }
430 }
431
432 #[test]
433 fn add_bigint_to_int() {
434 let addr = MaybeRelocatable::from(Felt252::from(7i32));
435 let added_addr = addr.add_int(&Felt252::from(2i32));
436 assert_eq!(added_addr, Ok(MaybeRelocatable::Int(Felt252::from(9))));
437 }
438
439 #[test]
440 fn add_usize_to_int() {
441 let addr = MaybeRelocatable::from(Felt252::from(7_i32));
442 let added_addr = addr.add_usize(2).unwrap();
443 assert_eq!(MaybeRelocatable::Int(Felt252::from(9)), added_addr);
444 }
445
446 #[test]
447 fn add_bigint_to_relocatable() {
448 let addr = MaybeRelocatable::RelocatableValue(relocatable!(7, 65));
449 let added_addr = addr.add_int(&Felt252::from(2));
450 assert_eq!(
451 added_addr,
452 Ok(MaybeRelocatable::RelocatableValue(Relocatable {
453 segment_index: 7,
454 offset: 67
455 }))
456 );
457 }
458
459 #[test]
460 fn add_int_mod_offset_exceeded() {
461 let addr = MaybeRelocatable::from((0, 0));
462 let error = addr.add_int(&felt_hex!("0x10000000000000000"));
463 assert_eq!(
464 error,
465 Err(MathError::RelocatableAddFelt252OffsetExceeded(Box::new((
466 relocatable!(0, 0),
467 felt_hex!("0x10000000000000000")
468 ))))
469 );
470 }
471
472 #[test]
473 fn add_usize_to_relocatable() {
474 let addr = MaybeRelocatable::RelocatableValue(relocatable!(7, 65));
475 let added_addr = addr.add_usize(2);
476 assert_eq!(
477 added_addr,
478 Ok(MaybeRelocatable::RelocatableValue(Relocatable {
479 segment_index: 7,
480 offset: 67
481 }))
482 );
483 }
484
485 #[test]
486 fn add_bigint_to_int_prime_mod() {
487 let addr = MaybeRelocatable::Int(Felt252::MAX);
489 let added_addr = addr.add_int(&Felt252::from(5));
490 assert_eq!(added_addr, Ok(MaybeRelocatable::Int(Felt252::from(4))));
491 }
492
493 #[test]
494 fn add_bigint_to_relocatable_prime() {
495 let addr = MaybeRelocatable::from((1, 9));
496 let added_addr = addr.add_int(&felt_str!(
497 "3618502788666131213697322783095070105623107215331596699973092056135872020481"
498 ));
499 assert_eq!(
500 added_addr,
501 Ok(MaybeRelocatable::RelocatableValue(Relocatable {
502 segment_index: 1,
503 offset: 9
504 }))
505 );
506 }
507
508 #[test]
509 fn add_int_to_int() {
510 let addr_a = &MaybeRelocatable::from(felt_str!(
511 "3618502788666131213697322783095070105623107215331596699973092056135872020488"
512 ));
513 let addr_b = &MaybeRelocatable::from(Felt252::from(17_i32));
514 let added_addr = addr_a.add(addr_b);
515 assert_eq!(added_addr, Ok(MaybeRelocatable::Int(Felt252::from(24))));
516 }
517
518 #[test]
519 fn add_relocatable_to_relocatable_should_fail() {
520 let addr_a = &MaybeRelocatable::from((7, 5));
521 let addr_b = &MaybeRelocatable::RelocatableValue(relocatable!(7, 10));
522 let error = addr_a.add(addr_b);
523 assert_eq!(
524 error,
525 Err(MathError::RelocatableAdd(Box::new((
526 relocatable!(7, 5),
527 relocatable!(7, 10)
528 ))))
529 );
530 }
531
532 #[test]
533 fn add_int_to_relocatable() {
534 let addr_a = &MaybeRelocatable::from((7, 7));
535 let addr_b = &MaybeRelocatable::from(Felt252::from(10));
536 let added_addr = addr_a.add(addr_b);
537 assert_eq!(
538 added_addr,
539 Ok(MaybeRelocatable::RelocatableValue(Relocatable {
540 segment_index: 7,
541 offset: 17
542 }))
543 );
544 }
545
546 #[test]
547 fn add_relocatable_to_int() {
548 let addr_a = &MaybeRelocatable::from(Felt252::from(10_i32));
549 let addr_b = &MaybeRelocatable::RelocatableValue(relocatable!(7, 7));
550 let added_addr = addr_a.add(addr_b);
551 assert_eq!(
552 added_addr,
553 Ok(MaybeRelocatable::RelocatableValue(Relocatable {
554 segment_index: 7,
555 offset: 17
556 }))
557 );
558 }
559
560 #[test]
561 fn add_int_to_relocatable_prime() {
562 let addr_a = &MaybeRelocatable::from((7, 14));
563 let addr_b = &MaybeRelocatable::Int(felt_hex!(
564 "800000000000011000000000000000000000000000000000000000000000001"
565 ));
566 let added_addr = addr_a.add(addr_b);
567 assert_eq!(
568 added_addr,
569 Ok(MaybeRelocatable::RelocatableValue(Relocatable {
570 segment_index: 7,
571 offset: 14
572 }))
573 );
574 }
575
576 #[test]
577 fn add_int_rel_int_offset_exceeded() {
578 let addr = MaybeRelocatable::from((0, 0));
579 let error = addr.add(&MaybeRelocatable::from(felt_hex!("0x10000000000000000")));
580 assert_eq!(
581 error,
582 Err(MathError::RelocatableAddFelt252OffsetExceeded(Box::new((
583 relocatable!(0, 0),
584 felt_hex!("0x10000000000000000")
585 ))))
586 );
587 }
588
589 #[test]
590 fn add_int_int_rel_offset_exceeded() {
591 let addr = MaybeRelocatable::Int(felt_hex!("0x10000000000000000"));
592 let relocatable = Relocatable {
593 offset: 0,
594 segment_index: 0,
595 };
596 let error = addr.add(&MaybeRelocatable::RelocatableValue(relocatable));
597 assert_eq!(
598 error,
599 Err(MathError::RelocatableAddFelt252OffsetExceeded(Box::new((
600 relocatable!(0, 0),
601 felt_hex!("0x10000000000000000")
602 ))))
603 );
604 }
605
606 #[test]
607 fn sub_int_from_int() {
608 let addr_a = &MaybeRelocatable::from(Felt252::from(7));
609 let addr_b = &MaybeRelocatable::from(Felt252::from(5));
610 let sub_addr = addr_a.sub(addr_b);
611 assert_eq!(sub_addr, Ok(MaybeRelocatable::Int(Felt252::from(2))));
612 }
613
614 #[test]
615 fn sub_relocatable_from_relocatable_same_offset() {
616 let addr_a = &MaybeRelocatable::from((7, 17));
617 let addr_b = &MaybeRelocatable::from((7, 7));
618 let sub_addr = addr_a.sub(addr_b);
619 assert_eq!(sub_addr, Ok(MaybeRelocatable::Int(Felt252::from(10))));
620 }
621
622 #[test]
623 fn sub_relocatable_from_relocatable_diff_offset() {
624 let addr_a = &MaybeRelocatable::from((7, 17));
625 let addr_b = &MaybeRelocatable::from((8, 7));
626 let error = addr_a.sub(addr_b);
627 assert_eq!(
628 error,
629 Err(MathError::RelocatableSubDiffIndex(Box::new((
630 relocatable!(7, 17),
631 relocatable!(8, 7)
632 ))))
633 );
634 }
635
636 #[test]
637 fn sub_int_addr_ref_from_relocatable_addr_ref() {
638 let addr_a = &MaybeRelocatable::from((7, 17));
639 let addr_b = &MaybeRelocatable::from(Felt252::from(5_i32));
640 let addr_c = addr_a.sub(addr_b);
641 assert_eq!(addr_c, Ok(MaybeRelocatable::from((7, 12))));
642 }
643
644 #[test]
645 fn sub_rel_to_int_error() {
646 assert_eq!(
647 MaybeRelocatable::from(Felt252::from(7_i32)).sub(&MaybeRelocatable::from((7, 10))),
648 Err(MathError::SubRelocatableFromInt(Box::new((
649 Felt252::from(7_i32),
650 Relocatable::from((7, 10))
651 ))))
652 );
653 }
654
655 #[test]
656 fn divmod_working() {
657 let value = &MaybeRelocatable::from(Felt252::from(10));
658 let div = &MaybeRelocatable::from(Felt252::from(3));
659 let (q, r) = value.divmod(div).expect("Unexpected error in divmod");
660 assert_eq!(
661 q,
662 MaybeRelocatable::from(
663 Felt252::from(10).field_div(&Felt252::from(3).try_into().unwrap())
664 )
665 );
666 assert_eq!(r, MaybeRelocatable::from(Felt252::ZERO));
667 }
668
669 #[test]
670 fn divmod_bad_type() {
671 let value = &MaybeRelocatable::from(Felt252::from(10));
672 let div = &MaybeRelocatable::from((2, 7));
673 assert_eq!(
674 value.divmod(div),
675 Err(MathError::DivModWrongType(Box::new((
676 MaybeRelocatable::from(Felt252::from(10)),
677 MaybeRelocatable::from((2, 7))
678 ))))
679 );
680 }
681
682 #[test]
683 fn relocate_relocatable_value() {
684 let value = MaybeRelocatable::from((2, 7));
685 let relocation_table = vec![1, 2, 5];
686 assert_eq!(
687 relocate_value(value, &relocation_table),
688 Ok(Felt252::from(12))
689 );
690 }
691
692 #[test]
693 fn relocate_relocatable_in_temp_segment_value() {
694 let value = MaybeRelocatable::from((-1, 7));
695 let relocation_table = vec![1, 2, 5];
696 assert_eq!(
697 relocate_value(value, &relocation_table),
698 Err(MemoryError::TemporarySegmentInRelocation(-1)),
699 );
700 }
701
702 #[test]
703 fn relocate_relocatable_in_temp_segment_value_with_offset() {
704 let value = MaybeRelocatable::from((-1, 7));
705 let relocation_table = vec![1, 2, 5];
706 assert_eq!(
707 relocate_value(value, &relocation_table),
708 Err(MemoryError::TemporarySegmentInRelocation(-1)),
709 );
710 }
711
712 #[test]
713 fn relocate_relocatable_in_temp_segment_value_error() {
714 let value = MaybeRelocatable::from((-1, 7));
715 let relocation_table = vec![1, 2, 5];
716 assert_eq!(
717 relocate_value(value, &relocation_table),
718 Err(MemoryError::TemporarySegmentInRelocation(-1))
719 );
720 }
721
722 #[test]
723 fn relocate_int_value() {
724 let value = MaybeRelocatable::from(Felt252::from(7));
725 let relocation_table = vec![1, 2, 5];
726 assert_eq!(
727 relocate_value(value, &relocation_table),
728 Ok(Felt252::from(7))
729 );
730 }
731
732 #[test]
733 fn relocate_relocatable_value_no_relocation() {
734 let value = MaybeRelocatable::from((2, 7));
735 let relocation_table = vec![1, 2];
736 assert_eq!(
737 relocate_value(value, &relocation_table),
738 Err(MemoryError::Relocation)
739 );
740 }
741
742 #[test]
743 fn relocatable_add_int() {
744 assert_eq!(
745 relocatable!(1, 2) + &Felt252::from(4),
746 Ok(relocatable!(1, 6))
747 );
748 assert_eq!(relocatable!(3, 2) + &Felt252::ZERO, Ok(relocatable!(3, 2)));
749 }
750
751 #[test]
752 fn relocatable_add_int_mod_offset_exceeded_error() {
753 assert_eq!(
754 relocatable!(0, 0) + &(Felt252::from(usize::MAX) + 1_u64),
755 Err(MathError::RelocatableAddFelt252OffsetExceeded(Box::new((
756 relocatable!(0, 0),
757 Felt252::from(usize::MAX) + 1_u64
758 ))))
759 );
760 }
761
762 #[test]
763 fn relocatable_add_i32() {
764 let reloc = relocatable!(1, 5);
765
766 assert_eq!(reloc + 3, Ok(relocatable!(1, 8)));
767 assert_eq!(reloc + (-3), Ok(relocatable!(1, 2)));
768 }
769
770 #[test]
771 fn relocatable_add_i32_with_overflow() {
772 let reloc = relocatable!(1, 1);
773
774 assert_eq!(
775 reloc + (-3),
776 Err(MathError::RelocatableSubUsizeNegOffset(Box::new((
777 relocatable!(1, 1),
778 3
779 ))))
780 );
781 }
782
783 #[test]
784 fn mayberelocatable_try_into_reloctable() {
785 let address = mayberelocatable!(1, 2);
786 assert_eq!(Ok(relocatable!(1, 2)), address.try_into());
787
788 let value = mayberelocatable!(1);
789 let err: Result<Relocatable, _> = value.try_into();
790 assert_eq!(Err(MemoryError::AddressNotRelocatable), err)
791 }
792
793 #[test]
794 fn relocatable_sub_rel_test() {
795 let reloc = relocatable!(7, 6);
796 assert_eq!(reloc - relocatable!(7, 5), Ok(1));
797 assert_eq!(
798 reloc - relocatable!(7, 9),
799 Err(MathError::RelocatableSubUsizeNegOffset(Box::new((
800 relocatable!(7, 6),
801 9
802 ))))
803 );
804 }
805
806 #[test]
807 fn sub_rel_different_indexes() {
808 let a = relocatable!(7, 6);
809 let b = relocatable!(8, 6);
810 assert_eq!(
811 a - b,
812 Err(MathError::RelocatableSubDiffIndex(Box::new((a, b))))
813 );
814 }
815
816 #[test]
817 fn add_maybe_mod_ok() {
818 assert_eq!(
819 relocatable!(1, 0) + &mayberelocatable!(2),
820 Ok(relocatable!(1, 2))
821 );
822 assert_eq!(
823 relocatable!(0, 29) + &mayberelocatable!(100),
824 Ok(relocatable!(0, 129))
825 );
826 assert_eq!(
827 relocatable!(2, 12) + &mayberelocatable!(104),
828 Ok(relocatable!(2, 116))
829 );
830 assert_eq!(
831 relocatable!(1, 0) + &mayberelocatable!(0),
832 Ok(relocatable!(1, 0))
833 );
834 assert_eq!(
835 relocatable!(1, 2) + &mayberelocatable!(71),
836 Ok(relocatable!(1, 73))
837 );
838 }
839
840 #[test]
841 fn add_maybe_mod_add_two_relocatable_error() {
842 assert_eq!(
843 relocatable!(1, 0) + &mayberelocatable!(1, 2),
844 Err(MathError::RelocatableAdd(Box::new((
845 relocatable!(1, 0),
846 relocatable!(1, 2)
847 ))))
848 );
849 }
850
851 #[test]
852 fn add_maybe_mod_offset_exceeded_error() {
853 assert_eq!(
854 relocatable!(1, 0) + &mayberelocatable!(usize::MAX as i128 + 1),
855 Err(MathError::RelocatableAddFelt252OffsetExceeded(Box::new((
856 relocatable!(1, 0),
857 Felt252::from(usize::MAX) + 1_u64
858 ))))
859 );
860 }
861
862 #[test]
863 fn get_relocatable_test() {
864 assert_eq!(
865 mayberelocatable!(1, 2).get_relocatable(),
866 Some(relocatable!(1, 2))
867 );
868 assert_eq!(mayberelocatable!(3).get_relocatable(), None)
869 }
870
871 #[test]
872 fn relocatable_display() {
873 assert_eq!(
874 format!("{}", Relocatable::from((1, 0))),
875 String::from("1:0")
876 )
877 }
878
879 #[test]
880 fn maybe_relocatable_relocatable_display() {
881 assert_eq!(
882 format!("{}", MaybeRelocatable::from((1, 0))),
883 String::from("1:0")
884 )
885 }
886
887 #[test]
888 fn maybe_relocatable_int_display() {
889 assert_eq!(
890 format!("{}", MaybeRelocatable::from(Felt252::from(6))),
891 String::from("6")
892 )
893 }
894
895 #[test]
896 fn relocatable_add_assign_usize() {
897 let mut addr = Relocatable::from((1, 0));
898 addr += 1;
899 assert_eq!(addr, Relocatable::from((1, 1)))
900 }
901}