i64.move 4.0 KB

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