i64.move 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. module pyth::i64 {
  2. use pyth::error;
  3. const MAX_POSITIVE_MAGNITUDE: u64 = (1 << 63) - 1;
  4. const MAX_NEGATIVE_MAGNITUDE: u64 = (1 << 63);
  5. /// As Move does not support negative numbers natively, we use our own internal
  6. /// representation.
  7. struct I64 has copy, drop, store {
  8. negative: bool,
  9. magnitude: u64,
  10. }
  11. public fun new(magnitude: u64, negative: bool): I64 {
  12. let max_magnitude = MAX_POSITIVE_MAGNITUDE;
  13. if (negative) {
  14. max_magnitude = MAX_NEGATIVE_MAGNITUDE;
  15. };
  16. assert!(magnitude <= max_magnitude, error::magnitude_too_large());
  17. // Ensure we have a single zero representation: (0, false).
  18. // (0, true) is invalid.
  19. if (magnitude == 0) {
  20. negative = false;
  21. };
  22. I64 {
  23. magnitude: magnitude,
  24. negative: negative,
  25. }
  26. }
  27. public fun get_is_negative(i: &I64): bool {
  28. i.negative
  29. }
  30. public fun get_magnitude(in: &I64): u64 {
  31. in.magnitude
  32. }
  33. public fun get_magnitude_if_positive(in: &I64): u64 {
  34. assert!(!in.negative, error::negative_value());
  35. in.magnitude
  36. }
  37. public fun get_magnitude_if_negative(in: &I64): u64 {
  38. assert!(in.negative, error::positive_value());
  39. in.magnitude
  40. }
  41. public fun from_u64(from: u64): I64 {
  42. // Use the MSB to determine whether the number is negative or not.
  43. let negative = (from >> 63) == 1;
  44. let magnitude = parse_magnitude(from, negative);
  45. new(magnitude, negative)
  46. }
  47. fun parse_magnitude(from: u64, negative: bool): u64 {
  48. // If positive, then return the input verbatamin
  49. if (!negative) {
  50. return from
  51. };
  52. // Otherwise convert from two's complement by inverting and adding 1
  53. let inverted = from ^ 0xFFFFFFFFFFFFFFFF;
  54. inverted + 1
  55. }
  56. #[test]
  57. fun test_max_positive_magnitude() {
  58. new(0x7FFFFFFFFFFFFFFF, false);
  59. assert!(&new(1<<63 - 1, false) == &from_u64(1<<63 - 1), 1);
  60. }
  61. #[test]
  62. #[expected_failure(abort_code = 65557)]
  63. fun test_magnitude_too_large_positive() {
  64. new(0x8000000000000000, false);
  65. }
  66. #[test]
  67. fun test_max_negative_magnitude() {
  68. new(0x8000000000000000, true);
  69. assert!(&new(1<<63, true) == &from_u64(1<<63), 1);
  70. }
  71. #[test]
  72. #[expected_failure(abort_code = 65557)]
  73. fun test_magnitude_too_large_negative() {
  74. new(0x8000000000000001, true);
  75. }
  76. #[test]
  77. fun test_from_u64_positive() {
  78. assert!(from_u64(0x64673) == new(0x64673, false), 1);
  79. }
  80. #[test]
  81. fun test_from_u64_negative() {
  82. assert!(from_u64(0xFFFFFFFFFFFEDC73) == new(0x1238D, true), 1);
  83. }
  84. #[test]
  85. fun test_get_is_negative() {
  86. assert!(get_is_negative(&new(234, true)) == true, 1);
  87. assert!(get_is_negative(&new(767, false)) == false, 1);
  88. }
  89. #[test]
  90. fun test_get_magnitude() {
  91. assert!(get_magnitude(&new(234, false)) == 234, 1);
  92. }
  93. #[test]
  94. fun test_get_magnitude_if_positive_positive() {
  95. assert!(get_magnitude_if_positive(&new(7686, false)) == 7686, 1);
  96. }
  97. #[test]
  98. #[expected_failure(abort_code = 196609)]
  99. fun test_get_magnitude_if_positive_negative() {
  100. assert!(get_magnitude_if_positive(&new(7686, true)) == 7686, 1);
  101. }
  102. #[test]
  103. fun test_get_magnitude_if_negative_negative() {
  104. assert!(get_magnitude_if_negative(&new(7686, true)) == 7686, 1);
  105. }
  106. #[test]
  107. #[expected_failure(abort_code = 196627)]
  108. fun test_get_magnitude_if_negative_positive() {
  109. assert!(get_magnitude_if_negative(&new(7686, false)) == 7686, 1);
  110. }
  111. #[test]
  112. fun test_single_zero_representation() {
  113. assert!(&new(0, true) == &new(0, false), 1);
  114. assert!(&new(0, true) == &from_u64(0), 1);
  115. assert!(&new(0, false) == &from_u64(0), 1);
  116. }
  117. }