ab_core_primitives/
balance.rs

1//! Balance-related primitives
2
3use ab_io_type::metadata::IoTypeMetadataKind;
4use ab_io_type::trivial_type::TrivialType;
5use core::cmp::Ordering;
6use core::mem::MaybeUninit;
7use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
8use core::{fmt, ptr};
9
10/// Logically the same as `u128`, but aligned to `8` bytes instead of `16`.
11///
12/// Byte layout is the same as `u128`, just alignment is different
13#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
14#[repr(C)]
15pub struct Balance(u64, u64);
16
17unsafe impl TrivialType for Balance {
18    const METADATA: &[u8] = &[IoTypeMetadataKind::Balance as u8];
19}
20
21// Ensure this never mismatches with code in `ab-io-type` despite being in different crate
22const _: () = {
23    let (type_details, _metadata) = IoTypeMetadataKind::type_details(Balance::METADATA)
24        .expect("Statically correct metadata; qed");
25    assert!(size_of::<Balance>() == type_details.recommended_capacity as usize);
26    assert!(align_of::<Balance>() == type_details.alignment.get() as usize);
27};
28
29impl fmt::Debug for Balance {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        f.debug_tuple("Balance").field(&self.as_u128()).finish()
32    }
33}
34
35impl fmt::Display for Balance {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        self.as_u128().fmt(f)
38    }
39}
40
41impl Ord for Balance {
42    #[inline(always)]
43    fn cmp(&self, other: &Balance) -> Ordering {
44        self.as_u128().cmp(&other.as_u128())
45    }
46}
47
48impl PartialOrd for Balance {
49    #[inline(always)]
50    fn partial_cmp(&self, other: &Balance) -> Option<Ordering> {
51        Some(self.cmp(other))
52    }
53}
54
55impl Add for Balance {
56    type Output = Balance;
57
58    #[inline(always)]
59    #[track_caller]
60    fn add(self, rhs: Balance) -> Balance {
61        Self::new(self.as_u128().add(rhs.as_u128()))
62    }
63}
64
65impl AddAssign for Balance {
66    #[inline(always)]
67    #[track_caller]
68    fn add_assign(&mut self, rhs: Balance) {
69        *self = *self + rhs;
70    }
71}
72
73impl Sub for Balance {
74    type Output = Balance;
75
76    #[inline(always)]
77    #[track_caller]
78    fn sub(self, rhs: Balance) -> Balance {
79        Self::new(self.as_u128().sub(rhs.as_u128()))
80    }
81}
82
83impl SubAssign for Balance {
84    #[inline(always)]
85    #[track_caller]
86    fn sub_assign(&mut self, rhs: Balance) {
87        *self = *self - rhs;
88    }
89}
90
91impl<Rhs> Mul<Rhs> for Balance
92where
93    u128: Mul<Rhs, Output = u128>,
94{
95    type Output = Balance;
96
97    #[inline(always)]
98    #[track_caller]
99    fn mul(self, rhs: Rhs) -> Balance {
100        Self::new(<u128 as Mul<Rhs>>::mul(self.as_u128(), rhs))
101    }
102}
103
104impl<Rhs> MulAssign<Rhs> for Balance
105where
106    u128: Mul<Rhs, Output = u128>,
107{
108    #[inline(always)]
109    #[track_caller]
110    fn mul_assign(&mut self, rhs: Rhs) {
111        *self = *self * rhs;
112    }
113}
114
115impl<Rhs> Div<Rhs> for Balance
116where
117    u128: Div<Rhs, Output = u128>,
118{
119    type Output = Balance;
120
121    #[inline(always)]
122    #[track_caller]
123    fn div(self, rhs: Rhs) -> Balance {
124        Self::new(<u128 as Div<Rhs>>::div(self.as_u128(), rhs))
125    }
126}
127
128impl<Rhs> DivAssign<Rhs> for Balance
129where
130    u128: Div<Rhs, Output = u128>,
131{
132    #[inline(always)]
133    #[track_caller]
134    fn div_assign(&mut self, rhs: Rhs) {
135        *self = *self / rhs;
136    }
137}
138
139impl From<u128> for Balance {
140    #[inline(always)]
141    fn from(value: u128) -> Self {
142        Self::new(value)
143    }
144}
145
146impl From<Balance> for u128 {
147    #[inline(always)]
148    fn from(value: Balance) -> Self {
149        value.as_u128()
150    }
151}
152
153impl Balance {
154    /// Minimum balance
155    pub const MIN: Self = Self::new(0);
156    /// Maximum balance
157    pub const MAX: Self = Self::new(u128::MAX);
158
159    /// Create a value from `u128`
160    #[inline(always)]
161    pub const fn new(n: u128) -> Self {
162        let mut result = MaybeUninit::<Self>::uninit();
163        // SAFETY: correct size, valid pointer, and all bits are valid
164        unsafe {
165            result.as_mut_ptr().cast::<u128>().write_unaligned(n);
166            result.assume_init()
167        }
168    }
169
170    /// Turn value into `u128`
171    #[inline(always)]
172    pub const fn as_u128(self) -> u128 {
173        // SAFETY: correct size, valid pointer, and all bits are valid
174        unsafe { ptr::from_ref(&self).cast::<u128>().read_unaligned() }
175    }
176}