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