amount.rs 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. use std::fmt;
  2. // https://github.com/clarkmoody/cashu-rs
  3. use serde::{Deserialize, Serialize};
  4. /// Number of satoshis
  5. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
  6. #[serde(transparent)]
  7. pub struct Amount(u64);
  8. impl Amount {
  9. pub const ZERO: Amount = Amount(0);
  10. /// Split into parts that are powers of two
  11. pub fn split(&self) -> Vec<Self> {
  12. let sats = self.0;
  13. (0_u64..64)
  14. .rev()
  15. .filter_map(|bit| {
  16. let part = 1 << bit;
  17. ((sats & part) == part).then_some(Self::from(part))
  18. })
  19. .collect()
  20. }
  21. }
  22. impl Default for Amount {
  23. fn default() -> Self {
  24. Amount::ZERO
  25. }
  26. }
  27. impl Default for &Amount {
  28. fn default() -> Self {
  29. &Amount::ZERO
  30. }
  31. }
  32. impl From<u64> for Amount {
  33. fn from(value: u64) -> Self {
  34. Self(value)
  35. }
  36. }
  37. impl From<Amount> for u64 {
  38. fn from(value: Amount) -> Self {
  39. value.0
  40. }
  41. }
  42. impl std::ops::Add for Amount {
  43. type Output = Amount;
  44. fn add(self, rhs: Amount) -> Self::Output {
  45. Amount(self.0 + rhs.0)
  46. }
  47. }
  48. impl std::ops::AddAssign for Amount {
  49. fn add_assign(&mut self, rhs: Self) {
  50. self.0 += rhs.0;
  51. }
  52. }
  53. impl std::ops::Sub for Amount {
  54. type Output = Amount;
  55. fn sub(self, rhs: Amount) -> Self::Output {
  56. Amount(self.0 - rhs.0)
  57. }
  58. }
  59. impl fmt::Display for Amount {
  60. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  61. write!(f, "{}", self.0)
  62. }
  63. }
  64. impl core::iter::Sum for Amount {
  65. fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
  66. let sats: u64 = iter.map(|amt| amt.0).sum();
  67. Amount::from(sats)
  68. }
  69. }
  70. #[cfg(test)]
  71. mod tests {
  72. use super::*;
  73. #[test]
  74. fn test_split_amount() {
  75. assert_eq!(Amount::from(1).split(), vec![Amount::from(1)]);
  76. assert_eq!(Amount::from(2).split(), vec![Amount::from(2)]);
  77. assert_eq!(
  78. Amount::from(3).split(),
  79. vec![Amount::from(2), Amount::from(1)]
  80. );
  81. let amounts: Vec<Amount> = [8, 2, 1].iter().map(|a| Amount::from(*a)).collect();
  82. assert_eq!(Amount::from(11).split(), amounts);
  83. let amounts: Vec<Amount> = [128, 64, 32, 16, 8, 4, 2, 1]
  84. .iter()
  85. .map(|a| Amount::from(*a))
  86. .collect();
  87. assert_eq!(Amount::from(255).split(), amounts);
  88. }
  89. }