1mod xrpl_iou_value;
2
3pub use xrpl_iou_value::{FLOAT_NEGATIVE_ONE, FLOAT_ONE, FLOAT_ZERO, XrplIouValue};
4
5mod ffi {
7 #![allow(non_upper_case_globals)]
8 #![allow(non_camel_case_types)]
9 #![allow(non_snake_case)]
10 #![allow(unused)]
11 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
12}
13
14use std::ffi::CStr;
15use std::fmt;
16use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20pub enum NumberError {
21 Overflow,
22 DivideByZero,
23 InvalidArgument,
24 OutOfMemory,
25 Unknown,
26}
27
28impl fmt::Display for NumberError {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 match self {
31 NumberError::Overflow => write!(f, "Number overflow"),
32 NumberError::DivideByZero => write!(f, "Division by zero"),
33 NumberError::InvalidArgument => write!(f, "Invalid argument"),
34 NumberError::OutOfMemory => write!(f, "Out of memory"),
35 NumberError::Unknown => write!(f, "Unknown error"),
36 }
37 }
38}
39
40impl std::error::Error for NumberError {}
41
42impl From<ffi::NumberError> for NumberError {
43 fn from(error: ffi::NumberError) -> Self {
44 match error {
45 ffi::NumberError_NUMBER_ERROR_OVERFLOW => NumberError::Overflow,
46 ffi::NumberError_NUMBER_ERROR_DIVIDE_BY_ZERO => NumberError::DivideByZero,
47 ffi::NumberError_NUMBER_ERROR_INVALID_ARGUMENT => NumberError::InvalidArgument,
48 ffi::NumberError_NUMBER_ERROR_OUT_OF_MEMORY => NumberError::OutOfMemory,
49 _ => NumberError::Unknown,
50 }
51 }
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum RoundingMode {
57 ToNearest,
58 TowardsZero,
59 Downward,
60 Upward,
61}
62
63impl From<RoundingMode> for ffi::RoundingMode {
64 fn from(mode: RoundingMode) -> Self {
65 match mode {
66 RoundingMode::ToNearest => ffi::RoundingMode_ROUNDING_TO_NEAREST,
67 RoundingMode::TowardsZero => ffi::RoundingMode_ROUNDING_TOWARDS_ZERO,
68 RoundingMode::Downward => ffi::RoundingMode_ROUNDING_DOWNWARD,
69 RoundingMode::Upward => ffi::RoundingMode_ROUNDING_UPWARD,
70 }
71 }
72}
73
74impl From<ffi::RoundingMode> for RoundingMode {
75 fn from(mode: ffi::RoundingMode) -> Self {
76 match mode {
77 ffi::RoundingMode_ROUNDING_TO_NEAREST => RoundingMode::ToNearest,
78 ffi::RoundingMode_ROUNDING_TOWARDS_ZERO => RoundingMode::TowardsZero,
79 ffi::RoundingMode_ROUNDING_DOWNWARD => RoundingMode::Downward,
80 ffi::RoundingMode_ROUNDING_UPWARD => RoundingMode::Upward,
81 _ => RoundingMode::ToNearest,
82 }
83 }
84}
85
86pub struct Number {
88 ptr: *mut ffi::Number,
89}
90
91unsafe impl Send for Number {}
92unsafe impl Sync for Number {}
93
94impl Number {
95 pub fn new() -> Self {
97 let ptr = unsafe { ffi::number_new() };
98 if ptr.is_null() {
99 panic!("Failed to allocate Number");
100 }
101 Number { ptr }
102 }
103
104 pub fn from_i64(mantissa: i64) -> Result<Self, NumberError> {
106 let mut error = ffi::NumberError_NUMBER_SUCCESS;
107 let ptr = unsafe { ffi::number_new_from_int64(mantissa, &mut error) };
108 if ptr.is_null() {
109 return Err(error.into());
110 }
111 Ok(Number { ptr })
112 }
113
114 pub fn from_mantissa_exponent(mantissa: i64, exponent: i32) -> Result<Self, NumberError> {
116 let mut error = ffi::NumberError_NUMBER_SUCCESS;
117 let ptr = unsafe { ffi::number_new_from_mantissa_exponent(mantissa, exponent, &mut error) };
118 if ptr.is_null() {
119 return Err(error.into());
120 }
121 Ok(Number { ptr })
122 }
123
124 pub fn from_xrpl_iou_value(buffer: XrplIouValue) -> Result<Self, NumberError> {
132 if buffer == FLOAT_ZERO {
133 return Ok(Number::new());
134 }
135
136 let value = u64::from_be_bytes(buffer);
138
139 let type_bit = (value >> 63) & 1;
141 let sign_bit = (value >> 62) & 1;
142 let exponent_bits = ((value >> 54) & 0xFF) as u8;
143 let mantissa_bits = value & 0x3FFFFFFFFFFFFF; if type_bit != 1 {
147 return Err(NumberError::InvalidArgument);
148 }
149
150 if mantissa_bits == 0 {
152 return Err(NumberError::InvalidArgument);
154 }
155
156 let exponent = (exponent_bits as i32) - 97;
158
159 if !(-96..=80).contains(&exponent) {
161 return Err(NumberError::InvalidArgument);
162 }
163
164 let mantissa = if sign_bit == 1 {
166 mantissa_bits as i64 } else {
168 -(mantissa_bits as i64) };
170
171 Self::from_mantissa_exponent(mantissa, exponent)
173 }
174
175 pub fn to_xrpl_iou_value(&self) -> Result<XrplIouValue, NumberError> {
183 if self.is_zero() {
185 return Ok(FLOAT_ZERO);
186 }
187
188 let mantissa = self.mantissa();
189 let exponent = self.exponent();
190
191 if !(-96..=80).contains(&exponent) {
193 return Err(NumberError::InvalidArgument);
194 }
195
196 let abs_mantissa = mantissa.unsigned_abs();
198
199 if abs_mantissa == 0 {
202 return Ok(FLOAT_ZERO);
203 }
204
205 if abs_mantissa > 0x3FFFFFFFFFFFFF {
207 return Err(NumberError::InvalidArgument);
208 }
209
210 let sign_bit = if mantissa >= 0 { 1u64 } else { 0u64 };
212
213 let exponent_bits = (exponent + 97) as u8;
215
216 let mut value = 0u64;
218 value |= 1u64 << 63; value |= sign_bit << 62; value |= (exponent_bits as u64) << 54; value |= abs_mantissa; Ok(value.to_be_bytes())
225 }
226
227 pub fn mantissa(&self) -> i64 {
229 unsafe { ffi::number_get_mantissa(self.ptr) }
230 }
231
232 pub fn exponent(&self) -> i32 {
234 unsafe { ffi::number_get_exponent(self.ptr) }
235 }
236
237 pub fn to_i64(&self) -> Result<i64, NumberError> {
239 let mut result = 0i64;
240 let error = unsafe { ffi::number_to_int64(self.ptr, &mut result) };
241 if error == ffi::NumberError_NUMBER_SUCCESS {
242 Ok(result)
243 } else {
244 Err(error.into())
245 }
246 }
247
248 pub fn signum(&self) -> i32 {
250 unsafe { ffi::number_signum(self.ptr) }
251 }
252
253 pub fn is_zero(&self) -> bool {
255 unsafe { ffi::number_is_zero(self.ptr) }
256 }
257
258 pub fn abs(&self) -> Result<Self, NumberError> {
260 let result = Number::new();
261 let error = unsafe { ffi::number_abs(result.ptr, self.ptr) };
262 if error == ffi::NumberError_NUMBER_SUCCESS {
263 Ok(result)
264 } else {
265 Err(error.into())
266 }
267 }
268
269 pub fn pow(&self, exponent: u32) -> Result<Self, NumberError> {
271 let result = Number::new();
272 let error = unsafe { ffi::number_power_uint(result.ptr, self.ptr, exponent) };
273 if error == ffi::NumberError_NUMBER_SUCCESS {
274 Ok(result)
275 } else {
276 Err(error.into())
277 }
278 }
279
280 pub fn root(&self, degree: u32) -> Result<Self, NumberError> {
282 let result = Number::new();
283 let error = unsafe { ffi::number_root(result.ptr, self.ptr, degree) };
284 if error == ffi::NumberError_NUMBER_SUCCESS {
285 Ok(result)
286 } else {
287 Err(error.into())
288 }
289 }
290
291 pub fn sqrt(&self) -> Result<Self, NumberError> {
293 let result = Number::new();
294 let error = unsafe { ffi::number_sqrt(result.ptr, self.ptr) };
295 if error == ffi::NumberError_NUMBER_SUCCESS {
296 Ok(result)
297 } else {
298 Err(error.into())
299 }
300 }
301
302 pub fn log10(&self) -> Result<Self, NumberError> {
304 let result = Number::new();
305 let error = unsafe { ffi::number_log10(result.ptr, self.ptr) };
306 if error == ffi::NumberError_NUMBER_SUCCESS {
307 Ok(result)
308 } else {
309 Err(error.into())
310 }
311 }
312
313 pub fn get_rounding_mode() -> RoundingMode {
315 let mode = unsafe { ffi::number_get_rounding_mode() };
316 mode.into()
317 }
318
319 pub fn set_rounding_mode(mode: RoundingMode) -> RoundingMode {
321 let prev_mode = unsafe { ffi::number_set_rounding_mode(mode.into()) };
322 prev_mode.into()
323 }
324
325 pub fn min() -> Self {
327 let ptr = unsafe { ffi::number_min() };
328 if ptr.is_null() {
329 panic!("Failed to create min Number");
330 }
331 Number { ptr }
332 }
333
334 pub fn max() -> Self {
336 let ptr = unsafe { ffi::number_max() };
337 if ptr.is_null() {
338 panic!("Failed to create max Number");
339 }
340 Number { ptr }
341 }
342
343 pub fn lowest() -> Self {
345 let ptr = unsafe { ffi::number_lowest() };
346 if ptr.is_null() {
347 panic!("Failed to create lowest Number");
348 }
349 Number { ptr }
350 }
351}
352
353impl Default for Number {
354 fn default() -> Self {
355 Self::new()
356 }
357}
358
359impl Clone for Number {
360 fn clone(&self) -> Self {
361 let mut error = ffi::NumberError_NUMBER_SUCCESS;
362 let ptr = unsafe { ffi::number_clone(self.ptr, &mut error) };
363 if ptr.is_null() {
364 panic!("Failed to clone Number: {:?}", NumberError::from(error));
365 }
366 Number { ptr }
367 }
368}
369
370impl Drop for Number {
371 fn drop(&mut self) {
372 unsafe { ffi::number_free(self.ptr) };
373 }
374}
375
376impl fmt::Display for Number {
377 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378 let len = unsafe { ffi::number_string_length(self.ptr) };
379 let mut buffer = vec![0u8; len + 1];
380 let error = unsafe {
381 ffi::number_to_string(self.ptr, buffer.as_mut_ptr() as *mut i8, buffer.len())
382 };
383 if error != ffi::NumberError_NUMBER_SUCCESS {
384 return Err(fmt::Error);
385 }
386 let cstr = unsafe { CStr::from_ptr(buffer.as_ptr() as *const i8) };
387 let s = cstr.to_str().map_err(|_| fmt::Error)?;
388 write!(f, "{}", s)
389 }
390}
391
392impl fmt::Debug for Number {
393 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
394 f.debug_struct("Number")
395 .field("mantissa", &self.mantissa())
396 .field("exponent", &self.exponent())
397 .field("value", &self.to_string())
398 .finish()
399 }
400}
401
402impl Add for &Number {
404 type Output = Result<Number, NumberError>;
405
406 fn add(self, rhs: &Number) -> Self::Output {
407 let result = Number::new();
408 let error = unsafe { ffi::number_add(result.ptr, self.ptr, rhs.ptr) };
409 if error == ffi::NumberError_NUMBER_SUCCESS {
410 Ok(result)
411 } else {
412 Err(error.into())
413 }
414 }
415}
416
417impl Add for Number {
418 type Output = Result<Number, NumberError>;
419
420 fn add(self, rhs: Number) -> Self::Output {
421 &self + &rhs
422 }
423}
424
425impl Sub for &Number {
426 type Output = Result<Number, NumberError>;
427
428 fn sub(self, rhs: &Number) -> Self::Output {
429 let result = Number::new();
430 let error = unsafe { ffi::number_subtract(result.ptr, self.ptr, rhs.ptr) };
431 if error == ffi::NumberError_NUMBER_SUCCESS {
432 Ok(result)
433 } else {
434 Err(error.into())
435 }
436 }
437}
438
439impl Sub for Number {
440 type Output = Result<Number, NumberError>;
441
442 fn sub(self, rhs: Number) -> Self::Output {
443 &self - &rhs
444 }
445}
446
447impl Mul for &Number {
448 type Output = Result<Number, NumberError>;
449
450 fn mul(self, rhs: &Number) -> Self::Output {
451 let result = Number::new();
452 let error = unsafe { ffi::number_multiply(result.ptr, self.ptr, rhs.ptr) };
453 if error == ffi::NumberError_NUMBER_SUCCESS {
454 Ok(result)
455 } else {
456 Err(error.into())
457 }
458 }
459}
460
461impl Mul for Number {
462 type Output = Result<Number, NumberError>;
463
464 fn mul(self, rhs: Number) -> Self::Output {
465 &self * &rhs
466 }
467}
468
469impl Div for &Number {
470 type Output = Result<Number, NumberError>;
471
472 fn div(self, rhs: &Number) -> Self::Output {
473 let result = Number::new();
474 let error = unsafe { ffi::number_divide(result.ptr, self.ptr, rhs.ptr) };
475 if error == ffi::NumberError_NUMBER_SUCCESS {
476 Ok(result)
477 } else {
478 Err(error.into())
479 }
480 }
481}
482
483impl Div for Number {
484 type Output = Result<Number, NumberError>;
485
486 fn div(self, rhs: Number) -> Self::Output {
487 &self / &rhs
488 }
489}
490
491impl Neg for &Number {
492 type Output = Result<Number, NumberError>;
493
494 fn neg(self) -> Self::Output {
495 let result = Number::new();
496 let error = unsafe { ffi::number_negate(result.ptr, self.ptr) };
497 if error == ffi::NumberError_NUMBER_SUCCESS {
498 Ok(result)
499 } else {
500 Err(error.into())
501 }
502 }
503}
504
505impl Neg for Number {
506 type Output = Result<Number, NumberError>;
507
508 fn neg(self) -> Self::Output {
509 -&self
510 }
511}
512
513impl AddAssign<&Number> for Number {
515 fn add_assign(&mut self, rhs: &Number) {
516 let error = unsafe { ffi::number_add_assign(self.ptr, rhs.ptr) };
517 if error != ffi::NumberError_NUMBER_SUCCESS {
518 panic!("Number addition failed: {:?}", NumberError::from(error));
519 }
520 }
521}
522
523impl AddAssign<Number> for Number {
524 fn add_assign(&mut self, rhs: Number) {
525 *self += &rhs;
526 }
527}
528
529impl SubAssign<&Number> for Number {
530 fn sub_assign(&mut self, rhs: &Number) {
531 let error = unsafe { ffi::number_subtract_assign(self.ptr, rhs.ptr) };
532 if error != ffi::NumberError_NUMBER_SUCCESS {
533 panic!("Number subtraction failed: {:?}", NumberError::from(error));
534 }
535 }
536}
537
538impl SubAssign<Number> for Number {
539 fn sub_assign(&mut self, rhs: Number) {
540 *self -= &rhs;
541 }
542}
543
544impl MulAssign<&Number> for Number {
545 fn mul_assign(&mut self, rhs: &Number) {
546 let error = unsafe { ffi::number_multiply_assign(self.ptr, rhs.ptr) };
547 if error != ffi::NumberError_NUMBER_SUCCESS {
548 panic!(
549 "Number multiplication failed: {:?}",
550 NumberError::from(error)
551 );
552 }
553 }
554}
555
556impl MulAssign<Number> for Number {
557 fn mul_assign(&mut self, rhs: Number) {
558 *self *= &rhs;
559 }
560}
561
562impl DivAssign<&Number> for Number {
563 fn div_assign(&mut self, rhs: &Number) {
564 let error = unsafe { ffi::number_divide_assign(self.ptr, rhs.ptr) };
565 if error != ffi::NumberError_NUMBER_SUCCESS {
566 panic!("Number division failed: {:?}", NumberError::from(error));
567 }
568 }
569}
570
571impl DivAssign<Number> for Number {
572 fn div_assign(&mut self, rhs: Number) {
573 *self /= &rhs;
574 }
575}
576
577impl PartialEq for Number {
579 fn eq(&self, other: &Self) -> bool {
580 unsafe { ffi::number_equals(self.ptr, other.ptr) }
581 }
582}
583
584impl Eq for Number {}
585
586impl PartialOrd for Number {
587 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
588 Some(self.cmp(other))
589 }
590}
591
592impl Ord for Number {
593 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
594 if unsafe { ffi::number_less_than(self.ptr, other.ptr) } {
595 std::cmp::Ordering::Less
596 } else if unsafe { ffi::number_greater_than(self.ptr, other.ptr) } {
597 std::cmp::Ordering::Greater
598 } else {
599 std::cmp::Ordering::Equal
600 }
601 }
602}
603
604impl From<i64> for Number {
606 fn from(value: i64) -> Self {
607 Number::from_i64(value).expect("Failed to create Number from i64")
608 }
609}
610
611impl TryFrom<XrplIouValue> for Number {
612 type Error = NumberError;
613
614 fn try_from(buffer: XrplIouValue) -> Result<Self, Self::Error> {
615 Number::from_xrpl_iou_value(buffer)
616 }
617}
618
619impl TryFrom<&Number> for XrplIouValue {
620 type Error = NumberError;
621
622 fn try_from(number: &Number) -> Result<Self, Self::Error> {
623 number.to_xrpl_iou_value()
624 }
625}
626
627impl TryFrom<Number> for XrplIouValue {
628 type Error = NumberError;
629
630 fn try_from(number: Number) -> Result<Self, Self::Error> {
631 number.to_xrpl_iou_value()
632 }
633}
634
635#[cfg(test)]
636mod tests {
637 use super::*;
638
639 #[test]
640 fn test_basic_arithmetic() {
641 let a = Number::from(100);
642 let b = Number::from(50);
643
644 let sum = (&a + &b).expect("Addition failed");
645 assert_eq!(sum.to_i64().expect("Conversion failed"), 150);
646
647 let diff = (&a - &b).expect("Subtraction failed");
648 assert_eq!(diff.to_i64().expect("Conversion failed"), 50);
649
650 let prod = (&a * &b).expect("Multiplication failed");
651 assert_eq!(prod.to_i64().expect("Conversion failed"), 5000);
652
653 let quot = (&a / &b).expect("Division failed");
654 assert_eq!(quot.to_i64().expect("Conversion failed"), 2);
655 }
656
657 #[test]
658 fn test_comparison() {
659 let a = Number::from(100);
660 let b = Number::from(50);
661 let c = Number::from(100);
662
663 assert!(a > b);
664 assert!(b < a);
665 assert!(a == c);
666 assert!(a >= c);
667 assert!(b <= a);
668 }
669
670 #[test]
671 fn test_display() {
672 let n = Number::from(12345);
673 let s = format!("{}", n);
674 assert!(!s.is_empty());
675 }
676
677 #[test]
678 fn test_mantissa_exponent() {
679 let n = Number::from_mantissa_exponent(12345, -2).expect("Failed to create number");
680 assert_eq!(n.to_i64().expect("Conversion failed"), 123);
683 }
684
685 #[test]
686 fn test_zero() {
687 let zero = Number::new();
688 assert!(zero.is_zero());
689 assert_eq!(zero.signum(), 0);
690 }
691
692 #[test]
693 fn test_mathematical_functions() {
694 let four = Number::from(4);
695 let sqrt_four = four.sqrt().expect("Square root failed");
696 assert_eq!(sqrt_four.to_i64().expect("Conversion failed"), 2);
697
698 let two = Number::from(2);
699 let eight = two.pow(3).expect("Power failed");
700 assert_eq!(eight.to_i64().expect("Conversion failed"), 8);
701 }
702
703 #[test]
704 fn test_xrpl_iou_value_zero() {
705 let zero_bytes = [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
707 let number = Number::from_xrpl_iou_value(zero_bytes).expect("Failed to parse zero");
708 assert!(number.is_zero());
709 assert_eq!(number.signum(), 0);
710 }
711
712 #[test]
713 fn test_xrpl_iou_value_positive() {
714 let mantissa = 1_000_000_000_000_000u64; let exponent = 82u8; let mut value = 0u64;
723 value |= 1u64 << 63; value |= 1u64 << 62; value |= (exponent as u64) << 54; value |= mantissa; let bytes = value.to_be_bytes();
729 let number = Number::from_xrpl_iou_value(bytes).expect("Failed to parse positive");
730
731 assert!(!number.is_zero());
732 assert_eq!(number.signum(), 1);
733
734 let string_val = number.to_string();
736 assert!(string_val.starts_with('1') || string_val == "1");
737 }
738
739 #[test]
740 fn test_xrpl_iou_value_negative() {
741 let mantissa = 1_000_000_000_000_000u64; let exponent = 82u8; let mut value = 0u64;
747 value |= 1u64 << 63; value |= 0u64 << 62; value |= (exponent as u64) << 54; value |= mantissa; let bytes = value.to_be_bytes();
753 let number = Number::from_xrpl_iou_value(bytes).expect("Failed to parse negative");
754
755 assert!(!number.is_zero());
756 assert_eq!(number.signum(), -1);
757
758 let string_val = number.to_string();
760 assert!(string_val.starts_with("-1") || string_val == "-1");
761 }
762
763 #[test]
764 fn test_xrpl_iou_value_invalid_type() {
765 let invalid_bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01];
767 let result = Number::from_xrpl_iou_value(invalid_bytes);
768 assert!(matches!(result, Err(NumberError::InvalidArgument)));
769 }
770
771 #[test]
772 fn test_xrpl_iou_value_invalid_exponent() {
773 let invalid_bytes = [0xFF, 0xC0, 0x6F, 0x7B, 0x5C, 0x00, 0x00, 0x00];
776 let result = Number::from_xrpl_iou_value(invalid_bytes);
777 assert!(matches!(result, Err(NumberError::InvalidArgument)));
778 }
779
780 #[test]
781 fn test_xrpl_iou_value_try_from() {
782 let zero_bytes = [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
784 let number: Number = zero_bytes.try_into().expect("TryFrom failed");
785 assert!(number.is_zero());
786 }
787
788 #[test]
789 fn test_xrpl_iou_value_large_mantissa() {
790 let max_mantissa = 9_999_999_999_999_999u64;
794 let mut value = 0u64;
795 value |= 1u64 << 63; value |= 1u64 << 62; value |= 82u64 << 54; value |= max_mantissa; let bytes = value.to_be_bytes();
801 let number = Number::from_xrpl_iou_value(bytes).expect("Failed to parse large mantissa");
802 assert!(!number.is_zero());
803 assert_eq!(number.signum(), 1);
804 }
805
806 #[test]
807 fn test_xrpl_iou_value_float_one_constant() {
808 let number = Number::from_xrpl_iou_value(FLOAT_ONE).expect("Failed to parse FLOAT_ONE");
810 assert!(!number.is_zero());
811 assert_eq!(number.signum(), 1);
812
813 let string_val = number.to_string();
815 assert_eq!(string_val, "1");
816
817 assert_eq!(number.to_i64().expect("Conversion failed"), 1);
819 }
820
821 #[test]
822 fn test_xrpl_iou_value_float_negative_one_constant() {
823 let number = Number::from_xrpl_iou_value(FLOAT_NEGATIVE_ONE)
825 .expect("Failed to parse FLOAT_NEGATIVE_ONE");
826 assert!(!number.is_zero());
827 assert_eq!(number.signum(), -1);
828
829 let string_val = number.to_string();
831 assert_eq!(string_val, "-1");
832
833 assert_eq!(number.to_i64().expect("Conversion failed"), -1);
835 }
836
837 #[test]
838 fn test_xrpl_iou_value_constants_arithmetic() {
839 let one = Number::from_xrpl_iou_value(FLOAT_ONE).expect("Failed to parse FLOAT_ONE");
841 let neg_one = Number::from_xrpl_iou_value(FLOAT_NEGATIVE_ONE)
842 .expect("Failed to parse FLOAT_NEGATIVE_ONE");
843
844 let sum = (&one + &neg_one).expect("Addition failed");
846 assert!(sum.is_zero());
847
848 let diff = (&one - &neg_one).expect("Subtraction failed");
850 assert_eq!(diff.to_i64().expect("Conversion failed"), 2);
851
852 let prod = (&one * &neg_one).expect("Multiplication failed");
854 assert_eq!(prod.signum(), -1);
855 assert_eq!(prod.to_i64().expect("Conversion failed"), -1);
856
857 let negated_one = (-&one).expect("Negation failed");
859 assert_eq!(negated_one.signum(), -1);
860 assert_eq!(negated_one, neg_one);
861 }
862
863 #[test]
864 fn test_xrpl_iou_value_constants_try_from() {
865 let one: Number = FLOAT_ONE.try_into().expect("TryFrom FLOAT_ONE failed");
867 let neg_one: Number = FLOAT_NEGATIVE_ONE
868 .try_into()
869 .expect("TryFrom FLOAT_NEGATIVE_ONE failed");
870
871 assert_eq!(one.to_i64().expect("Conversion failed"), 1);
872 assert_eq!(neg_one.to_i64().expect("Conversion failed"), -1);
873 }
874
875 #[test]
876 fn test_to_xrpl_iou_value_zero() {
877 let zero = Number::new();
879 let bytes = zero.to_xrpl_iou_value().expect("Failed to convert zero");
880 assert_eq!(bytes, FLOAT_ZERO);
881
882 let back_to_zero = Number::from_xrpl_iou_value(bytes).expect("Failed to parse back");
884 assert!(back_to_zero.is_zero());
885 }
886
887 #[test]
888 fn test_to_xrpl_iou_value_constants() {
889 let one = Number::from_xrpl_iou_value(FLOAT_ONE).expect("Failed to parse FLOAT_ONE");
891 let one_bytes = one.to_xrpl_iou_value().expect("Failed to convert one");
892 assert_eq!(one_bytes, FLOAT_ONE);
893
894 let neg_one = Number::from_xrpl_iou_value(FLOAT_NEGATIVE_ONE)
895 .expect("Failed to parse FLOAT_NEGATIVE_ONE");
896 let neg_one_bytes = neg_one
897 .to_xrpl_iou_value()
898 .expect("Failed to convert negative one");
899 assert_eq!(neg_one_bytes, FLOAT_NEGATIVE_ONE);
900 }
901
902 #[test]
903 fn test_to_xrpl_iou_value_round_trip() {
904 let test_cases = vec![
906 Number::from(123),
907 Number::from(-456),
908 Number::from(1_000_000),
909 Number::from(-999_999),
910 ];
911
912 for original in test_cases {
913 let bytes = original
914 .to_xrpl_iou_value()
915 .expect("Failed to convert to XRPL");
916 let converted =
917 Number::from_xrpl_iou_value(bytes).expect("Failed to convert from XRPL");
918
919 let orig_str = original.to_string();
922 let conv_str = converted.to_string();
923 assert_eq!(orig_str, conv_str, "Round-trip failed for {}", original);
924 }
925 }
926
927 #[test]
928 fn test_to_xrpl_iou_value_precision() {
929 let precise = Number::from_mantissa_exponent(1234567890123456, -10)
931 .expect("Failed to create precise number");
932
933 let bytes = precise
934 .to_xrpl_iou_value()
935 .expect("Failed to convert precise number");
936 let back = Number::from_xrpl_iou_value(bytes).expect("Failed to parse back");
937
938 assert_eq!(precise.to_string(), back.to_string());
940 }
941
942 #[test]
943 fn test_try_from_implementations() {
944 let number = Number::from(123);
946 let bytes: XrplIouValue = (&number).try_into().expect("TryFrom reference failed");
947 let bytes_owned: XrplIouValue = number.clone().try_into().expect("TryFrom owned failed");
948
949 assert_eq!(bytes, bytes_owned);
950
951 let back: Number = bytes.try_into().expect("TryFrom back failed");
953 assert_eq!(number, back);
954 }
955}