brk_structs/structs/
sats.rs1use std::{
2 iter::Sum,
3 ops::{Add, AddAssign, Div, Mul, SubAssign},
4};
5
6use allocative::Allocative;
7use bitcoin::Amount;
8use derive_deref::Deref;
9use serde::{Deserialize, Serialize};
10use vecdb::{CheckedSub, StoredCompressed};
11use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
12
13use crate::StoredF64;
14
15use super::{Bitcoin, Cents, Dollars, Height};
16
17#[derive(
18 Debug,
19 PartialEq,
20 Eq,
21 PartialOrd,
22 Ord,
23 Clone,
24 Copy,
25 Deref,
26 Default,
27 FromBytes,
28 Immutable,
29 IntoBytes,
30 KnownLayout,
31 Serialize,
32 Deserialize,
33 StoredCompressed,
34 Allocative,
35)]
36pub struct Sats(u64);
37
38#[allow(clippy::inconsistent_digit_grouping)]
39impl Sats {
40 pub const ZERO: Self = Self(0);
41 pub const _1: Self = Self(1);
42 pub const _10: Self = Self(10);
43 pub const _100: Self = Self(100);
44 pub const _1K: Self = Self(1_000);
45 pub const _10K: Self = Self(10_000);
46 pub const _100K: Self = Self(100_000);
47 pub const _1M: Self = Self(1_000_000);
48 pub const _10M: Self = Self(10_000_000);
49 pub const _1BTC: Self = Self::ONE_BTC;
50 pub const _10BTC: Self = Self(10_00_000_000);
51 pub const _100BTC: Self = Self(100_00_000_000);
52 pub const _1K_BTC: Self = Self(1_000_00_000_000);
53 pub const _10K_BTC: Self = Self(10_000_00_000_000);
54 pub const _100K_BTC: Self = Self(100_000_00_000_000);
55 pub const ONE_BTC: Self = Self(1_00_000_000);
56 pub const MAX: Self = Self(u64::MAX);
57 pub const FIFTY_BTC: Self = Self(50_00_000_000);
58 pub const ONE_BTC_U128: u128 = 1_00_000_000;
59
60 pub fn new(sats: u64) -> Self {
61 Self(sats)
62 }
63
64 pub fn is_zero(&self) -> bool {
65 *self == Self::ZERO
66 }
67
68 pub fn is_not_zero(&self) -> bool {
69 *self != Self::ZERO
70 }
71}
72
73impl Add for Sats {
74 type Output = Self;
75 fn add(self, rhs: Self) -> Self::Output {
76 Self::from(self.0 + rhs.0)
77 }
78}
79
80impl AddAssign for Sats {
81 fn add_assign(&mut self, rhs: Self) {
82 *self = *self + rhs;
83 }
84}
85
86impl CheckedSub<Sats> for Sats {
87 fn checked_sub(self, rhs: Self) -> Option<Self> {
88 self.0.checked_sub(rhs.0).map(Self::from)
89 }
90}
91
92impl CheckedSub<usize> for Sats {
93 fn checked_sub(self, rhs: usize) -> Option<Self> {
94 self.0.checked_sub(rhs as u64).map(Self::from)
95 }
96}
97
98impl SubAssign for Sats {
99 fn sub_assign(&mut self, rhs: Self) {
100 *self = self.checked_sub(rhs).unwrap();
101 }
106}
107
108impl Mul<Sats> for Sats {
109 type Output = Self;
110 fn mul(self, rhs: Sats) -> Self::Output {
111 Sats::from(self.0.checked_mul(rhs.0).unwrap())
112 }
113}
114
115impl Mul<usize> for Sats {
116 type Output = Self;
117 fn mul(self, rhs: usize) -> Self::Output {
118 Sats::from(self.0.checked_mul(rhs as u64).unwrap())
119 }
120}
121
122impl Mul<u64> for Sats {
123 type Output = Self;
124 fn mul(self, rhs: u64) -> Self::Output {
125 Sats::from(self.0.checked_mul(rhs).unwrap())
126 }
127}
128
129impl Mul<Height> for Sats {
130 type Output = Self;
131 fn mul(self, rhs: Height) -> Self::Output {
132 Sats::from(self.0.checked_mul(u64::from(rhs)).unwrap())
133 }
134}
135
136impl Mul<StoredF64> for Sats {
137 type Output = Self;
138 fn mul(self, rhs: StoredF64) -> Self::Output {
139 Sats::from((self.0 as f64 * f64::from(rhs)) as u64)
140 }
141}
142
143impl Sum for Sats {
144 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
145 let sats: u64 = iter.map(|sats| sats.0).sum();
146 Self::from(sats)
147 }
148}
149
150impl Div<Dollars> for Sats {
151 type Output = Self;
152 fn div(self, rhs: Dollars) -> Self::Output {
153 let raw_cents = u64::from(Cents::from(rhs));
154 if raw_cents != 0 {
155 Self(self.0 * 100 / raw_cents)
156 } else {
157 Self::MAX
158 }
159 }
160}
161
162impl Div<Sats> for Sats {
163 type Output = Self;
164 fn div(self, rhs: Sats) -> Self::Output {
165 if rhs.0 == 0 {
166 Self(0)
167 } else {
168 Self(self.0 / rhs.0)
169 }
170 }
171}
172
173impl Div<usize> for Sats {
174 type Output = Self;
175 fn div(self, rhs: usize) -> Self::Output {
176 Self(self.0 / rhs as u64)
177 }
178}
179
180impl From<u64> for Sats {
181 fn from(value: u64) -> Self {
182 Self(value)
183 }
184}
185
186impl From<usize> for Sats {
187 fn from(value: usize) -> Self {
188 Self(value as u64)
189 }
190}
191
192impl From<f64> for Sats {
193 fn from(value: f64) -> Self {
194 Self(value.round() as u64)
195 }
196}
197
198impl From<Sats> for f64 {
199 fn from(value: Sats) -> Self {
200 value.0 as f64
201 }
202}
203
204impl From<Sats> for usize {
205 fn from(value: Sats) -> Self {
206 value.0 as usize
207 }
208}
209
210impl From<Amount> for Sats {
211 fn from(value: Amount) -> Self {
212 Self(value.to_sat())
213 }
214}
215impl From<Sats> for Amount {
216 fn from(value: Sats) -> Self {
217 Self::from_sat(value.0)
218 }
219}
220
221impl From<Bitcoin> for Sats {
222 fn from(value: Bitcoin) -> Self {
223 Self((f64::from(value) * (Sats::ONE_BTC.0 as f64)).round() as u64)
224 }
225}
226
227impl From<Sats> for u64 {
228 fn from(value: Sats) -> Self {
229 value.0
230 }
231}
232
233impl From<u128> for Sats {
234 fn from(value: u128) -> Self {
235 if value > u64::MAX as u128 {
236 panic!("u128 bigger than u64")
237 }
238 Self(value as u64)
239 }
240}
241
242impl From<Sats> for u128 {
243 fn from(value: Sats) -> Self {
244 value.0 as u128
245 }
246}
247
248impl Mul<Sats> for usize {
249 type Output = Sats;
250 fn mul(self, rhs: Sats) -> Self::Output {
251 Self::Output::from(rhs.0 * self as u64)
252 }
253}
254
255impl std::fmt::Display for Sats {
256 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257 let mut buf = itoa::Buffer::new();
258 let str = buf.format(self.0);
259 f.write_str(str)
260 }
261}