i16.move 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /// Adapted from pyth::i64, modified for i16
  2. module pyth_lazer::i16;
  3. const MAX_POSITIVE_MAGNITUDE: u64 = (1 << 15) - 1; // 32767
  4. const MAX_NEGATIVE_MAGNITUDE: u64 = (1 << 15); // 32768
  5. /// To consume these values, first call `get_is_negative()` to determine if the I16
  6. /// represents a negative or positive value. Then call `get_magnitude_if_positive()` or
  7. /// `get_magnitude_if_negative()` to get the magnitude of the number in unsigned u64 format.
  8. /// This API forces consumers to handle positive and negative numbers safely.
  9. public struct I16 has copy, drop, store {
  10. negative: bool,
  11. magnitude: u64,
  12. }
  13. public fun new(magnitude: u64, mut negative: bool): I16 {
  14. let mut max_magnitude = MAX_POSITIVE_MAGNITUDE;
  15. if (negative) {
  16. max_magnitude = MAX_NEGATIVE_MAGNITUDE;
  17. };
  18. assert!(magnitude <= max_magnitude, 0); //error::magnitude_too_large()
  19. // Ensure we have a single zero representation: (0, false).
  20. // (0, true) is invalid.
  21. if (magnitude == 0) {
  22. negative = false;
  23. };
  24. I16 {
  25. magnitude,
  26. negative,
  27. }
  28. }
  29. public fun get_is_negative(i: &I16): bool {
  30. i.negative
  31. }
  32. public fun get_magnitude_if_positive(in: &I16): u64 {
  33. assert!(!in.negative, 0); // error::negative_value()
  34. in.magnitude
  35. }
  36. public fun get_magnitude_if_negative(in: &I16): u64 {
  37. assert!(in.negative, 0); //error::positive_value()
  38. in.magnitude
  39. }
  40. public fun from_u16(from: u16): I16 {
  41. // Use the MSB to determine whether the number is negative or not.
  42. let from_u64 = (from as u64);
  43. let negative = (from_u64 >> 15) == 1;
  44. let magnitude = parse_magnitude(from_u64, negative);
  45. new(magnitude, negative)
  46. }
  47. fun parse_magnitude(from: u64, negative: bool): u64 {
  48. // If positive, then return the input verbatim
  49. if (!negative) {
  50. return from
  51. };
  52. // Otherwise convert from two's complement by inverting and adding 1
  53. // For 16-bit numbers, we only invert the lower 16 bits
  54. let inverted = from ^ 0xFFFF;
  55. inverted + 1
  56. }
  57. #[test]
  58. fun test_max_positive_magnitude() {
  59. new(0x7FFF, false); // 32767
  60. assert!(&new((1<<15) - 1, false) == &from_u16(((1<<15) - 1) as u16), 1);
  61. }
  62. #[test]
  63. #[expected_failure]
  64. fun test_magnitude_too_large_positive() {
  65. new(0x8000, false); // 32768
  66. }
  67. #[test]
  68. fun test_max_negative_magnitude() {
  69. new(0x8000, true); // 32768
  70. assert!(&new(1<<15, true) == &from_u16((1<<15) as u16), 1);
  71. }
  72. #[test]
  73. #[expected_failure]
  74. fun test_magnitude_too_large_negative() {
  75. new(0x8001, true); // 32769
  76. }
  77. #[test]
  78. fun test_from_u16_positive() {
  79. assert!(from_u16(0x1234) == new(0x1234, false), 1);
  80. }
  81. #[test]
  82. fun test_from_u16_negative() {
  83. assert!(from_u16(0xEDCC) == new(0x1234, true), 1);
  84. }
  85. #[test]
  86. fun test_get_is_negative() {
  87. assert!(get_is_negative(&new(234, true)) == true, 1);
  88. assert!(get_is_negative(&new(767, false)) == false, 1);
  89. }
  90. #[test]
  91. fun test_get_magnitude_if_positive_positive() {
  92. assert!(get_magnitude_if_positive(&new(7686, false)) == 7686, 1);
  93. }
  94. #[test]
  95. #[expected_failure]
  96. fun test_get_magnitude_if_positive_negative() {
  97. assert!(get_magnitude_if_positive(&new(7686, true)) == 7686, 1);
  98. }
  99. #[test]
  100. fun test_get_magnitude_if_negative_negative() {
  101. assert!(get_magnitude_if_negative(&new(7686, true)) == 7686, 1);
  102. }
  103. #[test]
  104. #[expected_failure]
  105. fun test_get_magnitude_if_negative_positive() {
  106. assert!(get_magnitude_if_negative(&new(7686, false)) == 7686, 1);
  107. }
  108. #[test]
  109. fun test_single_zero_representation() {
  110. assert!(&new(0, true) == &new(0, false), 1);
  111. assert!(&new(0, true) == &from_u16(0), 1);
  112. assert!(&new(0, false) == &from_u16(0), 1);
  113. }
  114. #[test]
  115. fun test_boundary_values() {
  116. // Test positive boundary
  117. assert!(from_u16(0x7FFF) == new(32767, false), 1);
  118. // Test negative boundary
  119. assert!(from_u16(0x8000) == new(32768, true), 1);
  120. // Test -1
  121. assert!(from_u16(0xFFFF) == new(1, true), 1);
  122. }